В любое время, когда вам нужно промежуточное представление, которое будет использоваться для генерации кода, наиболее очевидной из них, которая приходит мне на ум, является абстрактное синтаксическое дерево (AST). Представление вашего примера - это списки, которые по моему опыту не так гибки в форме. Для любой вещи, кроме тривиального генерации кода, я бы не стал бить вокруг куста и просто пошел с полномасштабным представлением AST. Используя списки, вы отжимаете больше работы на сторону поколения, чтобы анализировать информацию, такую как типы и то, что означает первый элемент. Переход к представлению AST даст вам большую гибкость и развяжет большую часть системы за счет большей работы со стороны синтаксического анализа (или больше работы с функциями, которые генерируют формы). Сторона поколения будет делать больше работы, но многие из этих компонентов могут быть отделены, так как их входы будут более структурированными.
С точки зрения того, что должно АСТ выглядеть, я бы либо скопировать enlive Кристофа гранд, где он использует {:tag <tag name> :attrs <map of attrs> :content <some collection>}
или что Clojure скрипт использует {:op <some operator> :children <some collection>}
.
Это делает его весьма общий характер, так как вы можете определить произвольные ходоков, что заглянуть в :children
и может пересечь любую структуру, не зная точно о том, что в :op
«s или :tag
» s есть.
Затем для атомных компонентов вы можете обернуть его на карту и предоставить ему некоторую информацию о типе (относительно семантики вашего DSL), которая не зависит от фактического типа объекта. {:atom <the object> :type :background-image}
.
На стороне генерации кода, когда вы сталкиваетесь с атомом, ваш код может отправляться на :type
, а затем, если хотите, дальнейшая отправка по фактическому типу объекта. Поколение из форм коллекции также легко, отправьте на: op /: tag, а затем повторите с детьми. Для какой коллекции использовать для детей, я бы больше ознакомился с обсуждением групп google. Их выводы были для меня полезными.
https://groups.google.com/forum/#!topic/clojure-dev/vZLVKmKX0oc/discussion
Резюмируя, для детей, если бы семантическое значение упорядочения, например, в если заявление, а затем использовать карту {:conditional z :then y :else x}
. Если это просто список аргументов, вы можете использовать вектор.
большое спасибо - просто вид идей, которые я искал! – mikera