From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Pascal J. Bourguignon" Newsgroups: gmane.emacs.help Subject: Re: macro temp variables Date: Fri, 19 Sep 2014 19:33:30 +0200 Organization: Informatimago Message-ID: <87sijny0ph.fsf@kuiper.lan.informatimago.com> References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1411148426 13423 80.91.229.3 (19 Sep 2014 17:40:26 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 19 Sep 2014 17:40:26 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Fri Sep 19 19:40:21 2014 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1XV2AO-0004l9-7I for geh-help-gnu-emacs@m.gmane.org; Fri, 19 Sep 2014 19:40:20 +0200 Original-Received: from localhost ([::1]:59687 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XV2AN-0007RK-Sz for geh-help-gnu-emacs@m.gmane.org; Fri, 19 Sep 2014 13:40:19 -0400 Original-Path: usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 118 Original-X-Trace: individual.net 6u565WZeIX1TQy7bGph+8gLyUY4ZXg8Llz1P+DtTX/ZXNwAOk9 Cancel-Lock: sha1:NDRkNjM4MzBjNGQ0MGNlYjAzOTg4NDA4YTkyNjQ3Njg5ZmQ1ZGI0Yg== sha1:qcxhsg0HdfXEQXBdOCtfxbtV3dk= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) Original-Xref: usenet.stanford.edu gnu.emacs.help:207759 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:100033 Archived-At: Eric Abrahamsen writes: > I've never actually needed to write a macro that provided temporary > local variables, and consequently am not very good at it. Despite having > read the docs and basically followed the examples there, my attempt is > producing errors. > > The idea with the below is to make a macro that iterates over Org > headlines, and runs the body once for each headline: for each run, a > handful of temporary variables should be bound to various bits of the > headline. > > It should be fairly clear from looking at it. "tree" should be bound > once, at the top level of the call. All the other make-symbol variables > should be re-bound with each pass of org-element-map. > > I tested this with a little stub call that tried to access the 'todo > symbol, and that gets me "symbol's value as variable is void" for 'todo. > I tried replacing the inner "setq" series with a let*, and got the same > result. Clearly this is just not the way you do it, but I've tried > several different things and nothing works. Am I supposed to be using > nested back-quotes? Can someone tell me how to fix this? > > (defmacro org-iter-headings (&rest body) > (declare (indent 0)) > (let ((tree (make-symbol "tree")) > (head (make-symbol "head")) > (item (make-symbol "item")) > (todo (make-symbol "todo")) > (tags (make-symbol "tags")) > (body-pars (make-symbol "body"))) > `(save-restriction > (org-narrow-to-subtree > (outline-next-heading) ; Get off the parent heading. > (let ((,tree (org-element-parse-buffer))) > (org-element-map ,tree 'headline > (lambda (h) > (setq ,head (org-element-at-point) > ,item (org-element-property :raw-value ,head) > ,todo (cons > (org-element-property :todo-type ,head) > (org-element-property :todo-keyword ,head)) > ,tags (org-element-property :tags ,head) > ,body-pars (org-element-map ,head 'paragraph 'identity)) > ,@body))))))) You should indeed better use a let for rather than setq, but the problem is not here. The problem is that you want your body to access those variables. So the body must know their names. But you are computing new names that are uninterned, and therefore unaccessible. Therefore there's no way to access those temporary variables, from the body. Only code generated by your macro could access those variables (since the macro has their name stored in its head .. tags variables. In general, when you want to provide access to variables by the body, you must let the user name those variables. (setf lexical-binding t) ; always (require 'cl) ; always (defmacro* org-iterating-headings ((head item todo tags body-pars) &rest body) `(call-org-iterating-headings (lambda (,head ,item ,todo ,tags ,body-pars) ,@body))) You could write also it with emacs defmacro, but you would have to write: (defmacro org-iterating-headings (vars &rest body) (destructuring-bind (head item todo tags body-pars) vars `(call-org-iterating-headings (lambda (,head ,item ,todo ,tags ,body-pars) ,@body)))) (defun call-org-iterating-headings (thunk) (save-restriction (org-narrow-to-subtree (outline-next-heading) ; Get off the parent heading. (let ((tree (org-element-parse-buffer))) (org-element-map tree 'headline (lambda (h) (let* ((head (org-element-at-point)) (item (org-element-property :raw-value head)) (todo (cons (org-element-property :todo-type head) (org-element-property :todo-keyword head))) (tags (org-element-property :tags head)) (body-pars (org-element-map head 'paragraph 'identity))) (funcall thunk head item todo tags body-pars)))))))) You would use it as: (org-iterating-headings (h i to ta ps) (do-something-with-head h) (mapc (function do-something-else-with-par) ps)) which expands to: (pp (macroexpand '(org-iterating-headings (h i to ta ps) (do-something-with-head h) (mapc (function do-something-else-with-par) ps)))) (call-org-iterating-headings (lambda (h i to ta ps) (do-something-with-head h) (mapc #'do-something-else-with-par ps))) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk