Ogni volta che hai bisogno di una rappresentazione intermedia che verrà utilizzata per generare codice, la cosa più ovvia che mi viene in mente è un albero sintattico astratto (AST). La tua rappresentazione di esempio sono elenchi, che nella mia esperienza non sono flessibili come un modulo. Per qualcosa di più della generazione di codice banale, non vorrei battere la testa, e basta andare con una rappresentazione AST in piena regola. Usando le liste, si spinge più lavoro verso la generazione per analizzare le informazioni come i tipi e il significato del primo oggetto. Passare a una rappresentazione AST ti darà più flessibilità e disaccoppia maggiormente il sistema, a costo di più lavoro dal lato dell'analisi (o più lavoro dalle funzioni che generano i moduli). Anche la generazione farà più lavoro, ma molte di queste componenti possono essere disaccoppiate dal momento che i loro input saranno più strutturati.
In termini di ciò che deve l'aspetto AST come, vorrei copiare sia enlive di Christophe Grand, dove egli utilizza {:tag <tag name> :attrs <map of attrs> :content <some collection>}
o quello che lo script utilizza clojure, {:op <some operator> :children <some collection>}
.
Questo lo rende abbastanza generale da quando è possibile definire gli escursionisti arbitrari che fanno capolino in :children
e può attraversare qualsiasi struttura senza sapere esattamente su ciò che sono le :op
's o :tag
' s.
Quindi per i componenti atomici, è possibile avvolgerli in una mappa e dargli alcune informazioni sul tipo (rispetto alla semantica del DSL) che è indipendente dal tipo effettivo dell'oggetto. {:atom <the object> :type :background-image}
.
Sul lato di generazione del codice, quando si incontra un atomo, il codice può quindi essere inviato allo :type
e quindi, se lo si desidera, ulteriore invio al tipo effettivo dell'oggetto. Anche la generazione dai moduli di raccolta è semplice, spedita su: op /: tag e poi si ripresenta con i bambini. Per quale raccolta utilizzare per i bambini, vorrei leggere di più sulla discussione sui gruppi di google. Le loro conclusioni sono state illuminanti per me.
https://groups.google.com/forum/#!topic/clojure-dev/vZLVKmKX0oc/discussion
In sintesi, per i bambini, se non ci fossero semantica importanza ordinamento come ad esempio in un'istruzione if, quindi utilizzare una mappa {:conditional z :then y :else x}
. Se fosse solo un elenco di argomenti, allora potresti usare un vettore.
molte grazie - solo il tipo di informazioni che stavo cercando! – mikera