I have added a Javascript backend for CPSCM. The compiled code runs either inside a browser or in Rhino. The Bubble sort example demonstrates compiled Scheme code running “in a web page” and interfacing with native Javascript code (the latter provides DHTML functionality). You can call Scheme functions from Javascript and Javascript functions from Scheme with no restrictions (even continuations will work correctly). The explanations on the bubblesort page should get you started, in case you want to roll your own Scheme programs.
I have made updates and fixes to all backends. There are still missing pieces, but at least now they are summarized on the conformance page, so you know what to expect. Among the improvements, there is an error function which interacts correctly with dynamic-wind. I have borrowed the concept of failure continuations from SISC; you can access them via with-failure-continuation.
Finally, since Javascript console I/O is not standardized, I have implemented SRFI-6 output strings. By default, (display) and its family assume you are using Rhino and try to print to standard output. You can switch to a string using (current-output-port (open-output-string)), and at any point retrieve the accumulated output using (get-output-string (current-output-port)).
Alessandro Colomba (of SISCweb fame) played with CPSCM and noted that he had trouble compiling the SRFI-1 reference implementation (you need a self-contained SRFI-1 to check). After investigating the problem, I found out that the culprit was the η-reduction code in simplify-sexp, which wasn’t designed carefully and exhibited exponential behavior on certain inputs (in practice, I’ve only seen that happen on CPS-ed code). After refactoring simplify-sexp, SRFI-1 compiles in just a few seconds.
The fixes are up in SVN (I’ve tagged the current version as rel-0.9.2). Other improvements:
- Most of the code can be compiled under Chicken, with remarkable speed gains. Just type make in the scm directory. csi (which is still needed for the REPL) uses the compiled libraries automatically.
- By popular demand I have added a
file->lisp procedure for compiling a Scheme source file.
- Programs are no longer wrapped in a giant
letrec, but generate a sequence of top-level definitions and evaluation calls. This means you can compile libraries (such as SRFI-1 above) to separate files, and then load those compiled files independently in the back-end.
I am releasing CPSCM, a new Scheme compiler based on classic CPS conversion and trampolines. It will eventually support multiple backends (Javascript and Java are in the works), but currently it supports Scheme to Common Lisp translation. You can see it work right from your browser on the online demo page (no large jobs, please), or you can download and run it by following the instructions on the CPSCM homepage.
Macro-expansion is delegated to Al Petrofsky’s alexpander, which means that CPSCM has full syntax-rules support from the start. I’ll probably add define-macro support at some point. I don’t feel up to integrating syntax-case, but if anyone wants to contribute, it would be greatly appreciated.
Other than this, CPSCM supports full continuations, including correct call/cc + dynamic-wind interaction, and SRFI-0. It still lacks eval, error protection in dynamic-wind, streams, load, and multiple-file source facilities. An interesting point is that as soon as CPSCM is able to compile itself, eval can be added in (though the environment functions other than interaction-environment will be problematic.)
As with scsh-regexp, I will use Google Code Project Hosting. Some people have questioned this choice (and Google Code has earned mixed reviews); compared to Sourceforge, Google Code has a big advantage: they don’t make you fill out multi-page forms (and wait for approval!) for the “privillege” of uploading an open-source project.
In my last post, I mentioned generating the R5RS identifier list by scraping the HTML version of the R5RS standard. I decided to use Scheme for the job, and quickly learned that Chicken and SISC lack adequate regexp support (SISC has no support at all, apart from letting you interface with the underlying JVM). Eventually, I settled upon SCSH, as it has a powerful regexp API, as well as good shell integration.
The resulting SCSH script took forever to run (to be fair, I added code to separate procedure names from macro names, and didn’t bother optimizing beyond the naive O(n2) algorithm). I started to miss Chicken’s speed. The SCSH regexp API looked reasonably easy to port. I ended up writing both a Chicken and a SISC emulation layer (the latter based on java.util.regex). I am planning to add a pregexp backend as well, which would extend regexp support to any R5RS system.
Have a look at the scsh-regexp project for details, examples and news.
When interacting with a REPL, readline history and tab completion support are major productivity boosters. This is true in general, but especially so given Scheme’s long names (e.g. call-with-input-file). Some Schemes have integrated readline support, but the one I use most, namely SISC, does not.
The next best thing is to use something like rlwrap (as SISC actually does). «rlwrap COMMAND» adds history support out of the box by intercepting COMMAND’s standard input and output. Furthermore, I’ve just learned that, when configured properly, rlwrap can also autocomplete a predefined set of identifiers (and optionally learn new identifiers from standard input/output). SISC does not enable completion by default, but we can easily fix it. The relevant command-line arguments are
- -b DELIMITER-CHARS
- A list of word-separating delimiters. Whitespace is included by default; for Scheme, use “\”()[]’`”.
- -H HISTORY-file
- The history file.
- -f IDENTIFIER-FILE
- A file listing the identifiers to be completed by default, one per line (this option can occur multiple times). I wrote a script to parse the R5RS index HTML page; I’m putting the output online, so you can simply download the resulting R5RS identifier list. It makes sense to also add a -f HISTORY-FILE argument.
These are the basics; the man page documents a few more interesting options (in particular, see -r). Using rlwrap, you can enable readline history and completion for any interaction-challenged Scheme system.