unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* symbol-macrolet clobbers (match-data), bug or feature?
@ 2007-08-14 20:43 Howard Yeh!
  2007-08-16  1:08 ` Richard Stallman
  0 siblings, 1 reply; 2+ messages in thread
From: Howard Yeh! @ 2007-08-14 20:43 UTC (permalink / raw)
  To: bug-gnu-emacs

Hi,

I am writing a macro to make match-data more convenient. I can use it
to implement the =~ operator.

(defmacro* with-match-data ((&key in-string) &rest body)
  "setup local symbol macros for $0 ... $n  for nth submatch.
   symbol macros <1 ... <n  for (match-beginning n in-string).
   etc.
   Should work properly for both string-match and buffer-match.
  "
  ;; code and bug below
  ... )

(defmacro* =~ (regex string &rest body)
  (let ((str (gensym)))
    `(let ((,str ,string))
       (when (string-match ,regex ,str)
	      (with-match-data (:in-string ,str)
		,@body)))))


(=~ "\\(abc\\)\\(efg\\)?" "abcefg"
       (list (match-data) <0 >0 $0 $1 $2))

((0 6 0 3 3 6) 0 6 "abcefg" "abc" "efg")


;;;;;;; bug || feature ;;;;;;;;;;

It seems that the expansion of `with-match-data' is correct (it works
if I evaluate the "macroexpand-all"ed expression). But `symbol-
macrolet' changes the match-data when the expression is interpreted.

(macroexpand-all
 '(=~ "\\(abc\\)\\(efg\\)?" "abcefg"
	(list (match-data) <0 >0 $0 $1 $2)))
=>
(let
    ((G34784 "abcefg"))
  (if
   (string-match "\\(abc\\)\\(efg\\)?" G34784)
   (progn
     (let
	 ((G34785 G34784))
       (progn
	 (list
	  (match-data)
	  (match-beginning 0)
	  (match-end 0)
	  (match-string 0 G34785)
	  (match-string 1 G34785)
	  (match-string 2 G34785)))))))

which is fine

(eval (macroexpand-all
  '(=~ "\\(abc\\)\\(efg\\)?" "abcefg"
    (list (match-data) <0 >0 $0 $1 $2))))

=> ((0 6 0 3 3 6) 0 6 "abcefg" "abc" "efg")

but evaluating the expression without first expanding it is not fine

(r=~ "\\(abc\\)\\(efg\\)?" "abcefg"
       (list (match-data) <0 >0 $0 $1 $2))

=> ((0 1) 0 1 "a" nil nil)

For a workaround, I save the match-data before entering symbol-
macrolet, and (set-match-data) before executing the body.


;;;;;; code ;;;;;;;;;

(defmacro* with-match-data ((&key in-string) &rest body)
  (let ((str (gensym))
	(md (gensym)))
    `(let ((,str ,in-string)
	   (,md (match-data)))  ;; workaround for the bug
       ;;(my-debug "before" (match-data))  ;; here match-data is from
the previous match.
       (symbol-macrolet ,(loop for i to 9 append
			      (let ((match (intern (concat "$" (number-to-string i))))
				    (beg (intern (concat "<" (number-to-string i))))
				    (end (intern (concat ">" (number-to-string i)))))
				(list `(,match (match-string ,i ,str))
				      `(,beg (match-beginning ,i))
				      `(,end (match-end ,i)))))
	 ;;(my-debug "after" (match-data))   ;; here match-data is something
else.
	 (macrolet (($ (i)
		      `(match-string ,i ,',str))
		    (sub (replacement i &key fixedcase literal-string)
		      `(replace-match ,replacement ,fixedcase ,literal-
string ,',str ,i)))
	   (symbol-macrolet (;; no convenient way to support before/after
match for buffer search
			     ;;before
			     ;;($b (substring ,str 0 (match-beginning 0)))
			     ;;after
			     ;;($a (substring ,str (match-end 0) (length ,str)))
			     ;;match
			     ($m (match-string 0 ,str))
			     (foo ,str)
			     )
	     (set-match-data ,md) ;; workaround to set match-data back to the
original data.
	     ,@body))))))

(defmacro* =~ (regex string &rest body)
  (let ((str (gensym)))
    `(let ((,str ,string))
       (when (string-match ,regex ,str)
	      (with-match-data (:in-string ,str)
		,@body)))))

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: symbol-macrolet clobbers (match-data), bug or feature?
  2007-08-14 20:43 symbol-macrolet clobbers (match-data), bug or feature? Howard Yeh!
@ 2007-08-16  1:08 ` Richard Stallman
  0 siblings, 0 replies; 2+ messages in thread
From: Richard Stallman @ 2007-08-16  1:08 UTC (permalink / raw)
  To: Howard Yeh!; +Cc: bug-gnu-emacs

This is an interesting idea, but I'd rather it be implemented in a way
that does not require loading CL, and not using symbol-macrolet.

One way to do that is to write a list of variables to bind to certain
match values, like this:

(r=~ "\\(abc\\)\\(efg\\)?" "abcefg"
     ((s0 b0 e0) (s1) (s2))
   (list (match-data) b0 e0 s0 s1 s2))

which would be equivalent to your

(r=~ "\\(abc\\)\\(efg\\)?" "abcefg"
     (list (match-data) <0 >0 $0 $1 $2))

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-08-16  1:08 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-14 20:43 symbol-macrolet clobbers (match-data), bug or feature? Howard Yeh!
2007-08-16  1:08 ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).