(defun escape (s) (or (and (or (number? s) (bool? s)) (string s)) (and (symbol? s) (escape (string s))) (let ((out (vec))) (dolist (x s) (push out (cond ((= x (chr "<")) "<") ((= x (chr ">")) ">") ((= x (chr "&")) "&") (true x)))) (apply concat out)))) (defun escape-attr (s) (or (and (or (number? s) (bool? s)) s) (and (symbol? s) s) (let ((out (vec))) (dolist (x s) (push out (cond ((= x (chr "<")) "<") ((= x (chr ">")) ">") ((= x (chr "&")) "&") ((= x (chr "\"")) """) ((= x (chr "'")) "'") (true x)))) (apply concat out)))) (defmacro html (&body b) (let ((s (vec 'vec))) (dolist (elem b) (if (cons? elem) (progn (if (symbol? (car elem)) (let ((tag (string (car elem)))) (push s "<") (push s tag) (while (keyword? (cadr elem)) (push s " ") (push s (keyword-name (cadr elem))) (set elem (cdr elem)) (push s "=\"") (if (cons? (cadr elem)) (push s (cadr elem)) (push s (escape-attr (cadr elem)))) (set elem (cdr elem)) (push s "\"")) (push s ">") (push s `(html ,@(cdr elem))) (push s "")) (push s elem))) (if (symbol? elem) (push s elem) (push s (escape elem))))) `(apply concat ,(apply (lambda (&rest r) r) s))))