www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Embedded D Template generation at compile time

Hello! I've written a few functions as a way to learn about D 
metaprogramming and CTFE. Maybe they'll be useful to someone else 
too. I'd also love it if I could get some feedback on how the 
code uses various D idioms, and if there's something that could 
be done a better way. The syntax the template language uses is 
the same as embedded ruby, so any Rails/PHP developers will feel 
right at home.

Source + documenting unittests here: 

Templates are compiled into a single anonymous D function at 
compile time, and the anon function uses an Appender for its 
internal buffer to maximize speed. It was designed so there is 
minimal overhead at runtime, but I'm sure it could be speed up 

An overview of how to use the template functions:

Anything between <% %> is D code
Anything between <%= %> is D code which is evaluated and pushed 
onto the buffer
Anything else is raw text that is pushed onto the buffer

Loops, conditional logic, and declarations all work as expected. 
Because the function is generated in the context of the call 
point, you can pass any arbitrary private object in scope to the 
render function.

// Some examples:
// Most basic: Raw text
const render = mixin(EmbeddedDFunc(`foo`));
writeln(render()); // foo

// Bit more: D literals
const render = mixin(EmbeddedDFunc(`<%= "foo" %> <%= 22 %>`));
writeln(render()); // foo 22

// Passing in a context to the template
// Static/member variables/methods all work
struct Ctx {
   static static_var = "foo";
   auto my_variable = 5;
   int my_method() {
   	return 10;
const render = mixin(EmbeddedDFunc(`<%= static_var %> <%= 
my_variable %> <%= my_method() %>`);
writeln(render(Ctx())); // 5 foo 10

// Loops (it'd have newlines, but I'm ignoring that for 
const render = mixin(EmbeddedDFunc(`
	<% foreach(i; 0..4 { %>
		<%= i %>
	<% } %>`));
writeln(render()) // 0123

Thank you,
--Dylan Knutson
May 15 2013