I’ve been working on a domain specific language called “Tessera” for defining tilings of the plane and rendering them to SVG. It is particularly suited for tilings with a recursive structure, typically aperiodic tilings. For example, this image of the Penrose rhombuses

was generated from this tessera script, and the image of Robert Amman’s A5 tiling in the header of this post was generated from this tessera script.
Tessera is a pure functional language implemented in C++17, source code here. I’m using Boost Spirit X3 to implement the parser, Eigen for matrices, Boost Multiprecision for greater than double precision floating point numbers, and my own “graph_ptr” class for garbage collecting smart pointers. These graph_ptrs are somewhat similar to Herb Sutter’s deferred_ptr, which I tried at first but found to perform too inefficiently for my use case. My implementation of Tessera parses source code into an expression tree and then compiles the expression tree into commands for a stack machine representation that actually executes the script.
Tessera is a Turing complete language and the scope of the project is big enough that I can’t easily document the whole thing in a single blog post. I plan on doing more posts like these, one focusing on advanced features of the language and perhaps one focusing on the language’s implementation. However, to get a feel for the language consider the following script which generates a “Sierpinki Carpet”.
let square = { regular_polygon(4) } with {
    north, west, south, east is this.edges;
    color is "purple";
};
let sierpinski_carpet = func( n ) {
    lay 
       s as N, s as NE, s as E, s as SE, s as S, s as SW, s as W, s as NW 
    such_that 
       N.east <-> NE.west,
       NE.south <-> E.north,
       E.south <-> SE.north,
       SE.west <-> S.east,
       S.west <-> SW.east,
       SW.north <-> W.south,
       W.north <-> NW.south 
    with {
       north, west, south, east on [N.north, W.west, S.south, E.east];
    }
} where {
    let s = if (n == 1) square else sierpinski_carpet(n-1);
};
tableau( num ) {
    lay sierpinski_carpet( num )
}
- We define 
squareto be a square shaped tile with its edges named after the cardinal directions as in (1) below. This is done by wrapping the output of the cannedregular_polygon()function in a “with expression”. Usingwithwe can add fields to an existing object (well, to a clone, as this is a pure functional language — objects are immutable). In this case we add a color and we add names for the four edges. - We define a recursive function 
sierpinski_carpet.- The meat of the work is done in a 
layexpression. Intuitivelylayexpressions model laying patches of adjacent tiles.- We specify eight arguments to lay. Each argument is whatever object 
sis. Again these will be clones ofs, as objects are immutable. - We provide aliases for the eight arguments that can be used to refer to them within the
layexpression. - In the 
such_thatclause of the expression we use the aliases to specify edge-to-edge matchings that define a square ring as in (2) - In the 
withclause we specify the names of fields that will be part of the public interface of the patch that thelayexpression evaluates to. We can specify the new fields in terms of the aliases of the arguments as they are still in scope. We let “east” refer to the east side of the east square in the patch, etc., as in (3) 
 - We specify eight arguments to lay. Each argument is whatever object 
 - In the 
whereclause of a function, which is evaluated before the function body, we can define local variables that will be in scope during the evaluation of the body. In this case we define an objectsthat is either a square tile to terminate the recursion or the result of evaluating a recursive call tosierpinski_carpet. 
 - The meat of the work is done in a 
 - In the 
tableaublock we callsierpinski_carpeton a numeric argument that can be provided when the tessera script is executed. tableau is like the main function of a C program, the entry point of the program. 

Calling sierpinski_carpet on 4 yields
