From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christopher Genovese Subject: Re: full parser implementation for tag queries (parentheses, fast heading match, and more) Date: Sat, 4 Aug 2012 06:07:18 -0400 Message-ID: References: Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=047d7b10d1f789ea4204c66dd08e Return-path: Received: from eggs.gnu.org ([208.118.235.92]:47579) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SxbGq-0008QJ-1j for emacs-orgmode@gnu.org; Sat, 04 Aug 2012 06:07:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SxbGm-0003mk-LT for emacs-orgmode@gnu.org; Sat, 04 Aug 2012 06:07:43 -0400 Received: from mail-pb0-f41.google.com ([209.85.160.41]:43372) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SxbGm-0003mZ-4v for emacs-orgmode@gnu.org; Sat, 04 Aug 2012 06:07:40 -0400 Received: by pbbrp2 with SMTP id rp2so2984561pbb.0 for ; Sat, 04 Aug 2012 03:07:39 -0700 (PDT) In-Reply-To: List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: emacs-orgmode@gnu.org --047d7b10d1f789ea4204c66dd08e Content-Type: text/plain; charset=ISO-8859-1 A small addendum: Right after I posted (of course!), I noticed both a small mistake and an opportunity for simplification, relating to detecting and processing the todo expressions after a /. Specifically, the approximate fix I proposed to the bug in the 7.8 code is insufficient to handle regexp matching in todo expressions. The full solution using the new function org-find-todo-query is needed in the code as I have it, and that can just be plugged in instead of the string-match. (See Note h in the original post, specifically the string-match given there, and org-find-todo-query.) But I realized that all that is unnecessary as the todo processing can be easily built into the new parser. I've mostly done that just now and will test and post an update Saturday, er...today. Sorry to muddy the waters by not catching that earlier, and sorrier still if I'm rambling. Off to bed... -- Christopher On Sat, Aug 4, 2012 at 3:50 AM, Christopher Genovese wrote: > I am writing an application layer on top of org that uses the > entry mapping API, but I needed both negation of complex > selections and heading searches. Because the current tag query > parser does not handle parenthesized expressions, it does not > allow negating complex queries. At first, I wrote a workaround > solution that mimics/specializes the mapping API, but that > approach seemed inelegant and harder to maintain. > > So instead I implemented a full parser for tag queries with a > number of useful features (see the labeled Notes at the bottom > for further comments on these features): > > 1. Parenthesized expressions to arbitrary depth are allowed. > 2. A '-' can be used to negate a parenthesized term. [Note a] > 3. Regex's in {} can contain braces escaped by doubling: {{ }}. [Note b] > 4. Supports fast property search on HEADING and PRIORITY. [Note c] > 5. Handles hyphens in property names properly. [Note > d,h] > 6. Allows only the proper comparison operators, including ==. [Note > e,h] > 7. Allows spaces around operators and terms for readability. [Note f] > 8. Matchers use the original expression order; not a big > deal, but free. > 9. The error messages during parsing are reasonably helpful. > 10. Several bug fixes and a cleaner `org-make-tags-matcher'. [Note h] > > I'm submitting the code for your consideration, with the > goal of eventually incorporating this into org.el. I would be > happy to hear any comments or suggestions you have. As I'll describe > below, this involves relatively minor changes to two existing > functions and adding a few new support functions. I've attached two > files org-tag-query-parse.el (the code) and tag-query-tests.el (a > collection of tests built on a simple framework). I've also > put the files in http://www.stat.cmu.edu/~genovese/emacs/. The > comments in both files will I hope be helpful. > > At the risk of going on too long, I'd like to add a few comments > about the code and tests. First, the two existing functions that > are affected in the code are `org-make-tags-matcher' and > `org-scan-tags'. In the new version of the former, I've extracted > out both kinds of query parsing, leading to a shorter and cleaner > function. The new version of the latter differs in only a couple > *very minor* places that capture two values that were already > being computed anyway (see the diff reproduced in the comments). > Btw, I'm working from the 7.8.11 code. > > Loading org-tag-query-parse.el does not change the original > functions. Instead, I've added a `-NEW' to the names of these > functions and saved the originals also with a `-ORIGINAL' added. > After loading the file, you can choose a version to try by doing > > (org-tmp-use-tag-parser 'new) > and > (org-tmp-use-tag-parser 'original) > > or do (org-tmp-use-tag-parser) to toggle between versions. > You can also just use the names with suffixes directly. > I'd also suggest byte-compiling the file. > > I think the place to start looking at the code is the new version > of `org-make-tags-matcher'. The main entry function for the new > parser is `org-tag-query-parse', though the real workhorse is > actually the function `org-tag-query-parse-1'. There is also a > new function `org-todo-query-parse' which just extracts the > existing todo matching method. (I didn't do anything with that > method as the manual makes it clear that it is of secondary > importance.) I think the modularity here makes > `org-make-tags-matcher' and each separate parser easier to read > and understand. > > The other substantial piece (in terms of lines of code) is a utility > macro `org-match-cond' that is used throughout and makes the main > parser much more readable IMHO. Admittedly, I went a bit > overboard in optimizing it; the first version worked fine > but this one produces really nice code. I'd suggest ignoring this > code (in section "Parsing utility for readable matchers") on > first pass. The docstring is pretty complete, and its use is more > or less self-explanatory. Most of its work is done at compile time. > > To run the tests, load org-tag-query-parse.el and tag-query-tests.el > and do > > (tag-test-run :results) ; use :summary for a brief summary of all runs > (tag-test-other-tests) ; miscellaneous other tests, including scanning > > or name individual suites. They are at the moment: > > (tag-test-run :results 'org-comparison-1) ; or use :summary > (tag-test-run :results 'org-comparison-2) > (tag-test-run :results 'match-results-1) > (tag-test-run :results 'match-results-2) > (tag-test-run :results 'should-error-1) > > If you have other ideas for tests or find any bugs, please let me > know. Sorry for the homegrown framework; it just sort of grew and > then I was too tired to rewrite the tests. One complication here > is that the original and new algorithms produce different term > orders and use a few different functions. The function > tag-test-transform transforms original results to the new > algorithms conventions, but it does not handle PRIORITY or > HEADING matches at the moment. Use the tree form of the tess (see > match-results-1 for example) on these. Btw, I've run the tests on > GNU Emacs 23.2 and 24.1 (running on OS X lion). > > Notes: > a. There is no need to introduce a new character such as ! for > negation because the semantics of the - are clear and are > consistent with its use for tags. A - binds more tightly > than & which in turn binds more tightly than |. A + > selector can also be used for positive selection of a > parenthesized term but it is equivalent to using no > selector, just as for tags. > > b. Because \'s are so heavily used in regex's and because they > have to be doubled in strings, using \'s for an additional > escape layer would be messy, ambiguous, and hard to read. > Only the {}'s need to be escaped and the doubling escapes > {{ -> { and }} -> } are simple, readable, and fast to > parse. For example: "+{abc\\{{3,7\\}}}" gives the regex > "abc\\{3,7\\}". Parity makes correctness clear at a glance. > > c. Because headline (and priority) searches can be useful and > powerful, and because the information on those fields is > *already processed* in `org-scan-tags', we get those > special searches *essentially for free*, requiring only two > minor changes to `org-scan-tags'. See the unified diff in > comments. The special PRIORITY property already exists; I > added the special HEADING property for these purposes. I'm > open to changing the name of course, but I do think the > feature is both useful and elegant. (I'm using it in my > application, for instance.) > > d. I did not see it in the manual, but I think that property names > with hyphens should have these \-escaped -'s in the query > string, with the escaping slashes removed in the produced > matcher. This is not currently done, but the new version does. > See Note h for details. > > e. It seems desirable to support both = and == as equality operators > since the latter is so common by habit. The new version allows > this explicitly. The original version does as well, but the > regex for the comparison operator also allows other operators > <<, ><, >>, =>, and >= as well, which can produce bad matchers. > See Note h for details. > > f. Currently, spaces are ignored around &, |, the implicit & between > terms, around the comparison operators in property searches, > and around +/- selectors. Spaces are not ignored inside {}'s > for a regexp match. > > g. The current code also allows +/- selectors before property > comparisons. I don't really like this because > +PROP<>"something" and -PROP="something" have the same > meaning but look very different. But the new code does > support this. As a side note, there's really no need for > the & characters as +/- serve the and/and-not function > completely. But again, no prob. > > h. A few bugs detected in the 7.8.11 code: > > + Faulty test for todo matcher in org-make-tags-matcher > (string-match "/+" match) > > Ex: (org-make-tags-matcher "PROP={^\\s-*// .*$}") produces > an erroneous matcher: > > ("PROP={^\\s-*// .*$}" progn > (setq org-cached-props nil) > (member "PROP" tags-list)) > > For all practical purposes it will be enough to do: > > (string-match "\\(/\\(!\\)?\\s-*\\)[^{}\"]*$" match) > > instead of the current test in org-make-tags-matcher. > This works as long as the TODO keywords do not contain a > right brace or quotation marks. (In most other cases, the > new parser should give an error message at parse time.) > > A technicality: this is /not/ a complete solution because > arbitrary strings can be TODO keywords. For instance, > both PROP={/!} and PROP="/!{/!}" are valid TODO keywords > (it works!) *and* valid property comparisons. So, a pattern > alone is insufficient. We want to find the first slash > that is not enclosed in {}'s or ""'s; if found, a todo > match is needed. The function `org-find-todo-query' does > this and (org-find-todo-query match) can be plugged in > directly replacing the above (string-match ...) in then > new `org-make-tags-matcher'. > > But because the todo parsing uses {}'s for regex matches, > TODO keywords with {}'s are ignored anyway. So there's > no need to go beyond the fixed string-match above. > The function `org-todo-query-parse', which handles todo > parsing in the new version, makes this explicit. > > + Property names with -'s are not handled properly (cf. Note d) > > Specifically, the escapes are not removed. Example: > (org-make-tags-matcher "PROP\\-WITH\\-HYPHENS=2") > produces > > ("PROP\\-WITH\\-HYPHENS=2" and > (progn > (setq org-cached-props nil) > (= > (string-to-number > (or (org-cached-entry-get nil "PROP\\-WITH\\-HYPHENS") > "")) > 2)) > t) > > The original code /does/ instead remove -'s from tag > names, which shouldn't have them anyway. I suspect that > this was intended for property names rather than tag > names. The new version fixes up property names but does > not allow -'s in tags. > > + Incorrect comparison operators allowed (cf. Note e) > > The regular expression used is "[<=>]\\{1,2\\}" is used to > detect the comparison operators. But this can produce bad > matchers that fail opaquely at match time rather than > giving an appropriate error message at parse time. > > Ex: (org-make-tags-matcher "P<<2") produces > > ("P<<2" and > (progn > (setq org-cached-props nil) > (nil > (string-to-number (or (org-cached-entry-get nil "P") "")) 2)) > t) > > This is fixed in the new version and delivers an error > message at parse time. > > + missing org-re (line 7179 in org.el) with posix classes > > Minor consistency issue. This line does not occur in the new > code. > > > Thanks and regards, > > Christopher Genovese > > > --047d7b10d1f789ea4204c66dd08e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable A small addendum:

