(module news-macros (generate-path-parameters) (import chicken scheme) (use srfi-1 data-structures srfi-13) ;; The [tree] argument is a path-spec. ;; See generate-path-parameters for details. (define-for-syntax (path-tree->symbol-paths tree symbol-prefix) (define (_path-tree->symbol-paths tree symbol-prefix) (map (lambda (l) (let ((path-val (conc (eval (third tree)) (eval (third l))))) (if (null? (cdddr l)) `(,(symbol-append symbol-prefix (second l)) ,path-val) (append `(,(symbol-append symbol-prefix (second l)) ,path-val) (path-tree->symbol-paths `(,(first l) ,(second l) ,path-val ,@(cdddr l)) symbol-prefix))))) (cdddr tree))) ;; Convert a flat list to a list of pairs ;; '(a b c d) => '((a b) (c d)) (define (pairize lis) (if (null? lis) '() (cons (list (car lis) (cadr lis)) (pairize (cddr lis))))) (pairize (flatten (_path-tree->symbol-paths tree symbol-prefix)))) ;; Usage: ;; (generate-path-parameters ;; (/ res "res" ;; (/ css "css)) ;; values ;; path- ;; js-uri-var) ;; => (define path-res (make-parameter "/res")) ;; (define path-css (make-parameters "/res/css")) ;; (define js-uri-var ;; "var uri = {}; uri.uriRes = '/res'; uri.uriCss = ;; '/res/css';") ;; ;; Signature: ;; (generate-path-parameters [path-spec] init-proc prefix-symbol js-var) ;; Output: ;; A set of parameters that define paths and a variable containing a ;; string defining the URIs for a javascript. ;; [path-spec]: ;; A path-spec is a hierarchical tree. The first element in a list ;; is ignored. It is for formatting only. The second element is a symbol ;; representing the name of the parameter to be generated. The third ;; element is the part of the path for that parameter. The full path ;; is built by concatenating the parent paths to the path for the ;; current item. The parent item is the first three values in the ;; root node of the child. So each path is a combination of the ;; paths generated from each anscetor's node. The third element of ;; each node is 'eval'ed. (define-syntax generate-path-parameters (er-macro-transformer (lambda (exp r cmp) `(,(r 'begin) ;; Prepend a dummy node [*root*] since ;; path-tree->symbol-paths expects that. ,@(let ((symbol/paths (path-tree->symbol-paths `("" *root* "" ,(cadr exp)) (cadddr exp))) (symbol->camelcase-string (lambda (sym) (let ((symbols (string-split (symbol->string sym) "-"))) (fold (lambda (s o) (string-append o (string-titlecase s))) (car symbols) (cdr symbols)))))) (append (map (lambda (symbol/path) `(,(r 'define) ,(first symbol/path) (,(r 'make-parameter) (,(r 'apply) ,(caddr exp) `(,,(second symbol/path)))))) symbol/paths) `((,(r 'define) ,(fifth exp) ,(string-append "var uri = {};" (fold (lambda (symbol/path o) (string-append o "uri." (symbol->camelcase-string (car symbol/path)) " = '" (cadr symbol/path) "';")) "" symbol/paths)))))))))) )