Cada vez que necesite una representación intermedia que se utilizará para generar código, lo más obvio que se me viene a la mente es un árbol de sintaxis abstracta (AST). Su representación de ejemplo son listas, que en mi experiencia no es tan flexible de una forma. Para cualquier cosa más que la generación de código trivial, no me iría por las ramas, y simplemente iría con una representación completa de AST. Mediante el uso de listas, empuja más trabajo al lado de la generación para analizar la información, como los tipos y lo que significa el primer elemento. Pasar a una representación AST le dará más flexibilidad y desacoplará más del sistema, a costa de más trabajo del lado de análisis (o más trabajo de las funciones que generan los formularios). El lado de la generación también hará más trabajo, pero muchos de esos componentes se pueden desacoplar ya que sus entradas serán más estructuradas.
En términos de lo que debe el aspecto AST como, yo sería copiar cualquiera Enlive de Christophe Grand, donde utiliza {:tag <tag name> :attrs <map of attrs> :content <some collection>}
o qué secuencia de comandos utiliza clojure, {:op <some operator> :children <some collection>}
.
Esto hace que sea bastante general ya que se puede definir caminantes arbitrarias que se asoma al :children
y puede atravesar cualquier estructura sin saber exactamente de lo que son los :op
's' o :tag
s.
Luego, para los componentes atómicos, puede envolverlo en un mapa y darle algún tipo de información (con respecto a la semántica de su DSL) que sea independiente del tipo real del objeto. {:atom <the object> :type :background-image}
.
En el lado de la generación de código, al encontrar un átomo, el código puede enviarse en el :type
y luego, si lo desea, enviarlo en el tipo real del objeto. La generación a partir de formularios de recopilación también es fácil, se envía en: op /: tag y luego se repite con los hijos. Para qué colección usar para niños, leí más sobre la discusión en los grupos de google. Sus conclusiones fueron esclarecedoras para mí.
https://groups.google.com/forum/#!topic/clojure-dev/vZLVKmKX0oc/discussion
En resumen, para los niños, si había pedido importancia semántica como en una sentencia if, a continuación, utilizar un mapa {:conditional z :then y :else x}
. Si fuera solo una lista de argumentos, entonces podrías usar un vector.
muchas gracias, ¡solo el tipo de información que estaba buscando! – mikera