Right after I posted (of course!), I noticed both = a small mistake and an opportunity for
simplification, relating to detec= ting and processing the todo expressions after a /.
Specifically, the ap= proximate fix I proposed to the bug in the 7.8 code is insufficient
to handle regexp matching in todo expressions. The full solution using the<= br>new function org-find-todo-query is needed in the code as I have it, and= that can just
be plugged in instead of the string-match. (See Note h in= the original post, specifically
the string-match given there, and org-find-todo-query.)

But I reali= zed that all that is unnecessary as the todo processing can be easily built=
into the new parser. I've mostly done that just now and will test = and post an update
Saturday, er...today.

Sorry to muddy the waters by not catching tha= t earlier, and sorrier still if I'm rambling.=A0
Off to bed...
<= br>=A0-- Christopher


On Sat, Aug 4, 2= 012 at 3:50 AM, Christopher Genovese <genovese@cmu.edu> wrote= :
I am writing an application layer on top of org that uses the<= br style=3D"font-family:courier new,monospace"> entry mapping API, but I = needed both negation of complex
selections and heading se= arches. Because the current tag query
parser d= oes not handle parenthesized expressions, it does not
allow negating complex qu= eries. At first, I wrote a workaround
solution= that mimics/specializes the mapping API, but that
approach seemed inelegant= and harder to maintain.

