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 basic idea 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 ----------------------------------- Compiling and running this program produces:
prefixprefixsuffixsuffix
---------+++ Quoting 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 ------------------------------------------------------------------------------------------ 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 ------------------------------------------------------------------ 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 ------------------------------------------------------------------------------------------ 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 ------------------------------------------------------------------ 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 ------------------------------------------------------------------------------------------ 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 ----------------------------------------------------------------------------- ---------+++ 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.