After working some more with Tiles, my mini-library for programmatic code generation, I've realized it has a feature that I haven't knowingly baked in, but which makes it a really good tool for the job. Namely, the code you write is composable.
Here's what I mean: If you want to generate a C function that prints out names of countries' capitals then you can generate the code that does the actual printing first:
data = {
"Afghanistan": "Kabul",
"Brazil": "Brasilia",
"Canada": "Ottawa",
}
body = t/''
for country, capital in data.items():
body |= t/"""
printf("@{capital} is the capital of @{country}");
"""
Once done, you cen generate the scaffolding:
program = t/"""
#include <stdio.h>
int main(void) {
@{body}
return 0;
}
"""
The example, of course, shows just two levels of nesting. In practice, however, you'd have many levels of nesting.
But whatever the nesting level, you, as a programmer, can focus on a single task at a time. First, you think about how to print the capitals. Then you think about the scaffolding. There's no overlap.
Compare that to your typical templating solution:
template = Template("""
#include <stdio.h>
int main(void) {
{% for country, capital in data.items() %}
printf("{{ capital }} is the capital of {{ country }}");
{% endfor %}
return 0;
}
""")
template.render(data=data)
Note how you start with writing scaffolding (include, main) then you switch to the business logic (printf), then you get back to scaffolding (return).
The example is trivial and as such, the both solutions are kind of comparable.
However, imagine there are five levels of nesting.
The code written using Tiles would, logically, look like this:
level1
level2
level3
level4
level5
The code written using one the classic templating tools, on the other hand, would look like this:
level1
level2
level3
level4
level5
level4
level3
level2
level1
March 2nd, 2019