代码生成器是非常有用的工具。我有时使用 jinja2 的命令行版本来生成高度冗余的配置文件和其他文本文件,但它在转换数据方面功能有限。显然,Jinja2 的作者有不同的想法,而我想要类似于 列表推导 list comprehensions 或 D 语言的 可组合范围 composable range 算法之类的东西。
我决定制作一个类似于 Jinja2 的工具,但让我可以通过使用范围算法转换数据来生成复杂的文件。这个想法非常简单:一个直接用 D 语言代码重写的模板语言。因为它 就是 D 语言,它可以支持 D 语言所能做的一切。我想要一个独立的代码生成器,但是由于 D 语言的 mixin
特性,同样的模板语言可以作为嵌入式模板语言工作(例如,Web 应用程序中的 HTML)。有关该技巧的更多信息,请参阅 这篇 关于在编译时使用 mixins 将 Brainfuck 转换为 D 和机器代码的文章。
像往常一样,源码在 GitLab 上。这篇文章中的例子也可以在这里找到。
Hello world 示例
这是一个演示这个想法的例子:
Hello [= retro("dlrow") ]!
[: enum one = 1; :]
1 + 1 = [= one + one ]
[= some_expression ]
类似于 Jinja2 中的 {{ some_expression }}
,它在输出中呈现一个值。[: some_statement; :]
类似于 {% some_statement %}
,用于执行完整的代码语句。我更改了语法,因为 D 也大量使用花括号,并且将两者混合使模板难以阅读(还有一些特殊的非 D 指令,比如 include
,它们被包裹在 [
] 中)。
如果你将上面的内容保存到一个名为 hello.txt.dj
的文件中并运行 djinn
命令行工具,你会得到一个名为 hello.txt
的文件,其中包含你可能猜到的内容:
Hello world!
1 + 1 = 2
如果你使用过 Jinja2,你可能想知道第二行发生了什么。Djinn 有一个简化格式化和空格处理的特殊规则:如果源代码行包含 [:
语句或 [
大于号表示的不等式。
几个月前我使用了 线性规划 linear programming (LP)。线性规划问题是具有线性约束的连续变量系统。这次我将使用 混合整数线性规划 mixed integer linear programming (MILP),它通过允许整数约束变量来归纳 LP。事实证明,这足以成为 NP 完备的,而 MILP 恰好可以很好地模拟这个谜题。
在上一篇文章中,我使用 Julia 库 JuMP 来帮助解决这个问题。这次我将使用 CPLEX:基于文本的格式,它受到多个 LP 和 MILP 求解器的支持(如果需要,可以通过现成的工具轻松转换为其他格式)。这是上一篇文章中 CPLEX 格式的 LP:
Minimize
obj: v
Subject To
ptotal: pr + pp + ps = 1
rock: 4 ps - 5 pp - v