Tonight I was reminiscing with Tijs van der Storm about conferences of the past, in particular the day that I wrote a Quine in Stratego at OOPSLA 2004. I reported about that in my pre-blog and at the Stratego/XT site, but not in this blog. Since it was a fun example, I thought it deserved a place on my official blog. Here goes:
After GPCE/OOPSLA in Vancouver Tijs van der Storm challenged me to write a Stratego program that prints its own source. So I set to work, with the following result. I’ll make it educational and reconstruct the design process.
The core of a self printing program is that it should contain its own source and duplicate that. The following program implements this idea, but with ‘prefix’ and ‘suffix’ instead of the
---------------------------------- module quine imports lib strategies main = !["prefix", "suffix"] ; \ [x, y] -> [x, x, y, y] \ ; concat-strings ;(stdout, [ ]) ; 0 ----------------------------------- </pre> Compiling and running this program produces: prefixprefixsuffixsuffixQuoting the source
Next we replace 'prefix' and 'suffix' by the prefix and suffix of the program with respect to the list. Note that we don't bother with the layout of the quoted fragment. Note that the backslashes of the anonymous rewrite rule need to be escaped in the string.------------------------------------------------------------------------------------------ module quine imports lib strategies main = !["module quine imports lib strategies main = ![", "]; \\ [x, y] -> [x, x, y, y] \\; concat-strings;(stdout, [ ]); 0"] ; \ [x, y] -> [x, x, y, y] \ ; concat-strings ; (stdout, [ ]) ; 0 ------------------------------------------------------------------------------------------ </pre> The output of this program is ------------------------------------------------------------------ module quine imports lib strategies main = ![module quine imports lib strategies main = ![]; \ [x, y] -> [x, x, y, y] \; concat-strings;(stdout, [ ]); 0]; \ [x, y] -> [x, x, y, y] \; concat-strings; (stdout, [ ]); 0 ------------------------------------------------------------------ </pre> which is starting to look good, but not quite there, since it doesn't compile. Getting the quotes right
What we have to do now is introduce quotes in the printed program, such that the pieces of code in the list are actually parsed as strings.------------------------------------------------------------------------------------------ module quine imports lib strategies main = !["module quine imports lib strategies main = ![\"", "\"]; \\ [x, y] -> [x, x, y, y] \\; concat-strings;(stdout, [ ]); 0"] ; \ [x, y] -> [x, x, "\",\"", y, y] \ ; concat-strings ; (stdout, [ ]) ; 0 ------------------------------------------------------------------------------------------ </pre> The output of this program is ------------------------------------------------------------------ module quine imports lib strategies main = !["module quine imports lib strategies main = !["",""]; \ [x, y] -> [x, x, y, y] \; concat-strings;(stdout, [ ]); 0"]; \ [x, y] -> [x, x, y, y] \; concat-strings; (stdout, [ ]); 0 ------------------------------------------------------------------ </pre> which still does not compile because of the doublequotes embedded in the string. Getting the quotes more right
We need to escape the embedded strings. This can be achieved easily by using the escape strategy from the library, which escapes doublequotes and backslashes.------------------------------------------------------------------------------------------ module quine imports lib strategies main = !["module quine imports lib strategies main = ![\"", "\"]; \\ [x, y] -> [x,x, \"\\\",\\\"\", y, y] \\; concat-strings; (stdout, [ ]); 0"] ; \ [x, y] -> [x, x, "\",\"", y, y] \ ; concat-strings ; (stdout, [ ]) ; 0 ------------------------------------------------------------------------------------------ </pre> This produces (without the newlines) ----------------------------------------------------------------------------- module quine imports lib strategies main = !["module quine imports lib strategies main = ![\"","\"]; \\ [x, y] -> [x,x, \"\\\",\\\"\", y, y] \\; concat-strings; (stdout , [ ]); 0"]; \ [x, y] -> [x, x, "\",\"", y, y] \; concat-strings; (stdout, [ ]); 0 ----------------------------------------------------------------------------- </pre> Bootstrapping
Now the last program is not exactly the same as its predecessor, but if we compile and run it, it produces its own source literally.