Ant ~ Lisp, Or, A Significantly Better Explanation of Lisp
defmacro.org
defmacro.org
And, since I instinctively refused to look at Eclipse, I've been learning about Ant, which turns out to be almost completely isomorphic to a not-extremely-well-thought-out set of Lisp macros to form a build system.
So, since XML syntax bugs me, I figured I'd write a thing that took a Lisp-syntax file and spit out an XML-syntax file, which led me to google for 'ant lisp,' which led me to this document.
http://news.ycombinator.com/item?id=127736
http://news.ycombinator.com/item?id=1319034 [Posted 12 days ago]
Cf. http://zegoggl.es/2009/12/building-android-apps-in-scala-wit... http://blog.recursivity.com/post/470846055/simple-build-tool...
I like it how with macros, the biggest hurdle in creating a DSL is the actual syntax design, not the actual implementation.
; @echo off && REM -*- scheme -*-
; if not "%MZSCHEME%" == "" goto :run
; set MZSCHEME=mzscheme.exe
; :run
; "%MZSCHEME%" "%~f0" %*
; exit /b
#lang scheme
(require xml)
(permissive-xexprs #t)
;(read-comments #t)
;;; Filter to scrub whitespace
;;;
(define f
(eliminate-whitespace
'(project path target property fileset condition copy exec cvs commandline tar classpath
tarfileset manifest section junit jar java and or not uptodate javac javadoc delete move)
(lambda (x) x)))
;;; Move "name" attribute to the beginning of any attribute list in an xexpr
;;;
(define (name-first-attrib l)
(letrec
;; take attribute list, move any "name" element to its car
((reorder-attrs (lambda (alist)
(cond
((null? alist) alist)
((assq 'name alist) => (lambda (el) (cons el (remove 'name alist (lambda (x y) (eq? x (car y)))))))
(else alist))))
;; process any element (tag attrs el*)
(process-element (lambda (el)
(cons (car l) (cons (reorder-attrs (cadr l)) (map name-first-attrib (cddr l)))))) )
(if (pair? l)
(process-element l)
l)))
(define (process in out)
(pretty-print (name-first-attrib (xml->xexpr (f (document-element (read-xml in))))) out))
;;; Open input file before output file, so that an error upon opening input doesn't create a zero-length output file
;;; If either parameter is #f, default to stdin/stdout
;;;
(define (call-filter-with-files in-file out-file proc)
(let ((output-processing-thunk (lambda (from)
(if out-file
(call-with-output-file out-file (lambda (to) (proc from to)))
(proc from (current-output-port))))))
(if in-file
(call-with-input-file in-file output-processing-thunk)
(output-processing-thunk (current-input-port)))))
(define input-file (make-parameter #f))
(define output-file (make-parameter #f))
(command-line
#:program "ant-make-scm"
#:once-each
(("--output" "-o") filename "Create S-expression format Ant buildfile" (output-file filename))
#:args (build.xml) (unless (string=? "-" build.xml) (input-file build.xml)))
(call-filter-with-files (input-file) (output-file) process)If you want to use Ant and XML syntax bugs you - google for Lancet.
If you were to strip out the XML from Ant what is left is a poorly designed language which has little expressive power. Short of the surface structure of Ant is nothing like Lisp.
The Ant community couldn't even agree what sort of language it was. A hack pretending not be a hack.