コードの生成に使用される中間表現が必要な場合はいつでも、私の頭に浮かぶ最も明白なものは抽象構文木 (AST) です。あなたの表現例はリストであり、私の経験ではフォームの柔軟性がありません。些細なコード生成以上のことについては、私はブッシュの周りを打ち負かさず、本格的な AST 表現を使用します。リストを使用することで、タイプや最初の項目の意味などの情報を解析するための作業を生成側に任せることができます。AST 表現に移行すると、柔軟性が向上し、システムをより分離できますが、解析側の作業が増えます (または、フォームを生成する関数の作業が増えます)。生成側もより多くの作業を行うことになりますが、
AST がどのように見えるかという点では、Christophe Grand の enlive のどちらかをコピーします。{:tag <tag name> :attrs <map of attrs> :content <some collection>}
または clojure スクリプトが使用するもの、{:op <some operator> :children <some collection>}
.
:children
これにより、 や が何であるかを正確に知らなくても、任意の構造を覗いて横断できる:op
任意のウォーカーを定義できるため、非常に一般的になります:tag
。
次に、アトミック コンポーネントの場合は、それをマップにラップして、オブジェクトの実際の型とは無関係な型情報 (DSL のセマンティクスに関して) を与えることができます。{:atom <the object> :type :background-image}
.
コード生成側では、atom に遭遇すると、コードを にディスパッチし、:type
必要に応じてオブジェクトの実際の型にさらにディスパッチできます。コレクション フォームからの生成も簡単で、:op/:tag でディスパッチし、子で再実行します。子供にどのコレクションを使用するかについては、Google グループでの議論をもっと読みたいと思います。彼らの結論は私にとって啓発的でした。
https://groups.google.com/forum/#!topic/clojure-dev/vZLVKmKX0oc/discussion
要約すると、子供の場合、 if ステートメントなどの意味的な順序付けが重要な場合は、 map を使用します{:conditional z :then y :else x}
。単なる引数リストの場合は、ベクトルを使用できます。