Schmaltz
Render embedded Scheme in texts
Schmaltz is a way to embed Scheme code in text files using escape characters. This makes it a decent templating language à la PHP or shell here-documents.
Rationale
Schmaltz was inspired by shell here-documents as well as CHICKEN’s extension to Scheme string literals, which looks like this:
(define some-string #<#end
Here is a multiline string literal with #(display "embedded") Scheme code.
1 + 2 = #(+ 1 2), etc.
end
)
While this works fine enough, there are a number of limitations preventing it from more thorough use:
- The above notation only works with string literals.
- The
end
tag must be alone on a line and at the beginning of the line. That, plus the fact that this is a non-standard extension, mean that editors (Emacs) indent that end tag, leading to a mis-parse. Fixing it is possible but fiddly. - The escape notation isn’t extensible.
Here-documents, in shell and other scripts, are similar in form (I assume that CHICKEN’s extension was inspired by this syntax):
cat <<EOF
Here is a here-document in bourne shell. It performs expansion, so you can
include things like $(echo "this") in.
1 + 2 = $((1 + 2)), etc.
EOF
In shell here-documents, however, every expanded form is executed in a sub-shell, meaning that variable assignments and function definitions are not persistent across the document.
Schmaltz attempts to fix all of these problems. In fact, within a schmaltz-powered document you should have all of the power of Scheme within rendered forms, as well as persistence of environment and access to the rest of your Scheme system. Here is a schmaltz document in the same format as the above for illustration:
#,(define word "expansion")
Here is a schmaltz-powered text thing. It can do #,(display word), as well as
arithmetic and all sorts of other things.
#,(import (scheme inexact))
The square root of 13 is #,(sqrt 13), etc.
Installation
Schmaltz is written in CHICKEN Scheme v.5.3.0 and Works on My Machine™. Your mileage may vary, though I welcome bug reports and merge requests!
To install schmaltz, you’ll need the following eggs:
This repository comes with an egg file, so you should just be able to run chicken-install -s
inside of it to install all the dependencies as well as schmaltz.
Usage
Schmaltz is packaged both as a portable R7RS library (untested) and a CHICKEN executable.
R7RS library: (schmaltz)
The schmaltz library exports the following definitions in its public API:
(render [port] [environment])
procedure
Read the input PORT, evaluating every expansion form in ENVIRONMENT. PORT defaults to current-input-port
and ENVIRONMENT defaults to render-environment
. Outputs to current-output-port
.
(render-string string [environment])
procedure
Perform render
with STRING as the input port.
(render->string . args)
procedure
Perform render
, returning a string with the output. Takes the same arguments as render
.
(render-string->string . args)
procedure
Perform render-string
, returning a string with the output. Takes the same arguments as render-string
.
render-specials
parameter
Special characters to trigger expansion. Every expansion begins with #
, then another character, then a Scheme form. render-specials
is an alist where CARs is a character literal and CDRs are procedures of one parameter, an input port.
render-specials
defaults to
This renders #,(+ 1 2)
to 3
.
render-unprintables
parameter
String results not to include in the rendered output. For example, define
might return an unspecified or void value, which when displayed could be #<unspecified>
. render-unprintables
is an alist where CARs are strings and CDRs are procedures of one parameter, the current character being processed. The default value of render-unprintable
is an empty list, but see the section on the schmaltz
executable for a more useful example.
(unprintable/skip . _)
, (unprintable/backtrack char)
procedures
Helper procedures for definitions in render-unprintables
. See the example below for usage ideas.
unprintable/skip
skips whatever output is given from the rendered Scheme code and prints nothing. unprintable/backtrack
skips the output, but backtracks to output the character triggering the expansion as well as the preceding #
.
render-environment
parameter
The environment to evaluate rendered forms in. Defaults to interaction-environment
.
environment
procedure
Re-exported from (scheme eval)
for ease of building render-environment
s.
Executable: schmaltz
The schmaltz
executable reads standard input or files from the command line, rendering and concatenating all of them to standard output, like cat
. Also like cat
, if -
is passed as a parameter to schmaltz
, it will insert the contents of standard input at that position in the output.
You can call it as a compiled file or as a script as long as you have csi
installed.
By default, schmaltz
extends the definitions of the following library parameters:
render-specials
Adds @
for expanding to html via sxml->html
, e.g.
#@(a (@ (href "https://example.com")) "link")
renders to
<a href="https://example.com">link</a>
It wraps the form in an implicit quasiquote
so you can include (string) variables, e.g.
#,(define title "Schmaltz!")
#@(h1 ,title)
render-unprintables
The above skips printing unspecified values altogether, and the end-of-file marker backtracks to print the (non-)escaping #
at the input’s end. I’d recommend doing the same for any Scheme implementation, but I don’t know how they might display unspecified, void, or end-of-file characters.
License
Schmaltz, the library and the program, are licensed under the GOD WILLING LICENSE, version 1.0. See COPYING for details.
Contributing
Contributions are welcome! Email me at git at acdw dot net
or get in touch via whatever other channels you know how with questions or comments or whatever.