Temple: Compile time, embedded D templates

Dylan Knutson tcdknutson at gmail.com
Thu Jan 2 00:36:22 PST 2014


On Thursday, 2 January 2014 at 06:59:04 UTC, yazd wrote:
> How much of this is done at compile-time?

Strictly speaking, just the generation of the code that writes 
the template to the output buffer. E.g, the code above simulating 
the Rails form helper would be lowered to code approximately 
equivalent to this (but with more fluff to add line numbers, and 
expose some needed hooks for the context):

```
void Temple(OutputStream __buff, TempleContext __context = null)
{
	//...
	//struct FormHelper, etc
	//...

	// The actual rendering into a buffer code

	auto __buff_tmp_0 = form_for("/shorten", "", (f) {
		__buff.put("Shorten a URL: ");
		__buff.put(to!string( f.field_for("url") ));
		__buff.put(to!string( f.submit("Shorten URL") ));
	});
	__buff.put(__buff_tmp_0);

	auto __buff_tmp_1 = form_for("/person", "person", (f) {
		__buff.put("Name: ");
		__buff.put(to!string( f.field_for("name") ));
		__buff.put("Age: ");
		__buff.put(to!string( f.field_for("age") ));
		__buff.put("DOB: ");
		__buff.put(to!string( f.field_for("date_of_birth", "date") ));
		__buff.put(to!string( f.submit ));
	});
	__buff.put(__buff_tmp_1);
}
```

>I would guess that
> the code is compiled but it is evaluated on each render. Is 
> that correct? Is there a way to force compile-time evaluation 
> of at least part of the template which does not depend on a 
> runtime value?

Yes, generated templates themselves can be executed with CTFE 
(just had to make a small modification to ArrayOutputAppender, 
which has been pushed), as long as they don't take a context. The 
reason for this is that std.variant.Variant isn't CTFEable, 
because it uses memcpy in opAssign. I'd consider that a Phobos 
bug; perhaps there is a way to make std.variant CTFE compatible? 
That'd allow for a much wider (and more useful) range of 
templates to be evaluated at compile time.

Anyways, here's a working compile time evaluated, compile time 
generated template:

```
string templeToString(TempleFuncType* func, TempleContext context 
= null)
{
	auto accum = new AppenderOutputStream;
	(*func)(accum, context);
	return accum.data;
}


unittest
{
	alias render = Temple!q{
		<% if(true) { %>
			Bort
		<% } else { %>
			No bort!
		<% } %>

		<% auto a = capture(() { %>
			inside a capture block
		<% }); %>

		Before capture
		<%= a %>
		After capture
	};

	const result = templeToString(&render);
	static assert(isSameRender(result, `
		Bort
		Before capture
		inside a capture block
		After capture
	`));
}
```


More information about the Digitalmars-d-announce mailing list