15 Text Preprocessor
The scribble/text language provides everything from scheme/base with a few changes that make it suitable as a preprocessor language:
It uses read-syntax-inside to read the body of the module, similar to Document Reader.
It has a custom printer (current-print) that displays all values. The printer is also installed as the port-display-handler so it can be used through display as well as ~a in format strings. The printer displays most values (as is usual for display), except for
void and #f are not displayed,
pairs are displayed recursively (just their contents, no parentheses),
promises are forced, thunks are invoked.
This means that to write a text file that has scheme code, you simply write it as a module in the scribble/text language, and run it through mzscheme. Here is a sample file:
#lang scribble/text |
@(define (angled . body) (list "<" body ">"))@; |
@(define (shout . body) @angled[(map string-upcase body)])@; |
blah @angled{blah @shout{blah} blah} blah |
(Note how @; is used to avoid empty lines in the output.)
15.1 Using External Files
Using additional files that contain code for your preprocessing is trivial: the preprocessor source is a plain Scheme file, so you can require additional files as usual.
However, things can become tricky if you want to include an external file that should also be preprocessed. Using require with a text file (that uses the scribble/text language) almost works, but when a module is required, it is invoked before the current module, which means that the required file will be preprocessed before the current file regardless of where the require expression happens to be. Alternatively, you can use dynamic-require with #f for the last argument (which makes it similar to a plain load) – but remember that the path will be relative to the current directory, not to the source file.
Finally, there is a convenient syntax for including text files to be processed:
(include filename) |
Preprocess the filename using the same syntax as scribble/text. This is similar to using load in a namespace that can access names bound in the current file so included code can refer to bindings from the including module. Note, however, that the including module cannot refer to names that are bound the included file because it is still a plain scheme module – for such uses you should still use require as usual.