From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Mattias =?UTF-8?Q?Engdeg=C3=A5rd?= Newsgroups: gmane.emacs.bugs Subject: bug#47677: [PATCH] condition-case success continuation Date: Mon, 12 Apr 2021 21:20:24 +0200 Message-ID: <87F315E7-7F8A-46C5-A71B-F090F067D0B8@acm.org> References: <219007D9-0FD0-4AC2-A8B0-24A0FC277AE8@acm.org> <87lf9nzy48.fsf@gnus.org> Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.17\)) Content-Type: multipart/mixed; boundary="Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="15102"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Lars Ingebrigtsen , 47677@debbugs.gnu.org To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon Apr 12 21:21:13 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lW27U-0003mW-3G for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 12 Apr 2021 21:21:12 +0200 Original-Received: from localhost ([::1]:38130 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lW27T-0003jX-3v for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 12 Apr 2021 15:21:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:53964) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lW27K-0003jM-Jh for bug-gnu-emacs@gnu.org; Mon, 12 Apr 2021 15:21:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:46570) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lW27K-0001Q1-CT for bug-gnu-emacs@gnu.org; Mon, 12 Apr 2021 15:21:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1lW27K-0001g3-5v for bug-gnu-emacs@gnu.org; Mon, 12 Apr 2021 15:21: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: Mon, 12 Apr 2021 19:21:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 47677 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 47677-submit@debbugs.gnu.org id=B47677.16182552326377 (code B ref 47677); Mon, 12 Apr 2021 19:21:02 +0000 Original-Received: (at 47677) by debbugs.gnu.org; 12 Apr 2021 19:20:32 +0000 Original-Received: from localhost ([127.0.0.1]:58110 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lW26q-0001em-Bz for submit@debbugs.gnu.org; Mon, 12 Apr 2021 15:20:32 -0400 Original-Received: from mail150c50.megamailservers.eu ([91.136.10.160]:36648 helo=mail50c50.megamailservers.eu) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lW26o-0001ed-C0 for 47677@debbugs.gnu.org; Mon, 12 Apr 2021 15:20:31 -0400 X-Authenticated-User: mattiase@bredband.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=megamailservers.eu; s=maildub; t=1618255228; bh=wl7fPS2+678TsCooyO0AEHomNCL4nPoSK6YJDCyRZfs=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=XP5n9mkFTIXt4WBhXTCAjaL/rALFg0GmydBBAtYLdEvTlVEQJYuY8uaV2jOno2RZ5 LTNccv5TlXQV0OTNs3bqZvinit302Ha3jVRbngguDVcmy17i1CThDmMl2RwQ0fAZcS OJH0BO9iRqaZ33vGq73tXG2l7fc3DI3+5p4cjpYI= Feedback-ID: mattiase@acm.or Original-Received: from stanniol.lan (c-b952e353.032-75-73746f71.bbcust.telenor.se [83.227.82.185]) (authenticated bits=0) by mail50c50.megamailservers.eu (8.14.9/8.13.1) with ESMTP id 13CJKPIi015306; Mon, 12 Apr 2021 19:20:27 +0000 In-Reply-To: X-Mailer: Apple Mail (2.3445.104.17) X-CTCH-RefID: str=0001.0A742F24.60749D7C.002D, 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=JZTCUnCV c=1 sm=1 tr=0 a=von4qPfY+hyqc0zmWf0tYQ==:117 a=von4qPfY+hyqc0zmWf0tYQ==:17 a=M51BFTxLslgA:10 a=Uv_scK_R3qRFpUfcwGQA:9 a=CjuIK1q_8ugA:10 a=yuwFoldsWfbauk4T1MIA:9 a=B2y7HmGcmWMA:10 a=6f-eSLppCT1XzX82WLoA:9 a=De_Ol2h6w80A:10 a=tclcd6dtLQvEqt9_mmAA:9 X-Origin-Country: SE X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list 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-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:203932 Archived-At: --Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Here is an updated patch that reduces some code duplication in the = compiler and fixes an embarrassing bug, and as a bonus, an experimental = add-on that allows catching throws in condition-case using the handler = syntax ((:catch TAG) BODY...) Unfortunately but unsurprisingly the decision to evaluate the TAG = expressions made everything much messier than anticipated. It does work, = though, and if you would like to redefine `catch` as the macro (defmacro catch (tag &rest body) (let ((var (gensym))) `(condition-case ,var (progn ,@body) ((:catch ,tag) ,var)))) then that will work, too (with minor byte-code inefficiency that could = easily be addressed). Any combination of error, :catch and :success handlers is permitted, = making this a very versatile construct. It may be a good idea to do away with the TAG evaluation since that = flexibility isn't likely to be in high demand. --Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B Content-Disposition: attachment; filename=0001-Add-condition-case-success-handler-bug-47677.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-Add-condition-case-success-handler-bug-47677.patch" Content-Transfer-Encoding: quoted-printable =46rom=20864e56e63b45a05cb7ff274f33a2b4c9ee45746e=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20=3D?UTF-8?q?Mattias=3D20Engdeg=3DC3=3DA5rd?=3D=20= =0ADate:=20Wed,=207=20Apr=202021=2011:31:07=20+0200=0A= Subject:=20[PATCH]=20Add=20condition-case=20success=20handler=20= (bug#47677)=0A=0AAllow=20a=20condition-case=20handler=20on=20the=20form=20= (:success=20BODY)=20to=20be=0Aspecified=20as=20the=20success=20= continuation=20of=20the=20protected=20form,=20with=0Athe=20specified=20= variable=20bound=20to=20its=20result.=0A=0A*=20src/eval.c=20= (Fcondition_case):=20Update=20the=20doc=20string.=0A= (internal_lisp_condition_case):=20Implement=20in=20interpreter.=0A= (syms_of_eval):=20Defsym=20:success.=0A*=20lisp/emacs-lisp/bytecomp.el=20= (byte-compile-condition-case):=0AImplement=20in=20byte-compiler.=0A*=20= lisp/emacs-lisp/cl-macs.el=20(cl--self-tco):=20Allow=20self-TCO=0Afrom=20= success=20handler.=0A*=20doc/lispref/control.texi=20(Handling=20Errors):=20= Update=20manual.=0A*=20etc/NEWS:=20Announce.=0A*=20= test/lisp/emacs-lisp/bytecomp-tests.el=20(bytecomp-tests--test-cases)=0A= (bytecomp-condition-case-success):=0A*=20= test/lisp/emacs-lisp/cl-macs-tests.el=20(cl-macs--labels):=0AAdd=20test=20= cases.=0A---=0A=20doc/lispref/control.texi=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=209=20+-=0A=20etc/NEWS=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=205=20= +=0A=20lisp/emacs-lisp/bytecomp.el=20=20=20=20=20=20=20=20=20=20=20=20|=20= =2063=20+++++++-----=0A=20lisp/emacs-lisp/cl-macs.el=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=20=204=20+-=0A=20src/eval.c=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=2034=20= ++++++-=0A=20test/lisp/emacs-lisp/bytecomp-tests.el=20|=20127=20= +++++++++++++++++++++++++=0A=20test/lisp/emacs-lisp/cl-macs-tests.el=20=20= |=20=20=209=20+-=0A=207=20files=20changed,=20218=20insertions(+),=2033=20= deletions(-)=0A=0Adiff=20--git=20a/doc/lispref/control.texi=20= b/doc/lispref/control.texi=0Aindex=203388102f69..22b665bc93=20100644=0A= ---=20a/doc/lispref/control.texi=0A+++=20b/doc/lispref/control.texi=0A@@=20= -2012,7=20+2012,8=20@@=20Handling=20Errors=0A=20This=20special=20form=20= establishes=20the=20error=20handlers=20@var{handlers}=20around=0A=20the=20= execution=20of=20@var{protected-form}.=20=20If=20@var{protected-form}=20= executes=0A=20without=20error,=20the=20value=20it=20returns=20becomes=20= the=20value=20of=20the=0A-@code{condition-case}=20form;=20in=20this=20= case,=20the=20@code{condition-case}=20has=0A+@code{condition-case}=20= form=20(in=20the=20absence=20of=20a=20success=20handler;=20see=20below).=0A= +In=20this=20case,=20the=20@code{condition-case}=20has=0A=20no=20effect.=20= =20The=20@code{condition-case}=20form=20makes=20a=20difference=20when=20= an=0A=20error=20occurs=20during=20@var{protected-form}.=0A=20=0A@@=20= -2062,6=20+2063,12=20@@=20Handling=20Errors=0A=20If=20@var{var}=20is=20= @code{nil},=20that=20means=20no=20variable=20is=20bound.=20=20Then=20the=0A= =20error=20symbol=20and=20associated=20data=20are=20not=20available=20to=20= the=20handler.=0A=20=0A+@cindex=20success=20handler=0A+As=20a=20special=20= case,=20one=20of=20the=20@var{handlers}=20can=20be=20a=20list=20of=20the=0A= +form=20@code{(:success=20@var{body}@dots{})},=20where=20@var{body}=20is=20= executed=0A+with=20@var{var}=20(if=20non-@code{nil})=20bound=20to=20the=20= return=20value=20of=0A+@var{protected-form}=20when=20that=20expression=20= terminates=20without=20error.=0A+=0A=20@cindex=20rethrow=20a=20signal=0A=20= Sometimes=20it=20is=20necessary=20to=20re-throw=20a=20signal=20caught=20= by=0A=20@code{condition-case},=20for=20some=20outer-level=20handler=20to=20= catch.=20=20Here's=0Adiff=20--git=20a/etc/NEWS=20b/etc/NEWS=0Aindex=20= 7483a6e5b7..4ce33f06f0=20100644=0A---=20a/etc/NEWS=0A+++=20b/etc/NEWS=0A= @@=20-2922,6=20+2922,11=20@@=20arrays=20nor=20objects.=0A=20The=20= special=20events=20'dbus-event'=20and=20'file-notify'=20are=20now=20= ignored=20in=0A=20'while-no-input'=20when=20added=20to=20this=20= variable.=0A=20=0A++++=0A+**=20'condition-case'=20now=20allows=20for=20a=20= success=20handler.=0A+It=20is=20executed=20whenever=20the=20protected=20= form=20terminates=20without=20error,=0A+with=20the=20specified=20= variable=20bound=20to=20the=20returned=20value.=0A+=0A=20=0C=0A=20*=20= Changes=20in=20Emacs=2028.1=20on=20Non-Free=20Operating=20Systems=0A=20=0A= diff=20--git=20a/lisp/emacs-lisp/bytecomp.el=20= b/lisp/emacs-lisp/bytecomp.el=0Aindex=200babbbb978..4f91f0d5de=20100644=0A= ---=20a/lisp/emacs-lisp/bytecomp.el=0A+++=20= b/lisp/emacs-lisp/bytecomp.el=0A@@=20-4621,10=20+4621,15=20@@=20= byte-compile-unwind-protect=0A=20(defun=20byte-compile-condition-case=20= (form)=0A=20=20=20(let*=20((var=20(nth=201=20form))=0A=20=20=20=20=20=20=20= =20=20=20(body=20(nth=202=20form))=0A+=20=20=20=20=20=20=20=20=20= (handlers=20(nthcdr=203=20form))=0A=20=20=20=20=20=20=20=20=20=20(depth=20= byte-compile-depth)=0A+=20=20=20=20=20=20=20=20=20(success-handler=20= (assq=20:success=20handlers))=0A+=20=20=20=20=20=20=20=20=20= (failure-handlers=20(if=20success-handler=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(remq=20= success-handler=20handlers)=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=20handlers))=0A=20=20=20=20=20= =20=20=20=20=20(clauses=20(mapcar=20(lambda=20(clause)=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= (cons=20(byte-compile-make-tag)=20clause))=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(nthcdr=203=20form)))=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=20failure-handlers))=0A=20=20=20=20=20=20=20=20=20=20(endtag=20= (byte-compile-make-tag)))=0A=20=20=20=20=20= (byte-compile-set-symbol-position=20'condition-case)=0A=20=20=20=20=20= (unless=20(symbolp=20var)=0A@@=20-4650,30=20+4655,40=20@@=20= byte-compile-condition-case=0A=20=0A=20=20=20=20=20(byte-compile-form=20= body)=20;;=20byte-compile--for-effect=0A=20=20=20=20=20(dolist=20(_=20= clauses)=20(byte-compile-out=20'byte-pophandler))=0A-=20=20=20=20= (byte-compile-goto=20'byte-goto=20endtag)=0A=20=0A-=20=20=20=20(while=20= clauses=0A-=20=20=20=20=20=20(let=20((clause=20(pop=20clauses))=0A-=20=20= =20=20=20=20=20=20=20=20=20=20(byte-compile-bound-variables=20= byte-compile-bound-variables)=0A-=20=20=20=20=20=20=20=20=20=20=20=20= (byte-compile--lexical-environment=0A-=20=20=20=20=20=20=20=20=20=20=20=20= =20byte-compile--lexical-environment))=0A-=20=20=20=20=20=20=20=20(setq=20= byte-compile-depth=20(1+=20depth))=0A-=20=20=20=20=20=20=20=20= (byte-compile-out-tag=20(pop=20clause))=0A-=20=20=20=20=20=20=20=20= (dolist=20(_=20clauses)=20(byte-compile-out=20'byte-pophandler))=0A-=20=20= =20=20=20=20=20=20(cond=0A-=20=20=20=20=20=20=20=20=20((null=20var)=20= (byte-compile-discard))=0A-=20=20=20=20=20=20=20=20=20(lexical-binding=0A= -=20=20=20=20=20=20=20=20=20=20(push=20(cons=20var=20(1-=20= byte-compile-depth))=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= byte-compile--lexical-environment))=0A-=20=20=20=20=20=20=20=20=20(t=20= (byte-compile-dynamic-variable-bind=20var)))=0A-=20=20=20=20=20=20=20=20= (byte-compile-body=20(cdr=20clause))=20;;=20byte-compile--for-effect=0A-=20= =20=20=20=20=20=20=20(cond=0A-=20=20=20=20=20=20=20=20=20((null=20var)=20= nil)=0A-=20=20=20=20=20=20=20=20=20(lexical-binding=20= (byte-compile-discard=201=20'preserve-tos))=0A-=20=20=20=20=20=20=20=20=20= (t=20(byte-compile-out=20'byte-unbind=201)))=0A-=20=20=20=20=20=20=20=20= (byte-compile-goto=20'byte-goto=20endtag)))=0A-=0A-=20=20=20=20= (byte-compile-out-tag=20endtag)))=0A+=20=20=20=20(let=20= ((compile-handler-body=0A+=20=20=20=20=20=20=20=20=20=20=20(lambda=20= (body)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20(let=20= ((byte-compile-bound-variables=20byte-compile-bound-variables)=0A+=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (byte-compile--lexical-environment=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20byte-compile--lexical-environment))=0A+=20=20=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=20=20((null=20var)=20(byte-compile-discard))=0A+=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20(lexical-binding=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(push=20(cons=20var=20(1-=20= byte-compile-depth))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20byte-compile--lexical-environment))=0A+=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(t=20(byte-compile-dynamic-variable-bind=20= var)))=0A+=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (byte-compile-body=20body)=20;;=20byte-compile--for-effect=0A+=0A+=20=20=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=20=20((null=20var))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20(lexical-binding=20(byte-compile-discard=201=20'preserve-tos))=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(t=20(byte-compile-out=20= 'byte-unbind=201)))))))=0A+=0A+=20=20=20=20=20=20(when=20success-handler=0A= +=20=20=20=20=20=20=20=20(funcall=20compile-handler-body=20(cdr=20= success-handler)))=0A+=0A+=20=20=20=20=20=20(byte-compile-goto=20= 'byte-goto=20endtag)=0A+=0A+=20=20=20=20=20=20(while=20clauses=0A+=20=20=20= =20=20=20=20=20(let=20((clause=20(pop=20clauses)))=0A+=20=20=20=20=20=20=20= =20=20=20(setq=20byte-compile-depth=20(1+=20depth))=0A+=20=20=20=20=20=20= =20=20=20=20(byte-compile-out-tag=20(pop=20clause))=0A+=20=20=20=20=20=20= =20=20=20=20(dolist=20(_=20clauses)=20(byte-compile-out=20= 'byte-pophandler))=0A+=20=20=20=20=20=20=20=20=20=20(funcall=20= compile-handler-body=20(cdr=20clause))=0A+=20=20=20=20=20=20=20=20=20=20= (byte-compile-goto=20'byte-goto=20endtag)))=0A+=0A+=20=20=20=20=20=20= (byte-compile-out-tag=20endtag))))=0A=20=0A=20(defun=20= byte-compile-save-excursion=20(form)=0A=20=20=20(if=20(and=20(eq=20= 'set-buffer=20(car-safe=20(car-safe=20(cdr=20form))))=0Adiff=20--git=20= a/lisp/emacs-lisp/cl-macs.el=20b/lisp/emacs-lisp/cl-macs.el=0Aindex=20= 68211ec410..b7e5be95bc=20100644=0A---=20a/lisp/emacs-lisp/cl-macs.el=0A= +++=20b/lisp/emacs-lisp/cl-macs.el=0A@@=20-2144,7=20+2144,9=20@@=20= cl--self-tco=0A=20=20=20=20=20=20=20=20=20=20=20=20=20((and=20= `(condition-case=20,err-var=20,bodyform=20.=20,handlers)=0A=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20(guard=20(not=20(eq=20err-var=20= var))))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20`(condition-case=20= ,err-var=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(progn=20= (setq=20,retvar=20,bodyform)=20nil)=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20,(if=20(assq=20:success=20handlers)=0A+=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20bodyform=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20`(progn=20(setq=20= ,retvar=20,bodyform)=20nil))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20.=20,(mapcar=20(lambda=20(h)=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(cons=20(car=20= h)=20(funcall=20opt-exps=20(cdr=20h))))=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=20handlers)))=0Adiff=20= --git=20a/src/eval.c=20b/src/eval.c=0Aindex=20ddaa8edd81..fd93f5b9e1=20= 100644=0A---=20a/src/eval.c=0A+++=20b/src/eval.c=0A@@=20-1301,7=20= +1301,7=20@@=20DEFUN=20("condition-case",=20Fcondition_case,=20= Scondition_case,=202,=20UNEVALLED,=200,=0A=20=20=20=20=20=20=20=20doc:=20= /*=20Regain=20control=20when=20an=20error=20is=20signaled.=0A=20Executes=20= BODYFORM=20and=20returns=20its=20value=20if=20no=20error=20happens.=0A=20= Each=20element=20of=20HANDLERS=20looks=20like=20(CONDITION-NAME=20= BODY...)=0A-where=20the=20BODY=20is=20made=20of=20Lisp=20expressions.=0A= +or=20(:success=20BODY...),=20where=20the=20BODY=20is=20made=20of=20Lisp=20= expressions.=0A=20=0A=20A=20handler=20is=20applicable=20to=20an=20error=20= if=20CONDITION-NAME=20is=20one=20of=20the=0A=20error's=20condition=20= names.=20=20Handlers=20may=20also=20apply=20when=20non-error=0A@@=20= -1323,6=20+1323,10=20@@=20DEFUN=20("condition-case",=20Fcondition_case,=20= Scondition_case,=202,=20UNEVALLED,=200,=0A=20Then=20the=20value=20of=20= the=20last=20BODY=20form=20is=20returned=20from=20the=20`condition-case'=0A= =20expression.=0A=20=0A+The=20special=20handler=20(:success=20BODY...)=20= is=20invoked=20if=20BODYFORM=20terminated=0A+without=20signalling=20an=20= error.=20=20BODY=20is=20then=20evaluated=20with=20VAR=20bound=20to=0A= +the=20value=20returned=20by=20BODYFORM.=0A+=0A=20See=20also=20the=20= function=20`signal'=20for=20more=20info.=0A=20usage:=20(condition-case=20= VAR=20BODYFORM=20&rest=20HANDLERS)=20=20*/)=0A=20=20=20(Lisp_Object=20= args)=0A@@=20-1346,16=20+1350,21=20@@=20internal_lisp_condition_case=20= (Lisp_Object=20var,=20Lisp_Object=20bodyform,=0A=20=0A=20=20=20= CHECK_SYMBOL=20(var);=0A=20=0A+=20=20Lisp_Object=20success_handler=20=3D=20= Qnil;=0A+=0A=20=20=20for=20(Lisp_Object=20tail=20=3D=20handlers;=20CONSP=20= (tail);=20tail=20=3D=20XCDR=20(tail))=0A=20=20=20=20=20{=0A=20=20=20=20=20= =20=20Lisp_Object=20tem=20=3D=20XCAR=20(tail);=0A-=20=20=20=20=20=20= clausenb++;=0A=20=20=20=20=20=20=20if=20(!=20(NILP=20(tem)=0A=20=09=20=20= =20=20=20||=20(CONSP=20(tem)=0A=20=09=09=20&&=20(SYMBOLP=20(XCAR=20= (tem))=0A=20=09=09=20=20=20=20=20||=20CONSP=20(XCAR=20(tem))))))=0A=20=09= error=20("Invalid=20condition=20handler:=20%s",=0A=20=09=20=20=20=20=20=20= =20SDATA=20(Fprin1_to_string=20(tem,=20Qt)));=0A+=20=20=20=20=20=20if=20= (EQ=20(XCAR=20(tem),=20QCsuccess))=0A+=09success_handler=20=3D=20XCDR=20= (tem);=0A+=20=20=20=20=20=20else=0A+=09clausenb++;=0A=20=20=20=20=20}=0A=20= =0A=20=20=20/*=20The=20first=20clause=20is=20the=20one=20that=20should=20= be=20checked=20first,=20so=20it=0A@@=20-1369,7=20+1378,8=20@@=20= internal_lisp_condition_case=20(Lisp_Object=20var,=20Lisp_Object=20= bodyform,=0A=20=20=20Lisp_Object=20volatile=20*clauses=20=3D=20alloca=20= (clausenb=20*=20sizeof=20*clauses);=0A=20=20=20clauses=20+=3D=20= clausenb;=0A=20=20=20for=20(Lisp_Object=20tail=20=3D=20handlers;=20CONSP=20= (tail);=20tail=20=3D=20XCDR=20(tail))=0A-=20=20=20=20*--clauses=20=3D=20= XCAR=20(tail);=0A+=20=20=20=20if=20(!EQ=20(XCAR=20(XCAR=20(tail)),=20= QCsuccess))=0A+=20=20=20=20=20=20*--clauses=20=3D=20XCAR=20(tail);=0A=20=20= =20for=20(ptrdiff_t=20i=20=3D=200;=20i=20<=20clausenb;=20i++)=0A=20=20=20= =20=20{=0A=20=20=20=20=20=20=20Lisp_Object=20clause=20=3D=20clauses[i];=0A= @@=20-1409,6=20+1419,23=20@@=20internal_lisp_condition_case=20= (Lisp_Object=20var,=20Lisp_Object=20bodyform,=0A=20=0A=20=20=20= Lisp_Object=20result=20=3D=20eval_sub=20(bodyform);=0A=20=20=20= handlerlist=20=3D=20oldhandlerlist;=0A+=20=20if=20(!NILP=20= (success_handler))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20if=20(NILP=20= (var))=0A+=09return=20Fprogn=20(success_handler);=0A+=0A+=20=20=20=20=20=20= Lisp_Object=20handler_var=20=3D=20var;=0A+=20=20=20=20=20=20if=20(!NILP=20= (Vinternal_interpreter_environment))=0A+=09{=0A+=09=20=20result=20=3D=20= Fcons=20(Fcons=20(var,=20result),=0A+=09=09=20=20=20=20=20=20=20= Vinternal_interpreter_environment);=0A+=09=20=20handler_var=20=3D=20= Qinternal_interpreter_environment;=0A+=09}=0A+=0A+=20=20=20=20=20=20= ptrdiff_t=20count=20=3D=20SPECPDL_INDEX=20();=0A+=20=20=20=20=20=20= specbind=20(handler_var,=20result);=0A+=20=20=20=20=20=20return=20= unbind_to=20(count,=20Fprogn=20(success_handler));=0A+=20=20=20=20}=0A=20= =20=20return=20result;=0A=20}=0A=20=0A@@=20-4381,6=20+4408,7=20@@=20= syms_of_eval=20(void)=0A=20=20=20defsubr=20(&Sthrow);=0A=20=20=20defsubr=20= (&Sunwind_protect);=0A=20=20=20defsubr=20(&Scondition_case);=0A+=20=20= DEFSYM=20(QCsuccess,=20":success");=0A=20=20=20defsubr=20(&Ssignal);=0A=20= =20=20defsubr=20(&Scommandp);=0A=20=20=20defsubr=20(&Sautoload);=0Adiff=20= --git=20a/test/lisp/emacs-lisp/bytecomp-tests.el=20= b/test/lisp/emacs-lisp/bytecomp-tests.el=0Aindex=20= a11832d805..c9ab3ec1f1=20100644=0A---=20= a/test/lisp/emacs-lisp/bytecomp-tests.el=0A+++=20= b/test/lisp/emacs-lisp/bytecomp-tests.el=0A@@=20-444,6=20+444,65=20@@=20= bytecomp-tests--test-cases=0A=20=20=20=20=20=20=20=20(arith-error=20= (prog1=20(lambda=20(y)=20(+=20y=20x))=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20(setq=20x=2010))))=0A=20=20=20=20=20=20= 4)=0A+=0A+=20=20=20=20;;=20No=20error,=20no=20success=20handler.=0A+=20=20= =20=20(condition-case=20x=0A+=20=20=20=20=20=20=20=20(list=2042)=0A+=20=20= =20=20=20=20(error=20(cons=20'bad=20x)))=0A+=20=20=20=20;;=20Error,=20no=20= success=20handler.=0A+=20=20=20=20(condition-case=20x=0A+=20=20=20=20=20=20= =20=20(/=201=200)=0A+=20=20=20=20=20=20(error=20(cons=20'bad=20x)))=0A+=20= =20=20=20;;=20No=20error,=20success=20handler.=0A+=20=20=20=20= (condition-case=20x=0A+=20=20=20=20=20=20=20=20(list=2042)=0A+=20=20=20=20= =20=20(error=20(cons=20'bad=20x))=0A+=20=20=20=20=20=20(:success=20(cons=20= 'good=20x)))=0A+=20=20=20=20;;=20Error,=20success=20handler.=0A+=20=20=20= =20(condition-case=20x=0A+=20=20=20=20=20=20=20=20(/=201=200)=0A+=20=20=20= =20=20=20(error=20(cons=20'bad=20x))=0A+=20=20=20=20=20=20(:success=20= (cons=20'good=20x)))=0A+=20=20=20=20;;=20Verify=20that=20the=20success=20= code=20is=20not=20subject=20to=20the=20error=20handlers.=0A+=20=20=20=20= (condition-case=20x=0A+=20=20=20=20=20=20=20=20(list=2042)=0A+=20=20=20=20= =20=20(error=20(cons=20'bad=20x))=0A+=20=20=20=20=20=20(:success=20(/=20= (car=20x)=200)))=0A+=20=20=20=20;;=20Check=20variable=20scoping=20on=20= success.=0A+=20=20=20=20(let=20((x=202))=0A+=20=20=20=20=20=20= (condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20(list=20x)=0A+=20=20= =20=20=20=20=20=20(error=20(list=20'bad=20x))=0A+=20=20=20=20=20=20=20=20= (:success=20(list=20'good=20x))))=0A+=20=20=20=20;;=20Check=20variable=20= scoping=20on=20failure.=0A+=20=20=20=20(let=20((x=202))=0A+=20=20=20=20=20= =20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20(/=201=200)=0A+=20= =20=20=20=20=20=20=20(error=20(list=20'bad=20x))=0A+=20=20=20=20=20=20=20= =20(:success=20(list=20'good=20x))))=0A+=20=20=20=20;;=20Check=20capture=20= of=20mutated=20result=20variable.=0A+=20=20=20=20(funcall=0A+=20=20=20=20= =20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=203=0A+=20=20=20=20=20= =20=20(:success=20(prog1=20(lambda=20(y)=20(+=20y=20x))=0A+=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20(setq=20x=2010))))=0A+=20=20=20= =20=204)=0A+=20=20=20=20;;=20Check=20for-effect=20context,=20on=20error.=0A= +=20=20=20=20(let=20((f=20(lambda=20(x)=0A+=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(condition-case=20nil=0A+=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(/=201=200)=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(error=20'bad)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20(:success=20'good))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(1+=20x))))=0A+=20=20=20=20=20=20(funcall=20f=203))=0A+=20=20=20=20;;=20= Check=20for-effect=20context,=20on=20success.=0A+=20=20=20=20(let=20((f=20= (lambda=20(x)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (condition-case=20nil=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20nil=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (error=20'bad)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (:success=20'good))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(1+=20= x))))=0A+=20=20=20=20=20=20(funcall=20f=203))=0A=20=20=20=20=20)=0A=20=20= =20"List=20of=20expressions=20for=20cross-testing=20interpreted=20and=20= compiled=20code.")=0A=20=0A@@=20-1185,6=20+1244,74=20@@=20= bytecomp-string-vs-docstring=0A=20=20=20(let=20((lexical-binding=20t))=0A= =20=20=20=20=20(should=20(equal=20(funcall=20(byte-compile=20'(lambda=20= (x)=20"foo"))=20'dummy)=20"foo"))))=0A=20=0A+(ert-deftest=20= bytecomp-condition-case-success=20()=0A+=20=20;;=20No=20error,=20no=20= success=20handler.=0A+=20=20(should=20(equal=20(condition-case=20x=0A+=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(list=2042)=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(error=20(cons=20= 'bad=20x)))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= '(42)))=0A+=20=20;;=20Error,=20no=20success=20handler.=0A+=20=20(should=20= (equal=20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20(/=201=200)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(error=20(cons=20'bad=20x)))=0A+=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20'(bad=20arith-error)))=0A+=20=20;;=20No=20= error,=20success=20handler.=0A+=20=20(should=20(equal=20(condition-case=20= x=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (list=2042)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (error=20(cons=20'bad=20x))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20(:success=20(cons=20'good=20x)))=0A+=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20'(good=2042)))=0A+=20=20;;=20Error,=20success=20= handler.=0A+=20=20(should=20(equal=20(condition-case=20x=0A+=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(/=201=200)=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(error=20(cons=20'bad=20x))=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(:success=20= (cons=20'good=20x)))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= '(bad=20arith-error)))=0A+=20=20;;=20Verify=20that=20the=20success=20= code=20is=20not=20subject=20to=20the=20error=20handlers.=0A+=20=20= (should-error=20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(list=2042)=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(error=20(cons=20'bad=20x))=0A+=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(:success=20(/=20(car=20x)=200)))=0A+=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20:type=20'arith-error)=0A+=20=20= ;;=20Check=20variable=20scoping.=0A+=20=20(let=20((x=202))=0A+=20=20=20=20= (should=20(equal=20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20(list=20x)=0A+=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20(error=20(list=20'bad=20x))=0A+=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(:success=20= (list=20'good=20x)))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20'(good=20(2))))=0A+=20=20=20=20(should=20(equal=20(condition-case=20= x=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (/=201=200)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(error=20(list=20'bad=20x))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(:success=20(list=20'good=20x)))=0A+=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20'(bad=20(arith-error)))))=0A+=20= =20;;=20Check=20capture=20of=20mutated=20result=20variable.=0A+=20=20= (should=20(equal=20(funcall=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20(condition-case=20x=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=203=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20(:success=20(prog1=20(lambda=20(y)=20(+=20y=20x))=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=20x=2010))))=0A+=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=204)=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =2014))=0A+=20=20=20=20;;=20Check=20for-effect=20context,=20on=20error.=0A= +=20=20(should=20(equal=20(let=20((f=20(lambda=20(x)=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= (condition-case=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=20=20=20=20=20=20(/=201=200)=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(error=20'bad)=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(:success=20'good))=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(1+=20= x))))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (funcall=20f=203))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= 4))=0A+=20=20;;=20Check=20for-effect=20context,=20on=20success.=0A+=20=20= (should=20(equal=20(let=20((f=20(lambda=20(x)=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= (condition-case=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=20=20=20=20=20=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=20=20=20=20= (error=20'bad)=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(:success=20'good))=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(1+=20= x))))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (funcall=20f=203))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= 4)))=0A+=0A=20;;=20Local=20Variables:=0A=20;;=20no-byte-compile:=20t=0A=20= ;;=20End:=0Adiff=20--git=20a/test/lisp/emacs-lisp/cl-macs-tests.el=20= b/test/lisp/emacs-lisp/cl-macs-tests.el=0Aindex=205c3e603b92..f4e2e46a01=20= 100644=0A---=20a/test/lisp/emacs-lisp/cl-macs-tests.el=0A+++=20= b/test/lisp/emacs-lisp/cl-macs-tests.el=0A@@=20-630,12=20+630,13=20@@=20= cl-macs--labels=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(and=20xs=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= (progn=20(setq=20n1=20(1+=20n))=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(len2=20(cdr=20xs)=20n1))))))=0A-=20=20=20=20=20=20=20=20=20;;=20= Tail=20call=20in=20error=20handler.=0A+=20=20=20=20=20=20=20=20=20;;=20= Tail=20calls=20in=20error=20and=20success=20handlers.=0A=20=20=20=20=20=20= =20=20=20=20(len3=20(xs=20n)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20(if=20xs=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (condition-case=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(/=201=200)=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(arith-error=20(len3=20(cdr=20xs)=20(1+=20n))))=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (condition-case=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(/=201=20(logand=20n=201))=0A+=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20(arith-error=20(len3=20(cdr=20xs)=20= (1+=20n)))=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(:success=20(len3=20(cdr=20xs)=20(+=20n=20k))))=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20n)))=0A=20=20=20=20=20=20=20(should=20= (equal=20(len=20nil=200)=200))=0A=20=20=20=20=20=20=20(should=20(equal=20= (len2=20nil=200)=200))=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B Content-Disposition: attachment; filename=catch-in-condition-case.diff Content-Type: application/octet-stream; x-unix-mode=0644; name="catch-in-condition-case.diff" Content-Transfer-Encoding: 7bit diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 4f91f0d5de..82e0edd772 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -4636,22 +4636,34 @@ byte-compile-condition-case (byte-compile-warn "`%s' is not a variable-name or nil (in condition-case)" var)) - (dolist (clause (reverse clauses)) - (let ((condition (nth 1 clause))) - (unless (consp condition) (setq condition (list condition))) - (dolist (c condition) - (unless (and c (symbolp c)) - (byte-compile-warn - "`%S' is not a condition name (in condition-case)" c)) - ;; In reality, the `error-conditions' property is only required - ;; for the argument to `signal', not to `condition-case'. - ;;(unless (consp (get c 'error-conditions)) - ;; (byte-compile-warn - ;; "`%s' is not a known condition name (in condition-case)" - ;; c)) - ) - (byte-compile-push-constant condition)) - (byte-compile-goto 'byte-pushconditioncase (car clause))) + (let ((initial-depth byte-compile-depth) + (push-ops nil)) + ;; Push all conditions and tags in left-to-right order first, + ;; since tags need to be evaluated outside the scope of the handlers. + (dolist (clause clauses) + (let ((condition (nth 1 clause))) + (pcase condition + (`(:catch ,tag-expr) + (byte-compile-form tag-expr) + (push (cons 'byte-pushcatch (car clause)) push-ops)) + (`(:catch . ,_) + (error "malformed :catch clause: `%S'" (cdr clause))) + (_ ; error clause + (unless (consp condition) + (setq condition (list condition))) + (dolist (c condition) + (unless (and c (symbolp c)) + (byte-compile-warn + "`%S' is not a condition name (in condition-case)" c))) + (byte-compile-push-constant condition) + (push (cons 'byte-pushconditioncase (car clause)) push-ops))))) + ;; Then emit the handler activations in reverse order so that the + ;; first handler becomes the innermost. + (dolist (op push-ops) + ;; Use the depth at which the jumps will take place in the tag. + (setq byte-compile-depth (1+ initial-depth)) + (byte-compile-goto (car op) (cdr op))) + (cl-assert (equal byte-compile-depth initial-depth))) (byte-compile-form body) ;; byte-compile--for-effect (dolist (_ clauses) (byte-compile-out 'byte-pophandler)) diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index b37cfebab3..1651e47cfe 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el @@ -510,14 +510,18 @@ cconv-convert newprotform) ,@(mapcar (lambda (handler) - `(,(car handler) - ,@(let ((body - (mapcar (lambda (form) - (cconv-convert form newenv extend)) - (cdr handler)))) - (if (not (eq class :captured+mutated)) - body - `((let ((,var (list ,var))) ,@body)))))) + (let ((head (pcase (car handler) + (`(:catch ,tag-exp) + `(:catch ,(cconv-convert tag-exp env extend))) + (h h)))) + `(,head + ,@(let ((body + (mapcar (lambda (form) + (cconv-convert form newenv extend)) + (cdr handler)))) + (if (not (eq class :captured+mutated)) + body + `((let ((,var (list ,var))) ,@body))))))) handlers)))) (`(unwind-protect ,form . ,body) @@ -736,6 +740,10 @@ cconv-analyze-form (`(function . ,_) nil) ; same as quote (`(condition-case ,var ,protected-form . ,handlers) + (dolist (handler handlers) + (pcase handler + (`((:catch ,tag-exp) . ,_) + (cconv-analyze-form tag-exp env)))) (cconv-analyze-form protected-form env) (when (and var (symbolp var) (byte-compile-not-lexical-var-p var)) (byte-compile-warn diff --git a/src/eval.c b/src/eval.c index fd93f5b9e1..8a7676ec7a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1351,6 +1351,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, CHECK_SYMBOL (var); Lisp_Object success_handler = Qnil; + Lisp_Object tags = Qnil; /* Evaluated catch tags in reverse order. */ for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail)) { @@ -1361,10 +1362,21 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, || CONSP (XCAR (tem)))))) error ("Invalid condition handler: %s", SDATA (Fprin1_to_string (tem, Qt))); - if (EQ (XCAR (tem), QCsuccess)) + Lisp_Object head = XCAR (tem); + if (EQ (head, QCsuccess)) success_handler = XCDR (tem); else - clausenb++; + { + if (CONSP (head) && EQ (XCAR (head), QCcatch)) + { + if (NILP (XCDR (head)) || !NILP (XCDR (XCDR (head)))) + error ("Invalid condition handler: %s", + SDATA (Fprin1_to_string (tem, Qt))); + Lisp_Object tag = eval_sub (XCAR (XCDR (head))); + tags = Fcons (tag, tags); + } + clausenb++; + } } /* The first clause is the one that should be checked first, so it @@ -1386,7 +1398,15 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, Lisp_Object condition = CONSP (clause) ? XCAR (clause) : Qnil; if (!CONSP (condition)) condition = list1 (condition); - struct handler *c = push_handler (condition, CONDITION_CASE); + struct handler *c; + if (EQ (XCAR (condition), QCcatch)) + { + Lisp_Object tag = XCAR (tags); + tags = XCDR (tags); + c = push_handler (tag, CATCHER); + } + else + c = push_handler (condition, CONDITION_CASE); if (sys_setjmp (c->jmp)) { Lisp_Object val = handlerlist->val; @@ -4409,6 +4429,7 @@ syms_of_eval (void) defsubr (&Sunwind_protect); defsubr (&Scondition_case); DEFSYM (QCsuccess, ":success"); + DEFSYM (QCcatch, ":catch"); defsubr (&Ssignal); defsubr (&Scommandp); defsubr (&Sautoload); diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index c9ab3ec1f1..af02810f31 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el @@ -503,6 +503,38 @@ bytecomp-tests--test-cases (:success 'good)) (1+ x)))) (funcall f 3)) + + ;; Catching throws. + (let ((g (lambda (f) + (let ((tags (list 'a 'b))) + (condition-case x + (funcall f) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-a x)) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-b x)) + (:success (list 'ok x))))))) + (list (funcall g (lambda () 2)) + (funcall g (lambda () (throw 'a 3))) + (funcall g (lambda () (throw 'b 5))))) + + ;; Catching throws and errors. + (let ((g (lambda (f) + (let ((tags (list 'a 'b))) + (condition-case x + (funcall f) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-a x)) + (arith-error (list 'arith x)) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-b x)) + (error (list 'err x)) + (:success (list 'ok x))))))) + (list (funcall g (lambda () 2)) + (funcall g (lambda () (throw 'a 3))) + (funcall g (lambda () (throw 'b 5))) + (funcall g (lambda () (/ 1 0))) + (funcall g (lambda () (signal 'error nil))))) ) "List of expressions for cross-testing interpreted and compiled code.") @@ -1310,7 +1342,45 @@ bytecomp-condition-case-success (:success 'good)) (1+ x)))) (funcall f 3)) - 4))) + 4)) + + ;; Catching throws. + (should (equal + (let ((g (lambda (f) + (let ((tags (list 'a 'b))) + (condition-case x + (funcall f) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-a x)) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-b x)) + (:success (list 'ok x))))))) + (list (funcall g (lambda () 2)) + (funcall g (lambda () (throw 'a 3))) + (funcall g (lambda () (throw 'b 5))))) + '((ok 2) (catch-a 3) (catch-b 5)))) + + ;; Catching throws and errors. + (should (equal + (let ((g (lambda (f) + (let ((tags (list 'a 'b))) + (condition-case x + (funcall f) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-a x)) + (arith-error (list 'arith x)) + ((:catch (prog1 (car tags) (setq tags (cdr tags)))) + (list 'catch-b x)) + (error (list 'err x)) + (:success (list 'ok x))))))) + (list (funcall g (lambda () 2)) + (funcall g (lambda () (throw 'a 3))) + (funcall g (lambda () (throw 'b 5))) + (funcall g (lambda () (/ 1 0))) + (funcall g (lambda () (signal 'error nil))))) + '((ok 2) (catch-a 3) (catch-b 5) + (arith (arith-error)) (err (error))))) + ) ;; Local Variables: ;; no-byte-compile: t --Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii --Apple-Mail=_51898DD6-0AC4-45AD-8104-17DD900FD77B--