IMO using code that generates (possibly binary/opaque) config data is the sweet spot. It's one more layer of indirection, but it means you're language-agnostic, you have a "safe" interface, and your "config-generating" process can be as expressive as you like -- comments, loops, whatever.
The underlying conundrum is:
- systems need to be configured,
- human-readability is obviously necessary at some level,
- configuration is often very "compressible" (needs loops, needs variables to be maintainable), but
- system-writers don't know the structure of your data, the axes on which you'd want to compress things, the best abstractions for you.
Templating languages are an obvious direction, but they're uniformly bad. If they have limited expressiveness you'll run into the limits. Maybe there are templating languages with good unit testing frameworks, but I haven't seen them. "Look at the expanded diff" doesn't scale. And generating gobs of human-readable "data" (in a format that supports comments!) is very wasteful.
Or if you really must, then simply interrupt processes that loop infinitely, and fix the bugs that caused it.
You know, like you already do when you have an infinite loop.
Infinite loops are not the end of the world, you know. Processes can be interrupted, and computers have reset buttons.