From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Mattias =?UTF-8?Q?Engdeg=C3=A5rd?= Newsgroups: gmane.emacs.bugs Subject: bug#36444: [PATCH] Improved regexp-opt KEEP-ORDER check Date: Sun, 30 Jun 2019 14:28:57 +0200 Message-ID: <2CE5D98F-8F07-4E79-9132-FDBA0062D8E2@acm.org> Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\)) Content-Type: multipart/mixed; boundary="Apple-Mail=_2FDB2CD4-5E7F-4C22-9EAD-033BA0D7F357" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="42657"; mail-complaints-to="usenet@blaine.gmane.org" To: 36444@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Jun 30 14:30:27 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hhYyQ-000AyB-Cn for geb-bug-gnu-emacs@m.gmane.org; Sun, 30 Jun 2019 14:30:26 +0200 Original-Received: from localhost ([::1]:44552 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhYyO-0005vB-Nu for geb-bug-gnu-emacs@m.gmane.org; Sun, 30 Jun 2019 08:30:24 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:36760) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhYy3-0005v5-Qv for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:30:04 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhYy2-0006ed-TQ for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:30:03 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:60153) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hhYy2-0006dp-NT for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:30:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hhYy2-0001XO-Je for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:30:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Mattias =?UTF-8?Q?Engdeg=C3=A5rd?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 30 Jun 2019 12:30:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 36444 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.15618977595830 (code B ref -1); Sun, 30 Jun 2019 12:30:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 30 Jun 2019 12:29:19 +0000 Original-Received: from localhost ([127.0.0.1]:45464 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hhYxL-0001Vy-Gn for submit@debbugs.gnu.org; Sun, 30 Jun 2019 08:29:19 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:37438) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hhYxJ-0001Vq-Cv for submit@debbugs.gnu.org; Sun, 30 Jun 2019 08:29:18 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:36694) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhYxI-0005lx-Hr for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:29:17 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhYxH-00061M-Jd for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:29:16 -0400 Original-Received: from mail205c50.megamailservers.eu ([91.136.10.215]:36430 helo=mail193c50.megamailservers.eu) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hhYxH-0005mo-0V for bug-gnu-emacs@gnu.org; Sun, 30 Jun 2019 08:29:15 -0400 X-Authenticated-User: mattiase@bredband.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=megamailservers.eu; s=maildub; t=1561897740; bh=gm9T1VDSqK7MIsyvaU6Bbsf39+oM9y3CpwQGDOklcZY=; h=From:Subject:Date:To:From; b=qoKDwZBuBHgTUyGLDZxVpZ1xobAG60q+ysMAkdkebBemUUHwEFtUIgsVcmufdcETy 5/h/SIrnORmbFqGxHvxMrbuV95CNpcm2kr19YHNxwgg7yJpsT9v01NZqrQ/UlfjkWU Nus/vC8Sgyna/ubwQw7e4bLMvTyXn5QeZu6Z/R94= Feedback-ID: mattiase@acm.or Original-Received: from [192.168.1.65] (c-e636e253.032-75-73746f71.bbcust.telenor.se [83.226.54.230]) (authenticated bits=0) by mail193c50.megamailservers.eu (8.14.9/8.13.1) with ESMTP id x5UCSv1D009634 for ; Sun, 30 Jun 2019 12:29:00 +0000 X-Mailer: Apple Mail (2.3445.104.11) X-CTCH-RefID: str=0001.0A0B020F.5D18AB0C.0048, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-CTCH-VOD: Unknown X-CTCH-Spam: Unknown X-CTCH-Score: 0.000 X-CTCH-Flags: 0 X-CTCH-ScoreCust: 0.000 X-CSC: 0 X-CHA: v=2.3 cv=KsZjJ1eN c=1 sm=1 tr=0 a=M+GU/qJco4WXjv8D6jB2IA==:117 a=M+GU/qJco4WXjv8D6jB2IA==:17 a=lvMLtnk2CsVkxFO_dGUA:9 a=CjuIK1q_8ugA:10 a=s2lJpgmBrr0SaIv6U2UA:9 a=B2y7HmGcmWMA:10 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:161876 Archived-At: --Apple-Mail=_2FDB2CD4-5E7F-4C22-9EAD-033BA0D7F357 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Currently, regexp-opt does not attempt optimisation with KEEP-ORDER set = if the input list contains a proper prefix of another element, like ("ab" "abcd") on the grounds that the optimised string would be "ab\\(?:cd\\)?" which would not preserve the match order. However, this also prevents ("abcd" "ab") from being optimised, even though doing so would be harmless. The attached patch strengthens the check, allowing more inputs to be = optimised. --Apple-Mail=_2FDB2CD4-5E7F-4C22-9EAD-033BA0D7F357 Content-Disposition: attachment; filename=0001-Optimise-more-inputs-to-regexp-opt.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-Optimise-more-inputs-to-regexp-opt.patch" Content-Transfer-Encoding: quoted-printable =46rom=20ee29b82719c6ca40b3ff9054fcbf4e964ed18ad3=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20=3D?UTF-8?q?Mattias=3D20Engdeg=3DC3=3DA5rd?=3D=20= =0ADate:=20Sun,=2030=20Jun=202019=2012:53:52=20+0200=0A= Subject:=20[PATCH]=20Optimise=20more=20inputs=20to=20`regexp-opt'=0A=0A= Use=20a=20more=20precise=20test=20to=20determine=20whether=20the=20input=20= to=20`regexp-opt'=0Ais=20safe=20to=20optimise=20when=20KEEP-ORDER=20is=20= non-nil,=20permitting=20more=20inputs=0Ato=20be=20optimised=20than=20= before.=20=20For=20example,=20("good"=20"goal"=20"go")=20is=20now=0A= accepted.=0A=0A*=20lisp/emacs-lisp/regexp-opt.el=20(regexp-opt):=0AMore=20= precise=20test=20for=20whether=20the=20list=20is=20safe=20w.r.t.=20= KEEP-ORDER.=0A(regexp-opt--contains-prefix):=20Remove.=0A=0A*=20= test/lisp/emacs-lisp/regexp-opt-tests.el:=20Use=20lexical-binding.=0A= (regexp-opt-test--permutation,=20regexp-opt-test--factorial)=0A= (regexp-opt-test--permutations,=20regexp-opt-test--match-all)=0A= (regexp-opt-test--check-perm,=20regexp-opt-test--explain-perm)=0A= (regexp-opt-keep-order):=20Test=20KEEP-ORDER.=0A---=0A=20= lisp/emacs-lisp/regexp-opt.el=20=20=20=20=20=20=20=20=20=20=20=20|=2045=20= ++++++++---------=0A=20test/lisp/emacs-lisp/regexp-opt-tests.el=20|=2062=20= +++++++++++++++++++++++-=0A=202=20files=20changed,=2082=20insertions(+),=20= 25=20deletions(-)=0A=0Adiff=20--git=20a/lisp/emacs-lisp/regexp-opt.el=20= b/lisp/emacs-lisp/regexp-opt.el=0Aindex=20b6104f22e7..8afb0c08db=20= 100644=0A---=20a/lisp/emacs-lisp/regexp-opt.el=0A+++=20= b/lisp/emacs-lisp/regexp-opt.el=0A@@=20-140,21=20+140,33=20@@=20= regexp-opt=0A=20=09=20=20=20(completion-ignore-case=20nil)=0A=20=09=20=20= =20(completion-regexp-list=20nil)=0A=20=09=20=20=20(open=20(cond=20= ((stringp=20paren)=20paren)=20(paren=20"\\(")))=0A-=09=20=20=20= (sorted-strings=20(delete-dups=0A-=09=09=09=20=20=20=20(sort=20= (copy-sequence=20strings)=20'string-lessp)))=0A=20=09=20=20=20(re=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20(cond=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20;;=20No=20strings:=20return=20an=20unmatchable=20regexp.=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20((null=20strings)=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20(concat=20(or=20open=20"\\(?:")=20= regexp-unmatchable=20"\\)"))=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20= ;;=20If=20we=20cannot=20reorder,=20give=20up=20all=20attempts=20at=0A-=20= =20=20=20=20=20=20=20=20=20=20=20=20;;=20optimisation.=20=20There=20is=20= room=20for=20improvement=20(Bug#34641).=0A-=20=20=20=20=20=20=20=20=20=20= =20=20=20((and=20keep-order=20(regexp-opt--contains-prefix=20= sorted-strings))=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20(concat=20= (or=20open=20"\\(?:")=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(mapconcat=20#'regexp-quote=20strings=20"\\|")=0A-=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"\\)"))=0A+=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20;;=20The=20algorithm=20will=20= generate=20a=20pattern=20that=20matches=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20;;=20longer=20strings=20in=20the=20list=20before=20shorter.=20=20= If=20the=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20;;=20list=20order=20= matters,=20then=20no=20string=20must=20come=20after=20a=0A+=20=20=20=20=20= =20=20=20=20=20=20=20=20;;=20proper=20prefix=20of=20that=20string.=20=20= To=20check=20this,=20verify=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20;;=20= that=20a=20straight=20or-pattern=20matches=20each=20string=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20;;=20entirely.=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20((and=20keep-order=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(let*=20((case-fold-search=20nil)=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(alts=20= (mapconcat=20#'regexp-quote=20strings=20"\\|")))=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20(and=20(save-match-data=0A+=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(let=20((s=20strings))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(while=20(and=20s=0A+=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20(string-match=20alts=20(car=20= s))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(=3D=20= (match-end=200)=20(length=20(car=20s))))=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(setq=20= s=20(cdr=20s)))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20s))=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(concat=20(or=20open=20= "\\(?:")=20alts=20"\\)")))))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (t=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20(regexp-opt-group=20= sorted-strings=20(or=20open=20t)=20(not=20open))))))=0A+=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(regexp-opt-group=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(delete-dups=20(sort=20(copy-sequence=20strings)=20= 'string-lessp))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(or=20= open=20t)=20(not=20open))))))=0A=20=20=20=20=20=20=20(cond=20((eq=20= paren=20'words)=0A=20=09=20=20=20=20=20(concat=20"\\<"=20re=20"\\>"))=0A=20= =09=20=20=20=20((eq=20paren=20'symbols)=0A@@=20-339,21=20+351,6=20@@=20= regexp-opt-charset=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20(concat=20= "["=20all=20"]")))))))=0A=20=0A=20=0A-(defun=20= regexp-opt--contains-prefix=20(strings)=0A-=20=20"Whether=20STRINGS=20= contains=20a=20proper=20prefix=20of=20one=20of=20its=20other=20elements.=0A= -STRINGS=20must=20be=20a=20list=20of=20sorted=20strings=20without=20= duplicates."=0A-=20=20(let=20((s=20strings))=0A-=20=20=20=20;;=20In=20a=20= lexicographically=20sorted=20list,=20a=20string=20always=20immediately=0A= -=20=20=20=20;;=20succeeds=20one=20of=20its=20prefixes.=0A-=20=20=20=20= (while=20(and=20(cdr=20s)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(not=20(string-equal=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(car=20s)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(substring=20(cadr=20s)=200=20(min=20(length=20= (car=20s))=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20(length=20(cadr=20s)))))))=0A-=20=20=20=20=20=20(setq=20s=20= (cdr=20s)))=0A-=20=20=20=20(cdr=20s)))=0A-=0A-=0A=20(provide=20= 'regexp-opt)=0A=20=0A=20;;;=20regexp-opt.el=20ends=20here=0Adiff=20--git=20= a/test/lisp/emacs-lisp/regexp-opt-tests.el=20= b/test/lisp/emacs-lisp/regexp-opt-tests.el=0Aindex=20= 927de8c6a5..3658964faa=20100644=0A---=20= a/test/lisp/emacs-lisp/regexp-opt-tests.el=0A+++=20= b/test/lisp/emacs-lisp/regexp-opt-tests.el=0A@@=20-1,4=20+1,4=20@@=0A= -;;;=20regexp-opt-tests.el=20---=20Tests=20for=20regexp-opt.el=0A+;;;=20= regexp-opt-tests.el=20---=20Tests=20for=20regexp-opt.el=20=20-*-=20= lexical-binding:=20t=20-*-=0A=20=0A=20;;=20Copyright=20(C)=202013-2019=20= Free=20Software=20Foundation,=20Inc.=0A=20=0A@@=20-25,6=20+25,66=20@@=0A=20= =0A=20(require=20'regexp-opt)=0A=20=0A+(defun=20= regexp-opt-test--permutation=20(n=20list)=0A+=20=20"The=20Nth=20= permutation=20of=20LIST,=200=20=E2=89=A4=20N=20<=20(length=20LIST)!."=0A= +=20=20(let=20((len=20(length=20list))=0A+=20=20=20=20=20=20=20=20= (perm-list=20nil))=0A+=20=20=20=20(dotimes=20(i=20len)=0A+=20=20=20=20=20= =20(let*=20((d=20(-=20len=20i))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20= (k=20(mod=20n=20d)))=0A+=20=20=20=20=20=20=20=20(push=20(nth=20k=20list)=20= perm-list)=0A+=20=20=20=20=20=20=20=20(setq=20list=20(append=20(butlast=20= list=20(-=20(length=20list)=20k))=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(nthcdr=20(1+=20k)=20= list)))=0A+=20=20=20=20=20=20=20=20(setq=20n=20(/=20n=20d))))=0A+=20=20=20= =20(nreverse=20perm-list)))=0A+=0A+(defun=20regexp-opt-test--factorial=20= (n)=0A+=20=20"N!"=0A+=20=20(apply=20#'*=20(number-sequence=201=20n)))=0A= +=0A+(defun=20regexp-opt-test--permutations=20(list)=0A+=20=20"All=20= permutations=20of=20LIST."=0A+=20=20(mapcar=20(lambda=20(i)=20= (regexp-opt-test--permutation=20i=20list))=0A+=20=20=20=20=20=20=20=20=20= =20(number-sequence=200=20(1-=20(regexp-opt-test--factorial=20(length=20= list))))))=0A+=0A+(defun=20regexp-opt-test--match-all=20(words=20re)=0A+=20= =20(mapcar=20(lambda=20(w)=20(and=20(string-match=20re=20w)=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (match-string=200=20w)))=0A+=20=20=20=20=20=20=20=20=20=20words))=0A+=0A= +(defun=20regexp-opt-test--check-perm=20(perm)=0A+=20=20(let*=20((ref-re=20= (mapconcat=20#'regexp-quote=20perm=20"\\|"))=0A+=20=20=20=20=20=20=20=20=20= (opt-re=20(regexp-opt=20perm=20nil=20t))=0A+=20=20=20=20=20=20=20=20=20= (ref=20(regexp-opt-test--match-all=20perm=20ref-re))=0A+=20=20=20=20=20=20= =20=20=20(opt=20(regexp-opt-test--match-all=20perm=20opt-re)))=0A+=20=20=20= =20(equal=20opt=20ref)))=0A+=0A+(defun=20regexp-opt-test--explain-perm=20= (perm)=0A+=20=20(let*=20((ref-re=20(mapconcat=20#'regexp-quote=20perm=20= "\\|"))=0A+=20=20=20=20=20=20=20=20=20(opt-re=20(regexp-opt=20perm=20nil=20= t))=0A+=20=20=20=20=20=20=20=20=20(ref=20(regexp-opt-test--match-all=20= perm=20ref-re))=0A+=20=20=20=20=20=20=20=20=20(opt=20= (regexp-opt-test--match-all=20perm=20opt-re)))=0A+=20=20=20=20(concat=20= "\n"=0A+=20=20=20=20=20=20=20=20=20=20=20=20(format=20"Na=C3=AFve=20= regexp:=20=20=20=20=20%s\n"=20ref-re)=0A+=20=20=20=20=20=20=20=20=20=20=20= =20(format=20"Optimised=20regexp:=20%s\n"=20opt-re)=0A+=20=20=20=20=20=20= =20=20=20=20=20=20(format=20"Got:=20=20=20=20=20=20%s\n"=20opt)=0A+=20=20= =20=20=20=20=20=20=20=20=20=20(format=20"Expected:=20%s\n"=20ref))))=0A+=0A= +(put=20'regexp-opt-test--check-perm=20'ert-explainer=20= 'regexp-opt-test--explain-perm)=0A+=0A+(ert-deftest=20= regexp-opt-keep-order=20()=0A+=20=20"Check=20that=20KEEP-ORDER=20works."=0A= +=20=20(dolist=20(perm=20(regexp-opt-test--permutations=20'("abc"=20= "bca"=20"cab")))=0A+=20=20=20=20(should=20(regexp-opt-test--check-perm=20= perm)))=0A+=20=20(dolist=20(perm=20(regexp-opt-test--permutations=20= '("abc"=20"ab"=20"bca"=20"bc")))=0A+=20=20=20=20(should=20= (regexp-opt-test--check-perm=20perm)))=0A+=20=20(dolist=20(perm=20= (regexp-opt-test--permutations=20'("abxy"=20"cdxy")))=0A+=20=20=20=20= (should=20(regexp-opt-test--check-perm=20perm)))=0A+=20=20(dolist=20= (perm=20(regexp-opt-test--permutations=20'("afgx"=20"bfgx"=20"afgy"=20= "bfgy")))=0A+=20=20=20=20(should=20(regexp-opt-test--check-perm=20= perm)))=0A+=20=20(dolist=20(perm=20(regexp-opt-test--permutations=20= '("a"=20"ab"=20"ac"=20"abc")))=0A+=20=20=20=20(should=20= (regexp-opt-test--check-perm=20perm))))=0A+=0A=20(ert-deftest=20= regexp-opt-charset=20()=0A=20=20=20(should=20(equal=20= (regexp-opt-charset=20'(?a=20?b=20?a))=20"[ab]"))=0A=20=20=20(should=20= (equal=20(regexp-opt-charset=20'(?D=20?d=20?B=20?a=20?b=20?C=20?7=20?a=20= ?c=20?A))=0A--=20=0A2.20.1=20(Apple=20Git-117)=0A=0A= --Apple-Mail=_2FDB2CD4-5E7F-4C22-9EAD-033BA0D7F357--