--- tags: [strings, proposal] --- # String templates with control flow It's nice to be able to specify embedded content with tagged string templates. ```kotlin= html""" <h1>${ title }</h1> Do the things: <ul>${ listItems }</ul> """ ``` This works because the tag, `html` in this case, receives the literal parts and the interpolated parts: 1. Literal part `"<h1>"` 2. Interpolation `title` 3. Literal part `"</h1>\nDo the things:\n\n<ul>"` 4. Interpolation `listItems` 5. Literal part `"</ul>"` PHP allows embedding flow control in interpolations. ```php= <h1><?php echo($title) ?></h1> Do the things: <ul><?php foreach ($listItems as $listItem) { ?> <li><?php echo($listItem) ?></li><?php } ?></ul> ``` Some [JS tag libraries](https://lit.dev/docs/v1/lit-html/template-reference/#control-flow-with-javascript) have struggled with flow control. What would we need to provide a tag with a sequence of literal parts and interpolations using regular Temper control flow? PHP has two parts: - transitions from template fragments to PHP code and back - an `echo` function that emits an interpolated value. Let's consider some hand-wavy code in the Temper style and how it might desugar to simpler constructs. ``` html"""(out);; <h1>${ title }$</h1> Do the things: <ul> ${ for (let item of items) { }$ <li>${ out.emit(item) }$</li>${ } }$ </ul> """ ``` This differs from our current interpolated strings in a few ways: 1. `(out);;` after the opening quotes, like a block lambda formal parameter list, gives code inside interpolations something to refer to. Like `echo` in PHP. 2. `${` pairs with `}$` instead of with `}` which means `for (let item of items) {` is not ended by the `}` immediately following it. How could we manipulate this to produce a series of literal text and interpolated values for the `html` tag to process? This could transform to: ```C= // Introduce a block to preserve // apparent scope boundaries. { // Capture the tag to preserve // the order of operations. let tag#0 = html; // Create an object to collect parts. let collector#1 = new TagPartsCollector(); // based on (out);; // Let user code add interpolations // but not literal sections. let out = collector#1.interpolations; collector#1.literal("<h1>"); // Maybe some convention can let // us recognize and auto-emit // "simple" interpolations. out.emit(title); collector#1.literal(""" </h1> Do the things: <ul> """); // Here, the tokens for for (let item of items) { collector#1.literal("\n <li>"); out.emit(item); collector#1.literal("</li>"); } collector#1.literal("\n</ul>"); // Finally, invoke the tag tag#0(collector#1.build()) } ``` So allowing tagged templates with embedded flow controls requires: - a way to define a name to which code can send interpolated values, `out` in this example. This could be defaulted à la Kotlin `it` - a way to identify when an interpolation ends independent of flow control constructs block endings and benefits from - a way to identify which interpolations are "simple", which should be implicitly emitted. One rule of thumb could be, if there is no statement level token (`{`, `}`, `;`) outside non-statement-level brackets, nor a reference to the output channel. but otherwise, the desugaring is fairly straightforward. ---- Problems: if `html` were a macro, it would need to do flow-sensitive analysis if it wanted to, at compile time, pick escapers based on the structure of HTML produced. If `out` were passed into other functions that might be impossible. Specifically providing for branching and looping operations might simplify things. ## Generic tag-based control flow Suppose we have generic structure based on tags that map to blocks: ``` let q = Bob""" Text. $<for let a of x>$ Repeated line: $a $</for>$ """ ``` This might desugar to: ``` let q = Bob() { bob;; bob.emit("Text."); bob.for(let a of x) { bob2;; bob2.emit("Repeated line: "); bob2.arg(a); } } ``` Pros and cons: * Con: you have to recreate all the Temper control flow structures. * Pro: more direct control allows static analysis and optimization. * Pro/con: won't have the flexibility of a full language