So instead I implemented a full parser for tag q= ueries with a
number of useful features= (see the labeled Notes at the bottom
for furt= her comments on these features):

=A0 1. Parenthesized expressions to arbitrary depth = are allowed.
=A0 2. A '-' can be used = to negate a parenthesized term.=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 [Note a= ]
=A0 3. Regex's in {} = can contain braces escaped by doubling: {{ }}.=A0 [Note b]
=A0 4. Supports fast property search on HEADING and PRIORITY.= =A0=A0=A0=A0=A0=A0=A0 [Note c]
=A0 5. Handles hyphens in= property names properly.=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 [Note d,h]
=A0 6. Allows only the prope= r comparison operators, including =3D=3D.=A0=A0=A0 [Note e,h]
=A0 7. Allows spaces arou= nd operators and terms for readability.=A0=A0=A0=A0 [Note f]
=A0 8. Matchers use the original expression order; not a big=
=A0=A0=A0=A0 deal, but fr= ee.
=A0 9. The error messages during parsing a= re reasonably helpful.
=A0 10. Several bug fixes= and a cleaner `org-make-tags-matcher'.=A0=A0=A0=A0 [Note h]

I'm submitting the co= de for your consideration, with the
goal of eventually incorporating th= is into org.el. I would be

happy to hear any comment= s or suggestions you have. As I'll describe
functions and adding a fe= w new support functions. I've attached two
files org-tag-query-parse.el (the code) and tag-query-tests.el (a collection of tests built= on a simple framework). I've also
put the= files in http://www.stat.cmu.edu/~genovese/emacs/. The
comments in both files wi= ll I hope be helpful.

At the risk of going on too long, I'd like to a= dd a few comments
about the code and tests.= First, the two existing functions that
are af= fected in the code are `org-make-tags-matcher' and
`org-scan-tags'. In t= he new version of the former, I've extracted
out both kinds of query parsing, leading to a shorter and cleaner=
function. The new version= of the latter differs in only a couple
*very = minor* places that capture two values that were already
being computed anyway (se= e the diff reproduced in the comments).
Btw, I= 'm working from the 7.8.11 code.

Loading org-tag-query-parse.el does not change the o= riginal
functions. Instead, I've added a= `-NEW' to the names of these
functions and saved the o= riginals also with a `-ORIGINAL' added.
Af= ter loading the file, you can choose a version to try by doing

=A0=A0=A0 (org-tmp-use-tag-parser 'new)and
=A0=A0=A0 (org-tmp-use-ta= g-parser 'original)

or do (org-tmp-use-tag-parser) to toggle between = versions.
You can also just use the= names with suffixes directly.
I'd also s= uggest byte-compiling the file.

I think the place to start looking at the code is th= e new version
of `org-make-tags-matcher'. = The main entry function for the new
parser is `org-tag-query-= parse', though the real workhorse is
actua= lly the function `org-tag-query-parse-1'. There is also a
new function `org-todo-qu= ery-parse' which just extracts the
existin= g todo matching method. (I didn't do anything with that
method as the manual make= s it clear that it is of secondary
importance.= ) I think the modularity here makes
`org-make-tags-matcher= 9; and each separate parser easier to read
and= understand.

