;;; -*- lisp -*- (in-package :it.bese.ucw) (enable-bracket-syntax) ;;;; * UCW Extensions to YACLML (defmacro with-extracted-actions ((arg-list-name &rest action-param-names) &body body) "This macro extracts the NAME-id NAME-ajax-p variables, generates the check that only one of :NAME and :NAME-body attributes may be defined, and in case of a :NAME-body it handles action registration. The extracted NAME-id and NAME-ajax-p variables are runtime values, so you can not nil-check them at macroexpand-time, but the compiler can eliminate runtime nil-checks to constant nil's." (flet ((name-generator (symbol appended) (intern-concat (list symbol appended))) (intern-as-keyword (symbol) (intern (symbol-name symbol) (find-package "KEYWORD")))) (let* ((param-count (length action-param-names)) (action-object-tmps (iter (for i below param-count) (collect (gensym "ACTION-OBJECT")))) (action-original-tmps (iter (for i below param-count) (collect (gensym "ACTION-ORIGINAL")))) (action-provided-p-names (mapcar (rcurry #'name-generator "-PROVIDED-P") action-param-names)) ; because we can't nil-check after rebinding (action-ajax-p-names (mapcar (rcurry #'name-generator "-AJAX-P") action-param-names)) (action-ajax-p-tmps (iter (for i below param-count) (collect (gensym "ACTION-AJAX-P-TMP")))) (action-id-names (mapcar (rcurry #'name-generator "-ID") action-param-names)) (action-id-tmps (iter (for i below param-count) (collect (gensym "ACTION-ID-TMP")))) (action-object-names (mapcar (rcurry #'name-generator "-OBJECT") action-param-names)) (action-body-names (mapcar (rcurry #'name-generator "-BODY") action-param-names))) (with-unique-names () `(progn ;; emit the checks for NAME and NAME-body args at the same time ,@(iter (for action-param-name in action-param-names) (for action-body-name in action-body-names) (collect `(unless (or (xor ,action-param-name ,action-body-name) (notany #'identity (list ,action-param-name ,action-body-name))) (error ,(strcat "Only one of " action-param-name " or " action-body-name " is allowed"))))) ;; remove the NAME and NAME-body keyword args ,(when arg-list-name `(remf-keywords ,arg-list-name ,@(mapcar #'intern-as-keyword (append action-param-names action-body-names)))) ,(iter (for action in action-param-names) (for action-object-tmp in action-object-tmps) (for original in action-original-tmps) (for action-body in action-body-names) (for action-object in action-object-names) (for id in action-id-names) (for id-tmp in action-id-tmps) (for provided-p in action-provided-p-names) (for ajax-p in action-ajax-p-names) (for ajax-p-tmp in action-ajax-p-tmps) (nconcing (list #+nil action id ajax-p provided-p) into macro-ignorables) (nconcing (list action-object-tmp id-tmp ajax-p-tmp) into ignorables) (collect `(,provided-p (or ,action ,action-body)) into macro-bindings) (collect `(,original ,action) into macro-backup-bindings) (collect `(,action-object ',action-object-tmp) into macro-bindings) (collect `(,id (and ,provided-p ',id-tmp)) into macro-bindings) (collect `(,ajax-p (and ,provided-p ',ajax-p-tmp)) into macro-bindings) (collect ``(,',action-object-tmp ,(or ,original (when ,action-body `(register-action (:with-call/cc t) (ucw.rerl.info "Executing ~S, body is ~S" ',,action ',,action-body) ,,action-body)))) into bindings) (collect ``(,',id-tmp (when ,',action-object-tmp (action-id ,',action-object-tmp))) into bindings) (collect ``(,',ajax-p-tmp (when ,',action-object-tmp (action-ajax-p ,',action-object-tmp))) into bindings) (finally (return `(let (,@macro-backup-bindings) (let* (,@macro-bindings) (declare (ignorable ,@macro-ignorables)) `(let* (,,@bindings) (declare (ignorable ,@',ignorables)) ,,@body))))))))))) ;;;; Parenscript (eval-always (deftag-macro " #\Newline))) ) ; eval-always ;;;; ** UCW Tags (defun install-action-js (dom-node event-name action &key forms-to-submit forms-to-abandon progress-label) (setf forms-to-submit (ensure-list forms-to-submit)) (setf forms-to-abandon (ensure-list forms-to-abandon)) (multiple-value-bind (action-href uri) (action-href action :component (or (and (boundp '*current-component*) *current-component*) (context.window-component *context*))) (declare (ignore action-href)) (})))))) (deftag-macro