The other substantial piece (in terms of lines of co= de) is a utility
macro `org-match-cond' th= at is used throughout and makes the main

parser much more readable= IMHO. Admittedly, I went a bit
overboard in o= ptimizing it; the first version worked fine
but this one produces rea= lly nice code. I'd suggest ignoring this
c= ode (in section "Parsing utility for readable matchers") on
first pass. The docstring= is pretty complete, and its use is more
or le= ss self-explanatory. Most of its work is done at compile time.

To run the tests, load org-tag-query-parse.el and ta= g-query-tests.el
and do


=A0=A0 (tag-test-run :results) ; use :summary for a = brief summary of all runs
=A0=A0 (tag-test-other-te= sts)=A0 ; miscellaneous other tests, including scanning

or name individual suites. They are at the moment:

=A0=A0 (tag-test-run :res= ults 'org-comparison-1)=A0 ; or use :summary
=A0=A0 (tag-test-run :results 'org-comparison-2)
=A0=A0 (tag-test-run :res= ults 'match-results-1)
=A0=A0 (tag-test-ru= n :results 'match-results-2)
=A0=A0 (tag-test-run :res= ults 'should-error-1)

If you have other ideas for tests or find any b= ugs, please let me
know. Sorry for the homeg= rown framework; it just sort of grew and
then = I was too tired to rewrite the tests. One complication here
is that the original and = new algorithms produce different term
orders a= nd use a few different functions. The function
tag-test-transform transf= orms original results to the new
algorithms co= nventions, but it does not handle PRIORITY or
HEADING matches at the mo= ment. Use the tree form of the tess (see
match= -results-1 for example) on these. Btw, I've run the tests on
GNU Emacs 23.2 and 24.1 (= running on OS X lion).

Notes:
=A0=A0 a. There is no nee= d to introduce a new character such as ! for
= =A0=A0=A0=A0=A0 negation because the semantics of the - are clear and are
=A0=A0=A0=A0=A0 consisten= t with its use for tags. A - binds more tightly
=A0=A0=A0=A0=A0 selector = can also be used for positive selection of a
= =A0=A0=A0=A0=A0 parenthesized term but it is equivalent to using no<= br style=3D"font-family:courier new,monospace"> =A0=A0=A0=A0=A0 selector,= just as for tags.
=A0=A0=A0=A0=A0

=A0=A0 b. Because \'s= are so heavily used in regex's and because they
=A0=A0=A0=A0=A0 have to be doubled in strings, using \'s for an = additional
=A0=A0=A0=A0=A0 escape la= yer would be messy, ambiguous, and hard to read.
=A0=A0=A0=A0=A0 Only the {}'s need to be escaped and the doubling es= capes
=A0=A0=A0=A0=A0 {{ -> = { and }} -> } are simple, readable, and fast to
=A0=A0=A0=A0=A0 parse. For example: "+{abc\\{{3,7\\}}}" give= s the regex
=A0=A0=A0=A0=A0 "abc= \\{3,7\\}". Parity makes correctness clear at a glance.
=A0=A0=A0=A0=A0
=A0=A0 c. Because headlin= e (and priority) searches can be useful and
= =A0=A0=A0=A0=A0 powerful, and because the information on those fields is
=A0=A0=A0=A0=A0 *already = processed* in `org-scan-tags', we get those
=A0=A0=A0=A0=A0 minor cha= nges to `org-scan-tags'. See the unified diff in
=A0=A0=A0=A0=A0 comments. The special PRIORITY property already exis= ts; I
=A0=A0=A0=A0=A0 added the= special HEADING property for these purposes. I'm
=A0=A0=A0=A0=A0 open to changing the name of course, but I do think= the
=A0=A0=A0=A0=A0 feature i= s both useful and elegant. (I'm using it in my
=A0=A0=A0=A0=A0 application, for instance.)

=A0=A0 d. I did not see it in the manual, but I thin= k that property names
=A0=A0=A0=A0=A0 with hyp= hens should have these \-escaped -'s in the query
=A0=A0=A0=A0=A0 string, w= ith the escaping slashes removed in the produced
=A0=A0=A0=A0=A0 matcher. This is not currently done, but the new version= does.
=A0=A0=A0=A0=A0 See Note = h for details.

=A0=A0 e. It seems desirable to support both =3D and =3D= =3D as equality operators
=A0=A0=A0=A0=A0 since the= latter is so common by habit. The new version allows
=A0=A0=A0=A0=A0 this explicitly. The original version does as well,= but the
=A0=A0=A0=A0=A0 regex for= the comparison operator also allows other operators
=A0=A0=A0=A0=A0 <<, ><, >>, =3D>, and >=3D a= s well, which can produce bad matchers.
=A0=A0=A0=A0=A0 See Note = h for details.

=A0=A0 f. Currently, spaces are ignored around &, |, t= he implicit & between
=A0=A0=A0=A0=A0 terms, ar= ound the comparison operators in property searches,
=A0=A0=A0=A0=A0 and around +/- selectors. Spaces are not ignored insi= de {}'s
=A0=A0=A0=A0=A0 for a reg= exp match.

=A0=A0 g. The current code also allows +/- selectors before p= roperty
=A0=A0=A0=A0=A0 compariso= ns. I don't really like this because
=A0= =A0=A0=A0=A0 +PROP<>"something" and -PROP=3D"something= " have the same
=A0=A0=A0=A0=A0 meaning b= ut look very different. But the new code does
= =A0=A0=A0=A0=A0 support this. As a side note, there's really no need fo= r
=A0=A0=A0=A0=A0 the &= characters as +/- serve the and/and-not function
=A0=A0=A0=A0=A0 completely. But again, no prob.

=A0=A0 h. A few bugs detected in the 7.8.11 code:

=A0=A0=A0=A0=A0 + Faulty = test for todo matcher in org-make-tags-matcher
=A0=A0=A0=A0=A0=A0=A0 (string-match "/+" match)

=A0=A0=A0=A0=A0=A0=A0 Ex: (org-make-tags-matcher &qu= ot;PROP=3D{^\\s-*// .*$}") produces
=A0=A0=A0=A0=A0=A0=A0 an = erroneous matcher:
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ("PROP=3D{^\\s-= *// .*$}" progn
=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (setq org-cached-props nil)
=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (member "PROP" tags-list))

=A0=A0=A0=A0=A0=A0=A0 For all practical purposes it = will be enough to do:
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0=A0 = (string-match "\\(/\\(!\\)?\\s-*\\)[^{}\"]*$" match)<= br style=3D"font-family:courier new,monospace">=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 ins= tead of the current test in org-make-tags-matcher.
=A0=A0=A0=A0=A0=A0=A0 This works as long as the TODO keywords do not c= ontain a
=A0=A0=A0=A0=A0=A0=A0 rig= ht brace or quotation marks. (In most other cases, the
=A0=A0=A0=A0=A0=A0=A0 new parser should give an error message at p= arse time.)
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 A technicality: this is /n= ot/ a complete solution because
=A0=A0=A0=A0=A0=A0=A0 arb= itrary strings can be TODO keywords. For instance,
=A0=A0=A0=A0=A0=A0=A0 both PROP=3D{/!} and PROP=3D"/!{/!}" a= re valid TODO keywords
=A0=A0=A0=A0=A0=A0=A0 (it= works!) *and* valid property comparisons. So, a pattern

=A0=A0=A0=A0=A0=A0=A0 alone is insufficient. We want to find the= first slash
=A0=A0=A0=A0=A0=A0=A0 tha= t is not enclosed in {}'s or ""'s; if found, a todo
=A0=A0=A0=A0=A0=A0=A0 match is needed. The function= `org-find-todo-query' does
=A0=A0=A0=A0=A0=A0=A0 thi= s and (org-find-todo-query match) can be plugged in
=A0=A0=A0=A0=A0=A0=A0 directly replacing the above (string-match ...)= in then
=A0=A0=A0=A0=A0=A0=A0 new= `org-make-tags-matcher'.
=A0=A0=A0=A0=A0= =A0=A0
=A0=A0=A0=A0=A0=A0=A0 But= because the todo parsing uses {}'s for regex matches,
=A0=A0=A0=A0=A0=A0=A0 TODO keywords with {}'s are ignored= anyway. So there's
=A0=A0=A0=A0=A0=A0=A0 no = need to go beyond the fixed string-match above.
=A0=A0=A0=A0=A0=A0=A0 par= sing in the new version, makes this explicit.
= =A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0 + Propert= y names with -'s are not handled properly (cf. Note d)

=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 Spe= cifically, the escapes are not removed. Example:
=A0=A0=A0=A0=A0=A0=A0 (org-make-tags-matcher "PROP\\-WITH\\-HYPHENS= =3D2")
=A0=A0=A0=A0=A0=A0=A0 pro= duces
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 (&q= uot;PROP\\-WITH\\-HYPHENS=3D2" and
=A0=A0= =A0=A0=A0=A0=A0=A0 (progn
=A0=A0=A0=A0=A0=A0=A0=A0 = (setq org-cached-props nil)
=A0=A0=A0=A0=A0=A0= =A0=A0 (=3D
=A0=A0=A0=A0=A0=A0=A0=A0= =A0 (string-to-number
=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 (or (org-cached-entry-get nil "PROP\\-WITH\\-HYPHENS")

=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 ""))
=A0=A0=A0=A0=A0=A0=A0=A0= =A0 2))
=A0=A0=A0=A0=A0=A0=A0=A0 = t)
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 The= original code /does/ instead remove -'s from tag
=A0=A0=A0=A0=A0=A0=A0 names, which shouldn't have them anyway. = I suspect that
=A0=A0=A0=A0=A0=A0=A0 thi= s was intended for property names rather than tag
=A0=A0=A0=A0=A0=A0=A0 names. The new version fixes up property names bu= t does
=A0=A0=A0=A0=A0=A0=A0 not= allow -'s in tags.

=A0=A0=A0=A0=A0 + Incorrect comparison operators = allowed (cf. Note e)
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 The regular expression use= d is "[<=3D>]\\{1,2\\}" is used to
=A0=A0=A0=A0=A0=A0=A0 det= ect the comparison operators. But this can produce bad
=A0=A0=A0=A0=A0=A0=A0 matchers that fail opaquely at match time ra= ther than
=A0=A0=A0=A0=A0=A0=A0 giv= ing an appropriate error message at parse time.

= =A0=A0=A0=A0=A0=A0=A0 Ex:= (org-make-tags-matcher "P<<2") produces

=A0=A0=A0=A0=A0=A0=A0=A0 ("P<<2" and=
=A0=A0=A0=A0=A0=A0=A0=A0=A0 (progn
=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 (setq org-cached-props nil)
=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (nil
=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (string-to-number (or (org-cached-entry-get nil "P")= "")) 2))
<= span style=3D"font-family:courier new,monospace">=A0=A0=A0=A0=A0=A0=A0=A0= =A0 t)


=A0=A0=A0=A0=A0=A0=A0 This is fixed in the new versi= on and delivers an error
=A0=A0=A0=A0=A0=A0= =A0 message at parse time.

=A0=A0=A0=A0=A0 + missing org-re (line 7179 in org.e= l) with posix classes
=A0=A0=A0=A0=A0=A0=A0
=A0=A0=A0=A0=A0=A0=A0 Min= or consistency issue.=A0 This line does not occur in the new
=A0=A0=A0=A0=A0=A0=A0 code.


Than= ks and regards,

=A0=A0 Christopher Genove= se



--047d7b10d1f789ea4204c66dd08e--