From unknown Sun Jun 15 08:44:13 2025 X-Loop: help-debbugs@gnu.org Subject: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture Resent-From: Yuan Fu Original-Sender: "Debbugs-submit" Resent-CC: dgutov@yandex.ru, bug-gnu-emacs@gnu.org Resent-Date: Wed, 22 Mar 2023 04:50:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 62368 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: 62368@debbugs.gnu.org Cc: dgutov@yandex.ru X-Debbugs-Original-To: Bug Report Emacs X-Debbugs-Original-Xcc: dgutov@yandex.ru Received: via spool by submit@debbugs.gnu.org id=B.167946059429891 (code B ref -1); Wed, 22 Mar 2023 04:50:01 +0000 Received: (at submit) by debbugs.gnu.org; 22 Mar 2023 04:49:54 +0000 Received: from localhost ([127.0.0.1]:33194 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1peqQ6-0007m3-Dv for submit@debbugs.gnu.org; Wed, 22 Mar 2023 00:49:54 -0400 Received: from lists.gnu.org ([209.51.188.17]:39286) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1peqQ5-0007lw-7p for submit@debbugs.gnu.org; Wed, 22 Mar 2023 00:49:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1peqQ4-0005Aj-NM for bug-gnu-emacs@gnu.org; Wed, 22 Mar 2023 00:49:52 -0400 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1peqQ3-0001Di-2j for bug-gnu-emacs@gnu.org; Wed, 22 Mar 2023 00:49:52 -0400 Received: by mail-pl1-x62a.google.com with SMTP id iw3so18234384plb.6 for ; Tue, 21 Mar 2023 21:49:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1679460589; h=to:date:message-id:subject:mime-version:from:from:to:cc:subject :date:message-id:reply-to; bh=ocXgcamwd7J0CklU/TAkU+V4oFdupUANhofKGbeD4vw=; b=dvFb2EuUr79a1Yt/bFRp6JDlD+mVwSlwsA56C+h5KhYQWbUdP2StEVkzKQHiKfuZ6K gBQK6WcFURMGeUKjqVhrsGWG84+64vPV4vlMmZjAbqtgOSKVOzju8zoryd+7L+ypZ5Wp P/+BJFEdL6h1rVEWtparJVMsUWOnh0e4mPv0PD+E2Gz1vMuVGZY0pZPqUAKsK64faZBT Nwu1WKcm4waAMzjMg7AghuprOTD/Kbd/crCWPzRIqzYbwAk3mtVy0R8eDQHU0TTvq/um ds6b5owWeT+lue+j1EQORst70tVJVU7n118OZg010TiESnHolXn+8q2C3vQJ1IKyjmyu v65w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679460589; h=to:date:message-id:subject:mime-version:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=ocXgcamwd7J0CklU/TAkU+V4oFdupUANhofKGbeD4vw=; b=uCGY9cFRHy3B36F5u0XrI7vtr9axn9GHKYdnKsF1ug1uE3kBK9XP/V5ycugxih4gNS s3nZJLQfh+BHpqQQ/qWu3/U4Zy4Ie9jEu5vD+tJ5yNCBB6H4spp1zEAC/cJvT8iihZoI 7BPc6H0T2pqzDS0/W7F4MGUP5b8ogufAKvNFXrTHtCIStQsc2rD7tDInC+PhuleMQNRG 5Yo3uUV3dh/E4Ln+Oyy7+QZSmxYDhZw4WEyMMmbMubssP0V4iQpoHGbb0/9jorSqOWem MUzPUTFkcpZZuse4EsvtpGXcUbW/ptjf5qTqU0akdEPVJCD6yMjTEA2/aWV0k5GjFSIU yKkw== X-Gm-Message-State: AO0yUKXaDHGWg/xxNm84tfPzBs59j/Yx9ch68lUh9/YFOewgaiBXdLED 69FpX/Cma8imMAiVbG2TK95WczUE93o= X-Google-Smtp-Source: AK7set/On5A98uEbgrkuQec/rKS79FhewHawsSerUKXGvPA04H773DX/JaL7QtYwzfyQIG5AW8o1lw== X-Received: by 2002:a05:6a20:4b07:b0:d4:c41c:24e0 with SMTP id fp7-20020a056a204b0700b000d4c41c24e0mr4362427pzb.20.1679460588806; Tue, 21 Mar 2023 21:49:48 -0700 (PDT) Received: from smtpclient.apple (cpe-172-117-161-177.socal.res.rr.com. [172.117.161.177]) by smtp.gmail.com with ESMTPSA id s3-20020aa78d43000000b00625c96db7desm8677870pfe.198.2023.03.21.21.49.47 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Mar 2023 21:49:48 -0700 (PDT) From: Yuan Fu Content-Type: multipart/mixed; boundary="Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.400.51.1.1\)) Message-Id: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> Date: Tue, 21 Mar 2023 21:49:37 -0700 X-Mailer: Apple Mail (2.3731.400.51.1.1) Received-SPF: pass client-ip=2607:f8b0:4864:20::62a; envelope-from=casouri@gmail.com; helo=mail-pl1-x62a.google.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, FREEMAIL_REPLY=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Score: -0.3 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-Debbugs-CC: dgutov@yandex.ru Dmitry, when you have time, could you try your benchmark in bug#60953 with this patch? I made predicates evaluate before we create any nodes, so #equal and #match should be more efficient now, when there are a lot of rejections. In the same time #pred is made slightly worst since they now create a lisp node and discard it. (But this can be fixed with a little more complexity.) Yuan --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2 Content-Disposition: attachment; filename=pred-first.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="pred-first.patch" Content-Transfer-Encoding: quoted-printable =46rom=20312063d389ea4e4f17ab82ab3da093c172e4142d=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=20= 21=20Mar=202023=2016:03:08=20-0700=0ASubject:=20[PATCH=201/3]=20Refactor=20= Ftreesit_query_capture=0A=0ARefactor=20some=20part=20of=20= Ftreesit_query_capture=20out=20into=20separate=0Afunctions,=20to=20pave=20= the=20way=20for=20other=20query-based=20functions.=0A=0A*=20= src/treesit.c=20(treesit_resolve_node):=20New=20function.=0A= (treesit_initialize_query):=20New=20function.=0A= (Ftreesit_query_capture):=20Refactor=20some=20part=20into=20new=20= functions.=0A---=0A=20src/treesit.c=20|=20153=20= ++++++++++++++++++++++++++++++++------------------=0A=201=20file=20= changed,=2097=20insertions(+),=2056=20deletions(-)=0A=0Adiff=20--git=20= a/src/treesit.c=20b/src/treesit.c=0Aindex=205a4fe3e8803..e728d697c9d=20= 100644=0A---=20a/src/treesit.c=0A+++=20b/src/treesit.c=0A@@=20-2631,8=20= +2631,8=20@@=20DEFUN=20("treesit-query-compile",=0A=20=20=20=20=20=20=20= Lisp_Object=20signal_symbol=20=3D=20Qnil;=0A=20=20=20=20=20=20=20= Lisp_Object=20signal_data=20=3D=20Qnil;=0A=20=20=20=20=20=20=20TSQuery=20= *treesit_query=20=3D=20treesit_ensure_query_compiled=20(lisp_query,=0A-=09= =09=09=09=09=09=09=20&signal_symbol,=0A-=09=09=09=09=09=09=09=20= &signal_data);=0A+=09=09=09=09=09=09=09=20=20=20=20=20=20&signal_symbol,=0A= +=09=09=09=09=09=09=09=20=20=20=20=20=20&signal_data);=0A=20=0A=20=20=20=20= =20=20=20if=20(treesit_query=20=3D=3D=20NULL)=0A=20=09xsignal=20= (signal_symbol,=20signal_data);=0A@@=20-2641,6=20+2641,92=20@@=20DEFUN=20= ("treesit-query-compile",=0A=20=20=20=20=20}=0A=20}=0A=20=0A+/*=20= Resolve=20OBJ=20into=20a=20tree-sitter=20node=20Lisp_Object.=20=20OBJ=20= can=20be=20a=0A+=20=20=20node,=20a=20parser,=20or=20a=20language=20= symbol.=20=20Note=20that=20this=20function=20can=0A+=20=20=20signal.=20=20= */=0A+static=20Lisp_Object=20treesit_resolve_node=20(Lisp_Object=20obj)=0A= +{=0A+=20=20if=20(TS_NODEP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= treesit_check_node=20(obj);=20/*=20Check=20if=20up-to-date.=20=20*/=0A+=20= =20=20=20=20=20return=20obj;=0A+=20=20=20=20}=0A+=20=20else=20if=20= (TS_PARSERP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= treesit_check_parser=20(obj);=20/*=20Check=20if=20deleted.=20=20*/=0A+=20= =20=20=20=20=20return=20Ftreesit_parser_root_node=20(obj);=0A+=20=20=20=20= }=0A+=20=20else=20if=20(SYMBOLP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20= =20=20Lisp_Object=20parser=0A+=09=3D=20Ftreesit_parser_create=20(obj,=20= Fcurrent_buffer=20(),=20Qnil);=0A+=20=20=20=20=20=20return=20= Ftreesit_parser_root_node=20(parser);=0A+=20=20=20=20}=0A+=20=20else=0A+=20= =20=20=20xsignal2=20(Qwrong_type_argument,=0A+=09=20=20=20=20=20=20list4=20= (Qor,=20Qtreesit_node_p,=20Qtreesit_parser_p,=20Qsymbolp),=0A+=09=20=20=20= =20=20=20obj);=0A+}=0A+=0A+/*=20Create=20and=20initialize=20QUERY.=20=20= When=20success,=20initialize=20TS_QUERY,=0A+=20=20=20CURSOR,=20and=20= NEED_FREE,=20and=20return=20true;=20if=20failed,=20initialize=0A+=20=20=20= SIGNAL_SYMBOL=20and=20SIGNAL_DATA,=20and=20return=20false.=20=20If=20= NEED_FREE=20is=0A+=20=20=20initialized=20to=20true,=20the=20TS_QUERY=20= and=20CURSOR=20needs=20to=20be=20freed=0A+=20=20=20after=20use;=20= otherwise=20they=20shouldn't=20be=20freed=20by=20hand.=0A+=0A+=20=20=20= Basically=20this=20function=20looks=20at=20QUERY=20and=20check=20its=20= type,=20if=20QUERY=0A+=20=20=20is=20a=20compiled=20query,=20this=20= function=20takes=20out=20its=20query=20and=20cursor;=0A+=20=20=20if=20= QUERY=20is=20a=20string=20or=20a=20cons,=20this=20function=20creates=20a=20= new=20query=0A+=20=20=20and=20cursor=20(so=20they=20need=20to=20be=20= manually=20freed).=0A+=0A+=20=20=20This=20function=20assumes=20QUERY=20= is=20either=20a=20compiled=20query,=20a=20string=20or=0A+=20=20=20a=20= cons,=20the=20caller=20should=20make=20sure=20QUERY=20is=20valid.=0A+=0A= +=20=20=20LANG=20is=20the=20language=20to=20use=20if=20we=20need=20to=20= create=20the=20query=20and=0A+=20=20=20cursor.=20=20*/=0A+static=20bool=0A= +treesit_initialize_query=20(Lisp_Object=20query,=20const=20TSLanguage=20= *lang,=0A+=09=09=09=20=20TSQuery=20**ts_query,=20TSQueryCursor=20= **cursor,=0A+=09=09=09=20=20bool=20*need_free,=20Lisp_Object=20= *signal_symbol,=0A+=09=09=09=20=20Lisp_Object=20*signal_data)=0A+{=0A+=20= =20if=20(TS_COMPILED_QUERY_P=20(query))=0A+=20=20=20=20{=0A+=20=20=20=20=20= =20*ts_query=20=3D=20treesit_ensure_query_compiled=20(query,=20= signal_symbol,=0A+=09=09=09=09=09=09=20signal_data);=0A+=20=20=20=20=20=20= *cursor=20=3D=20XTS_COMPILED_QUERY=20(query)->cursor;=0A+=20=20=20=20=20=20= /*=20We=20don't=20need=20to=20free=20ts_query=20and=20cursor=20because=20= they=0A+=09=20are=20stored=20in=20a=20lisp=20object,=20which=20is=20= tracked=20by=20gc.=20=20*/=0A+=20=20=20=20=20=20*need_free=20=3D=20= false;=0A+=20=20=20=20=20=20return=20(*ts_query=20!=3D=20NULL);=0A+=20=20= =20=20}=0A+=20=20else=0A+=20=20=20=20{=0A+=20=20=20=20=20=20/*=20Since=20= query=20is=20not=20TS_COMPILED_QUERY,=20it=20can=20only=20be=20a=20= string=0A+=09=20or=20a=20cons.=20=20*/=0A+=20=20=20=20=20=20if=20(CONSP=20= (query))=0A+=09query=20=3D=20Ftreesit_query_expand=20(query);=0A+=20=20=20= =20=20=20char=20*query_string=20=3D=20SSDATA=20(query);=0A+=20=20=20=20=20= =20uint32_t=20error_offset;=0A+=20=20=20=20=20=20TSQueryError=20= error_type;=0A+=20=20=20=20=20=20*ts_query=20=3D=20ts_query_new=20(lang,=20= query_string,=20strlen=20(query_string),=0A+=09=09=09=09&error_offset,=20= &error_type);=0A+=20=20=20=20=20=20if=20(*ts_query=20=3D=3D=20NULL)=0A+=09= {=0A+=09=20=20*signal_symbol=20=3D=20Qtreesit_query_error;=0A+=09=20=20= *signal_data=20=3D=20treesit_compose_query_signal_data=20(error_offset,=0A= +=09=09=09=09=09=09=09=20=20=20=20error_type,=20query);=0A+=09=20=20= return=20false;=0A+=09}=0A+=20=20=20=20=20=20else=0A+=09{=0A+=09=20=20= *cursor=20=3D=20ts_query_cursor_new=20();=0A+=09=20=20*need_free=20=3D=20= true;=0A+=09=20=20return=20true;=0A+=09}=0A+=20=20=20=20}=0A+}=0A+=0A=20= DEFUN=20("treesit-query-capture",=0A=20=20=20=20=20=20=20=20= Ftreesit_query_capture,=0A=20=20=20=20=20=20=20=20= Streesit_query_capture,=202,=205,=200,=0A@@=20-2681,27=20+2767,7=20@@=20= DEFUN=20("treesit-query-capture",=0A=20=20=20treesit_initialize=20();=0A=20= =0A=20=20=20/*=20Resolve=20NODE=20into=20an=20actual=20node.=20=20*/=0A-=20= =20Lisp_Object=20lisp_node;=0A-=20=20if=20(TS_NODEP=20(node))=0A-=20=20=20= =20{=0A-=20=20=20=20=20=20treesit_check_node=20(node);=20/*=20Check=20if=20= up-to-date.=20=20*/=0A-=20=20=20=20=20=20lisp_node=20=3D=20node;=0A-=20=20= =20=20}=0A-=20=20else=20if=20(TS_PARSERP=20(node))=0A-=20=20=20=20{=0A-=20= =20=20=20=20=20treesit_check_parser=20(node);=20/*=20Check=20if=20= deleted.=20=20*/=0A-=20=20=20=20=20=20lisp_node=20=3D=20= Ftreesit_parser_root_node=20(node);=0A-=20=20=20=20}=0A-=20=20else=20if=20= (SYMBOLP=20(node))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20= parser=0A-=09=3D=20Ftreesit_parser_create=20(node,=20Fcurrent_buffer=20= (),=20Qnil);=0A-=20=20=20=20=20=20lisp_node=20=3D=20= Ftreesit_parser_root_node=20(parser);=0A-=20=20=20=20}=0A-=20=20else=0A-=20= =20=20=20xsignal2=20(Qwrong_type_argument,=0A-=09=20=20=20=20=20=20list4=20= (Qor,=20Qtreesit_node_p,=20Qtreesit_parser_p,=20Qsymbolp),=0A-=09=20=20=20= =20=20=20node);=0A+=20=20Lisp_Object=20lisp_node=20=3D=20= treesit_resolve_node=20(node);=0A=20=0A=20=20=20/*=20Extract=20C=20= values=20from=20Lisp=20objects.=20=20*/=0A=20=20=20TSNode=20treesit_node=0A= @@=20-2725,40=20+2791,15=20@@=20DEFUN=20("treesit-query-capture",=0A=20=20= =20TSQuery=20*treesit_query;=0A=20=20=20TSQueryCursor=20*cursor;=0A=20=20= =20bool=20needs_to_free_query_and_cursor;=0A-=20=20if=20= (TS_COMPILED_QUERY_P=20(query))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20= Lisp_Object=20signal_symbol=20=3D=20Qnil;=0A-=20=20=20=20=20=20= Lisp_Object=20signal_data=20=3D=20Qnil;=0A-=20=20=20=20=20=20= treesit_query=20=3D=20treesit_ensure_query_compiled=20(query,=20= &signal_symbol,=0A-=09=09=09=09=09=09=20=20=20=20=20&signal_data);=0A-=20= =20=20=20=20=20cursor=20=3D=20XTS_COMPILED_QUERY=20(query)->cursor;=0A-=20= =20=20=20=20=20/*=20We=20don't=20need=20to=20free=20ts_query=20and=20= cursor=20because=20they=0A-=09=20are=20stored=20in=20a=20lisp=20object,=20= which=20is=20tracked=20by=20gc.=20=20*/=0A-=20=20=20=20=20=20= needs_to_free_query_and_cursor=20=3D=20false;=0A-=20=20=20=20=20=20if=20= (treesit_query=20=3D=3D=20NULL)=0A-=09xsignal=20(signal_symbol,=20= signal_data);=0A-=20=20=20=20}=0A-=20=20else=0A-=20=20=20=20{=0A-=20=20=20= =20=20=20/*=20Since=20query=20is=20not=20TS_COMPILED_QUERY,=20it=20can=20= only=20be=20a=20string=0A-=09=20or=20a=20cons.=20=20*/=0A-=20=20=20=20=20= =20if=20(CONSP=20(query))=0A-=09query=20=3D=20Ftreesit_query_expand=20= (query);=0A-=20=20=20=20=20=20char=20*query_string=20=3D=20SSDATA=20= (query);=0A-=20=20=20=20=20=20uint32_t=20error_offset;=0A-=20=20=20=20=20= =20TSQueryError=20error_type;=0A-=20=20=20=20=20=20treesit_query=20=3D=20= ts_query_new=20(lang,=20query_string,=20strlen=20(query_string),=0A-=09=09= =09=09=20=20=20=20&error_offset,=20&error_type);=0A-=20=20=20=20=20=20if=20= (treesit_query=20=3D=3D=20NULL)=0A-=09xsignal=20(Qtreesit_query_error,=0A= -=09=09=20treesit_compose_query_signal_data=20(error_offset,=0A-=09=09=09= =09=09=09=20=20=20=20error_type,=20query));=0A-=20=20=20=20=20=20cursor=20= =3D=20ts_query_cursor_new=20();=0A-=20=20=20=20=20=20= needs_to_free_query_and_cursor=20=3D=20true;=0A-=20=20=20=20}=0A+=20=20= Lisp_Object=20signal_symbol;=0A+=20=20Lisp_Object=20signal_data;=0A+=20=20= if=20(!treesit_initialize_query=20(query,=20lang,=20&treesit_query,=20= &cursor,=0A+=09=09=09=09=20&needs_to_free_query_and_cursor,=0A+=09=09=09=09= =20&signal_symbol,=20&signal_data))=0A+=20=20=20=20xsignal=20= (signal_symbol,=20signal_data);=0A=20=0A-=20=20/*=20WARN:=20After=20this=20= point,=20free=20treesit_query=20and=20cursor=20before=20every=0A-=20=20=20= =20=20signal=20and=20return.=20=20*/=0A+=20=20/*=20WARN:=20After=20this=20= point,=20free=20TREESIT_QUERY=20and=20CURSOR=20before=20every=0A+=20=20=20= =20=20signal=20and=20return=20if=20NEEDS_TO_FREE_QUERY_AND_CURSOR=20is=20= true.=20=20*/=0A=20=0A=20=20=20/*=20Set=20query=20range.=20=20*/=0A=20=20= =20if=20(!NILP=20(beg)=20&&=20!NILP=20(end))=0A--=20=0A2.33.1=0A=0A=0A= =46rom=20b166cb228cfe23ede54718d4b5ab6d1753d8337e=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=20= 21=20Mar=202023=2016:13:23=20-0700=0ASubject:=20[PATCH=202/3]=20;=20= Minor=20refactor=20of=20Ftreesit_query_capture=0A=0A*=20src/treesit.c=20= (Ftreesit_query_capture):=20Move=20around=20some=20variable=0A= initialization.=0A---=0A=20src/treesit.c=20|=2011=20+++++------=0A=201=20= file=20changed,=205=20insertions(+),=206=20deletions(-)=0A=0Adiff=20= --git=20a/src/treesit.c=20b/src/treesit.c=0Aindex=20= e728d697c9d..cd98ff38293=20100644=0A---=20a/src/treesit.c=0A+++=20= b/src/treesit.c=0A@@=20-2770,12=20+2770,9=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20Lisp_Object=20lisp_node=20=3D=20= treesit_resolve_node=20(node);=0A=20=0A=20=20=20/*=20Extract=20C=20= values=20from=20Lisp=20objects.=20=20*/=0A-=20=20TSNode=20treesit_node=0A= -=20=20=20=20=3D=20XTS_NODE=20(lisp_node)->node;=0A-=20=20Lisp_Object=20= lisp_parser=0A-=20=20=20=20=3D=20XTS_NODE=20(lisp_node)->parser;=0A-=20=20= ptrdiff_t=20visible_beg=0A-=20=20=20=20=3D=20XTS_PARSER=20(XTS_NODE=20= (lisp_node)->parser)->visible_beg;=0A+=20=20TSNode=20treesit_node=20=3D=20= XTS_NODE=20(lisp_node)->node;=0A+=20=20Lisp_Object=20lisp_parser=20=3D=20= XTS_NODE=20(lisp_node)->parser;=0A+=0A=20=20=20const=20TSLanguage=20= *lang=0A=20=20=20=20=20=3D=20ts_parser_language=20(XTS_PARSER=20= (lisp_parser)->parser);=0A=20=0A@@=20-2804,6=20+2801,8=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20/*=20Set=20query=20range.=20=20*/=0A= =20=20=20if=20(!NILP=20(beg)=20&&=20!NILP=20(end))=0A=20=20=20=20=20{=0A= +=20=20=20=20=20=20ptrdiff_t=20visible_beg=0A+=09=3D=20XTS_PARSER=20= (XTS_NODE=20(lisp_node)->parser)->visible_beg;=0A=20=20=20=20=20=20=20= ptrdiff_t=20beg_byte=20=3D=20CHAR_TO_BYTE=20(XFIXNUM=20(beg));=0A=20=20=20= =20=20=20=20ptrdiff_t=20end_byte=20=3D=20CHAR_TO_BYTE=20(XFIXNUM=20= (end));=0A=20=20=20=20=20=20=20/*=20We=20never=20let=20tree-sitter=20run=20= on=20buffers=20too=20large,=20so=20these=0A--=20=0A2.33.1=0A=0A=0A=46rom=20= 5c6c111a92c1da0a81b97a42a0b84fe8d9f03524=20Mon=20Sep=2017=2000:00:00=20= 2001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=2021=20Mar=20= 2023=2021:10:59=20-0700=0ASubject:=20[PATCH=203/3]=20Evaluate=20= tree-sitter=20predicate=20functions=20before=20create=0A=20node=0A=0ABy=20= evaluating=20predicates=20before=20creating=20nodes,=20we=20can=20= eliminate=20some=0Awasteful=20consing=20when=20there=20are=20many=20= rejections=20(bug#60953).=20=20The=20one=0Adown=20side=20is=20that=20= #pred=20predicate=20now=20creates=20superfluous=20nodes:=20it=0Acreates=20= a=20node=20to=20feed=20to=20the=20function,=20but=20then=20discard=20it.=20= =20We=20can=0Aimprove=20it=20later=20if=20it=20proves=20problematic.=0A=0A= *=20src/treesit.c:=0A(capture_range):=20Remove.=0A(predicate_context):=20= New=20struct.=0A(treesit_predicates_for_pattern):=20Capture=20names=20= are=0Anot=20symbols=20anymore,=20but=20rather=20index=20numbers.=0A= (treesit_capture_id_to_name):=20New=20subroutine=20function=20that=20= converts=0Aan=20index=20number=20to=20the=20capture=20name.=20=20This=20= is=20only=20used=20by=20error=0Areporting.=0A= (treesit_predicate_capture_name_to_node):=20Remove.=0A= (treesit_capture_id_to_node):=20New=20function.=0A= (treesit_predicate_capture_name_to_text):=20Remove.=0A= (treesit_capture_id_to_text):=20New=20function.=0A= (treesit_predicate_equal)=0A(treesit_predicate_match)=0A= (treesit_predicate_pred)=0A(treesit_eval_predicates):=20Change=20to=20= the=20new=20index-based=20format.=20=20Also=0Anow=20we=20return=20the=20= signal=20data=20rather=20than=20signaling=20directly.=0A= (Ftreesit_query_capture):=20Now=20we=20evaluate=20predicates=20before=20= creating=0Anodes.=20=20We=20also=20set=20the=20current=20buffer=20to=20= that=20of=20the=20node=20we=20are=0Aworking=20on,=20so=20that=20the=20= predicate=20functions=20don't=20need=20to=20switch=0Abuffers=20= back-and-forth.=20=20Also,=20handle=20signals=20gracefully=20so=20we=20= don't=0Aleak=20memory.=0A---=0A=20src/treesit.c=20|=20337=20= +++++++++++++++++++++++++++++++-------------------=0A=201=20file=20= changed,=20208=20insertions(+),=20129=20deletions(-)=0A=0Adiff=20--git=20= a/src/treesit.c=20b/src/treesit.c=0Aindex=20cd98ff38293..c751223fc19=20= 100644=0A---=20a/src/treesit.c=0A+++=20b/src/treesit.c=0A@@=20-2349,23=20= +2349,38=20@@=20DEFUN=20("treesit-query-expand",=0A=20=20=20return=20= Fmapconcat=20(Qtreesit_pattern_expand,=20query,=20Vtreesit_str_space);=0A= =20}=0A=20=0A-/*=20This=20struct=20is=20used=20for=20passing=20captures=20= to=20be=20check=20against=0A-=20=20=20predicates.=20=20Captures=20we=20= check=20for=20are=20the=20ones=20in=20START=20before=0A-=20=20=20END.=20=20= For=20example,=20if=20START=20and=20END=20are=0A+/*=20This=20struct=20is=20= used=20passing=20context=20for=20evaluating=20predicates.=0A+=20=20=20= QUERY=20and=20MATCH=20are=20self-explanatory,=20ROOT_NODE=20is=20the=20= node=20we=20are=0A+=20=20=20querying.=0A=20=0A-=20=20=20START=20=20=20=20= =20=20=20END=0A+=20=20=20START=20and=20END=20points=20to=20the=20list=20= of=20captured=20nodes=20we=20are=20returning=0A+=20=20=20from=20= Ftreesit_query_capture.=20=20They=20mark=20the=20nodes=20we=20captured=20= in=0A+=20=20=20this=20match.=20=20Because=20we=20evaluate=20predicates=20= before=20adding=20captured=0A+=20=20=20nodes=20to=20the=20result=20list,=20= right=20now=20START=20simply=20equal=20to=20END.=0A+=0A+=20=20=20But=20= if=20we=20later=20decide=20we=20want=20to=20optimize=20for=20#pred=20= predicate,=0A+=20=20=20these=20two=20pointer=20will=20be=20useful.=0A+=0A= +=20=20=20An=20example:=0A+=0A+=20=20=20=20START=20=20=20=20=20=20=20=20=20= =20END=0A=20=20=20=20=20v=20=20=20=20=20=20=20=20=20=20=20=20=20=20v=0A-=20= =20=20(1=20.=20(2=20.=20(3=20.=20(4=20.=20(5=20.=20(6=20.=20nil))))))=0A= +=20=20=20(1=20.=20(2=20.=20(3=20.=20(4=20.=20(5=20.=20(6=20.=20= nil))))))=20->=20complete=20result=20list=0A=20=0A-=20=20=20We=20only=20= look=20at=20captures=201=202=203.=20=20*/=0A-struct=20capture_range=0A+=20= =20=201=202=203=20are=20the=20nodes=20captured=20by=20the=20current=20= match.=20=20*/=0A+struct=20predicate_context=0A=20{=0A+=20=20TSQuery=20= *query;=0A+=20=20TSQueryMatch=20*match;=0A+=20=20Lisp_Object=20= root_node;=0A=20=20=20Lisp_Object=20start;=0A=20=20=20Lisp_Object=20end;=0A= =20};=0A=20=0A=20/*=20Collect=20predicates=20for=20this=20match=20and=20= return=20them=20in=20a=20list.=20=20Each=0A-=20=20=20predicate=20is=20a=20= list=20of=20strings=20and=20symbols.=20=20*/=0A+=20=20=20predicate=20is=20= a=20list=20of=20strings=20and=20numbers.=20=20A=20number=20represents=0A= +=20=20=20the=20id=20of=20a=20capture=20name,=20the=20same=20thing=20as=20= the=20index=20attribute=20of=0A+=20=20=20a=20TSQueryCapture.=20=20*/=0A=20= static=20Lisp_Object=0A=20treesit_predicates_for_pattern=20(TSQuery=20= *query,=20uint32_t=20pattern_index)=0A=20{=0A@@=20-2381,12=20+2396,7=20= @@=20treesit_predicates_for_pattern=20(TSQuery=20*query,=20uint32_t=20= pattern_index)=0A=20=09{=0A=20=09case=20TSQueryPredicateStepTypeCapture:=0A= =20=09=20=20{=0A-=09=20=20=20=20uint32_t=20str_len;=0A-=09=20=20=20=20= const=20char=20*str=20=3D=20ts_query_capture_name_for_id=20(query,=0A-=09= =09=09=09=09=09=09=20=20=20=20step.value_id,=0A-=09=09=09=09=09=09=09=20=20= =20=20&str_len);=0A-=09=20=20=20=20predicate=20=3D=20Fcons=20= (intern_c_string_1=20(str,=20str_len),=0A-=09=09=09=20=20=20=20=20=20=20= predicate);=0A+=09=20=20=20=20predicate=20=3D=20Fcons=20(make_fixnum=20= (step.value_id),=20predicate);=0A=20=09=20=20=20=20break;=0A=20=09=20=20= }=0A=20=09case=20TSQueryPredicateStepTypeString:=0A@@=20-2407,118=20= +2417,159=20@@=20treesit_predicates_for_pattern=20(TSQuery=20*query,=20= uint32_t=20pattern_index)=0A=20=20=20return=20Fnreverse=20(result);=0A=20= }=0A=20=0A-/*=20Translate=20a=20capture=20NAME=20(symbol)=20to=20a=20= node.=0A-=20=20=20Signals=20treesit-query-error=20if=20such=20node=20is=20= not=20captured.=20=20*/=0A=20static=20Lisp_Object=0A= -treesit_predicate_capture_name_to_node=20(Lisp_Object=20name,=0A-=09=09=09= =09=09struct=20capture_range=20captures)=0A+treesit_capture_id_to_name=20= (TSQuery=20*query,=20ptrdiff_t=20id)=0A=20{=0A-=20=20Lisp_Object=20node=20= =3D=20Qnil;=0A-=20=20for=20(Lisp_Object=20tail=20=3D=20captures.start;=20= !EQ=20(tail,=20captures.end);=0A-=20=20=20=20=20=20=20tail=20=3D=20XCDR=20= (tail))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20if=20(EQ=20(XCAR=20(XCAR=20= (tail)),=20name))=0A-=09{=0A-=09=20=20node=20=3D=20XCDR=20(XCAR=20= (tail));=0A-=09=20=20break;=0A-=09}=0A-=20=20=20=20}=0A-=0A-=20=20if=20= (NILP=20(node))=0A-=20=20=20=20xsignal3=20(Qtreesit_query_error,=0A-=09=20= =20=20=20=20=20build_string=20("Cannot=20find=20captured=20node"),=0A-=09= =20=20=20=20=20=20name,=20build_string=20("A=20predicate=20can=20only=20= refer"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20= to=20captured=20nodes=20in=20the=20"=0A-=09=09=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20"same=20pattern"));=0A-=20=20return=20node;=0A= +=20=20uint32_t=20len;=0A+=20=20const=20char*=20name_str=20=3D=20= ts_query_capture_name_for_id=20(query,=20(uint32_t)=20id,=0A+=09=09=09=09= =09=09=20=20=20=20=20=20=20&len);=0A+=20=20return=20make_string=20= (name_str,=20(ptrdiff_t)=20len);=0A=20}=0A=20=0A-/*=20Translate=20a=20= capture=20NAME=20(symbol)=20to=20the=20text=20of=20the=20captured=20= node.=0A-=20=20=20Signals=20treesit-query-error=20if=20such=20node=20is=20= not=20captured.=20=20*/=0A-static=20Lisp_Object=0A= -treesit_predicate_capture_name_to_text=20(Lisp_Object=20name,=0A-=09=09=09= =09=09struct=20capture_range=20captures)=0A+/*=20Translate=20a=20capture=20= id=20(fixnum)=20into=20the=20captured=20TSNode=20and=20set=20to=0A+=20=20= =20NODE.=20=20If=20we=20can't=20find=20the=20captured=20node,=20set=20= SIGNAL_DATA=20and=0A+=20=20=20return=20false,=20otherwise=20return=20= true.=20=20*/=0A+static=20bool=0A+treesit_capture_id_to_node=20(TSNode=20= *node,=20Lisp_Object=20id,=0A+=09=09=09=20=20=20=20struct=20= predicate_context=20*context,=0A+=09=09=09=20=20=20=20Lisp_Object=20= *signal_data)=0A=20{=0A-=20=20Lisp_Object=20node=20=3D=20= treesit_predicate_capture_name_to_node=20(name,=20captures);=0A+=20=20= const=20TSQueryCapture=20*captures=20=3D=20context->match->captures;=0A+=20= =20for=20(int=20idx=20=3D=200;=20idx=20<=20= context->match->capture_count;=20idx++)=0A+=20=20=20=20{=0A+=20=20=20=20=20= =20if=20(captures[idx].index=20=3D=3D=20XFIXNUM=20(id))=0A+=09{=0A+=09=20= =20*node=20=3D=20captures->node;=0A+=09=20=20return=20true;=0A+=09}=0A+=20= =20=20=20}=0A+=20=20Lisp_Object=20name=20=3D=20= treesit_capture_id_to_name=20(context->query,=20XFIXNUM=20(id));=0A+=20=20= *signal_data=20=3D=20list3=20(build_string=20("Cannot=20find=20captured=20= node"),=0A+=09=09=09name,=20build_string=20("A=20predicate=20can=20only=20= refer"=0A+=09=09=09=09=09=20=20=20=20"=20to=20captured=20nodes=20in=20= the=20"=0A+=09=09=09=09=09=20=20=20=20"same=20pattern"));=0A+=20=20= return=20false;=0A+}=0A=20=0A-=20=20struct=20buffer=20*old_buffer=20=3D=20= current_buffer;=0A-=20=20set_buffer_internal=20(XBUFFER=20(XTS_PARSER=20= (XTS_NODE=20(node)->parser)->buffer));=0A-=20=20Lisp_Object=20text=20=3D=20= Fbuffer_substring=20(Ftreesit_node_start=20(node),=0A-=09=09=09=09=09= Ftreesit_node_end=20(node));=0A-=20=20set_buffer_internal=20= (old_buffer);=0A-=20=20return=20text;=0A+/*=20Translate=20a=20capture=20= id=20(fixnum)=20into=20the=20text=20of=20the=20captured=20node=0A+=20=20=20= in=20the=20current=20buffer,=20and=20populate=20TEXT=20with=20it.=20=20= (Assumes=20current=0A+=20=20=20buffer=20is=20the=20buffer=20in=20which=20= the=20captured=20node=20and=20ROOT_NODE=20is).=0A+=20=20=20ROOT_NODE=20= is=20the=20root=20node=20of=20the=20query.=20=20If=20we=20can't=20find=20= the=0A+=20=20=20captured=20node,=20set=20SIGNAL_DATA=20and=20return=20= false,=20otherwise=20return=0A+=20=20=20true.=20=20*/=0A+static=20bool=0A= +treesit_capture_id_to_text=20(Lisp_Object=20*text,=20Lisp_Object=20id,=0A= +=09=09=09=20=20=20=20struct=20predicate_context=20*context,=0A+=09=09=09= =20=20=20=20Lisp_Object=20*signal_data)=0A+{=0A+=20=20TSNode=20node;=0A+=20= =20if=20(!treesit_capture_id_to_node=20(&node,=20id,=20context,=20= signal_data))=0A+=20=20=20=20return=20false;=0A+=0A+=20=20Lisp_Object=20= parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A+=20=20= ptrdiff_t=20begin_v=20=3D=20XTS_PARSER=20(parser)->visible_beg;=0A+=0A+=20= =20ptrdiff_t=20start_byte=20=3D=20(ptrdiff_t)=20ts_node_start_byte=20= (node)=20+=20begin_v;=0A+=20=20ptrdiff_t=20end_byte=20=3D=20(ptrdiff_t)=20= ts_node_end_byte=20(node)=20+=20begin_v;=0A+=0A+=20=20ptrdiff_t=20start=20= =3D=20BYTE_TO_CHAR=20(start_byte);=0A+=20=20ptrdiff_t=20end=20=3D=20= BYTE_TO_CHAR=20(end_byte);=0A+=0A+=20=20*text=20=3D=20= make_buffer_string_both=20(start,=20start_byte,=0A+=09=09=09=09=20=20=20= end,=20end_byte,=20false);=0A+=20=20return=20true;=0A=20}=0A=20=0A=20/*=20= Handles=20predicate=20(#equal=20A=20B).=20=20Return=20true=20if=20A=20= equals=20B;=20return=0A-=20=20=20false=20otherwise.=20=20A=20and=20B=20= can=20be=20either=20string,=20or=20a=20capture=20name.=0A-=20=20=20The=20= capture=20name=20evaluates=20to=20the=20text=20its=20captured=20node=20= spans=20in=0A-=20=20=20the=20buffer.=20=20*/=0A+=20=20=20false=20= otherwise.=20=20A=20and=20B=20can=20be=20a=20either=20string=20or=20a=20= capture=20id.=0A+=20=20=20The=20capture=20id=20evaluates=20to=20the=20= text=20spanned=20by=20the=20captured=20node=0A+=20=20=20in=20the=20= buffer.=20=20Assume=20current=20buffer=20is=20the=20buffer=20of=20the=20= captured=0A+=20=20=20node=20and=20ROOT_NODE.=20=20If=20something=20went=20= wrong,=20set=20signal_data,=0A+=20=20=20otherwise=20set=20it=20to=20= Qnil.=20=20IOW,=20caller=20should=20check=20the=20nullness=20of=0A+=20=20= =20signal_data=20for=20errors.=20=20*/=0A=20static=20bool=0A= -treesit_predicate_equal=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A+treesit_predicate_equal=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A= =20{=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20!=3D=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`equal'=20requires=20"=0A-=09=09=20=20=20=20=20=20=20=20=20= =20=20=20"two=20arguments=20but=20only=20given"),=0A-=09=20=20=20=20=20=20= Flength=20(args));=0A-=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= *signal_data=20=3D=20list2=20(build_string=20("Predicate=20`equal'=20= requires=20"=0A+=09=09=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"two=20arguments=20but=20was=20given"),=0A+=09= =09=09=20=20=20=20Flength=20(args));=0A+=20=20=20=20=20=20return=20= false;=0A+=20=20=20=20}=0A=20=20=20Lisp_Object=20arg1=20=3D=20XCAR=20= (args);=0A=20=20=20Lisp_Object=20arg2=20=3D=20XCAR=20(XCDR=20(args));=0A= -=20=20Lisp_Object=20text1=20=3D=20(STRINGP=20(arg1)=0A-=09=09=20=20=20=20= =20=20=20?=20arg1=0A-=09=09=20=20=20=20=20=20=20:=20= treesit_predicate_capture_name_to_text=20(arg1,=0A-=09=09=09=09=09=09=09=09= =20captures));=0A-=20=20Lisp_Object=20text2=20=3D=20(STRINGP=20(arg2)=0A= -=09=09=20=20=20=20=20=20=20?=20arg2=0A-=09=09=20=20=20=20=20=20=20:=20= treesit_predicate_capture_name_to_text=20(arg2,=0A-=09=09=09=09=09=09=09=09= =20captures));=0A+=20=20Lisp_Object=20text1=20=3D=20arg1;=0A+=20=20= Lisp_Object=20text2=20=3D=20arg2;=0A+=20=20if=20(FIXNUMP=20(arg1))=0A+=20= =20=20=20{=0A+=20=20=20=20=20=20if=20(!treesit_capture_id_to_text=20= (&text1,=20arg1,=20context,=20signal_data))=0A+=09return=20false;=0A=20=0A= +=20=20=20=20}=0A+=20=20if=20(FIXNUMP=20(arg2))=0A+=20=20=20=20{=0A+=20=20= =20=20=20=20if=20(!treesit_capture_id_to_text=20(&text2,=20arg2,=20= context,=20signal_data))=0A+=09return=20false;=0A+=20=20=20=20}=0A=20=20=20= return=20!NILP=20(Fstring_equal=20(text1,=20text2));=0A=20}=0A=20=0A=20= /*=20Handles=20predicate=20(#match=20"regexp"=20@node).=20=20Return=20= true=20if=20"regexp"=0A-=20=20=20matches=20the=20text=20spanned=20by=20= @node;=20return=20false=20otherwise.=20=20Matching=0A-=20=20=20is=20= case-sensitive.=20=20*/=0A+=20=20=20matches=20the=20text=20spanned=20by=20= @node;=20return=20false=20otherwise.=0A+=20=20=20Matching=20is=20= case-sensitive.=20=20Assume=20current=20buffer=20is=20the=20buffer=20of=0A= +=20=20=20the=20captured=20node=20and=20ROOT_NODE.=20=20If=20something=20= went=20wrong,=20set=0A+=20=20=20signal_data,=20otherwise=20set=20it=20to=20= Qnil.=20=20IOW,=20caller=20should=20check=0A+=20=20=20the=20nullness=20= of=20signal_data=20for=20errors.=20=20*/=0A=20static=20bool=0A= -treesit_predicate_match=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A+treesit_predicate_match=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A= =20{=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20!=3D=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`match'=20requires=20two=20"=0A-=09=09=20=20=20=20=20=20=20= =20=20=20=20=20"arguments=20but=20only=20given"),=0A-=09=20=20=20=20=20=20= Flength=20(args));=0A+=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20= =3D=20list2=20(build_string=20("Predicate=20`match'=20requires=20two=20"=0A= +=09=09=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"arguments=20but=20only=20given"),=0A+=09=09=09=20=20=20=20= Flength=20(args));=0A+=20=20=20=20=20=20return=20false;=0A+=20=20=20=20}=0A= =20=0A=20=20=20Lisp_Object=20regexp=20=3D=20XCAR=20(args);=0A-=20=20= Lisp_Object=20capture_name=20=3D=20XCAR=20(XCDR=20(args));=0A+=20=20= Lisp_Object=20capture_id=20=3D=20XCAR=20(XCDR=20(args));=0A=20=0A=20=20=20= /*=20It's=20probably=20common=20to=20get=20the=20argument=20order=20= backwards.=20=20Catch=0A=20=20=20=20=20=20this=20mistake=20early=20and=20= show=20helpful=20explanation,=20because=20Emacs=0A=20=20=20=20=20=20= loves=20you.=20=20(We=20put=20the=20regexp=20first=20because=20that's=20= what=0A=20=20=20=20=20=20string-match=20does.)=20=20*/=0A=20=20=20if=20= (!STRINGP=20(regexp))=0A-=20=20=20=20xsignal1=20(Qtreesit_query_error,=0A= -=09=20=20=20=20=20=20build_string=20("The=20first=20argument=20to=20= `match'=20should=20"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20"be=20= a=20regexp=20string,=20not=20a=20capture=20name"));=0A-=20=20if=20= (!SYMBOLP=20(capture_name))=0A-=20=20=20=20xsignal1=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20("The=20= second=20argument=20to=20`match'=20should=20"=0A-=09=09=20=20=20=20=20=20= =20=20=20=20=20=20"be=20a=20capture=20name,=20not=20a=20string"));=0A+=20= =20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20build_string=20= ("The=20first=20argument=20to=20`match'=20should=20"=0A+=09=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"be=20= a=20regexp=20string,=20not=20a=20capture=20name");=0A+=20=20=20=20=20=20= return=20false;=0A+=20=20=20=20}=0A+=20=20if=20(!FIXNUMP=20(capture_id))=0A= +=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20build_string=20= ("The=20second=20argument=20to=20`match'=20should=20"=0A+=09=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"be=20= a=20capture=20name,=20not=20a=20string");=0A+=20=20=20=20=20=20return=20= false;=0A+=20=20=20=20}=0A=20=0A-=20=20Lisp_Object=20node=20=3D=20= treesit_predicate_capture_name_to_node=20(capture_name,=0A-=09=09=09=09=09= =09=09=20=20=20=20=20captures);=0A+=20=20TSNode=20treesit_node;=0A+=20=20= if=20(!treesit_capture_id_to_node=20(&treesit_node,=20capture_id,=20= context,=0A+=09=09=09=09=20=20=20signal_data))=0A+=20=20=20=20return=20= false;=0A=20=0A-=20=20struct=20buffer=20*old_buffer=20=3D=20= current_buffer;=0A-=20=20struct=20buffer=20*buffer=20=3D=20XBUFFER=20= (XTS_PARSER=20(XTS_NODE=20(node)->parser)->buffer);=0A-=20=20= set_buffer_internal=20(buffer);=0A-=0A-=20=20TSNode=20treesit_node=20=3D=20= XTS_NODE=20(node)->node;=0A-=20=20ptrdiff_t=20visible_beg=20=3D=20= XTS_PARSER=20(XTS_NODE=20(node)->parser)->visible_beg;=0A+=20=20= Lisp_Object=20parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A= +=20=20ptrdiff_t=20visible_beg=20=3D=20XTS_PARSER=20= (parser)->visible_beg;=0A=20=20=20uint32_t=20start_byte_offset=20=3D=20= ts_node_start_byte=20(treesit_node);=0A=20=20=20uint32_t=20= end_byte_offset=20=3D=20ts_node_end_byte=20(treesit_node);=0A-=20=20= ptrdiff_t=20start_byte=20=3D=20visible_beg=20+=20start_byte_offset;=0A-=20= =20ptrdiff_t=20end_byte=20=3D=20visible_beg=20+=20end_byte_offset;=0A+=20= =20ptrdiff_t=20start_byte=20=3D=20visible_beg=20+=20(ptrdiff_t)=20= start_byte_offset;=0A+=20=20ptrdiff_t=20end_byte=20=3D=20visible_beg=20+=20= (ptrdiff_t)=20end_byte_offset;=0A=20=20=20ptrdiff_t=20start_pos=20=3D=20= BYTE_TO_CHAR=20(start_byte);=0A=20=20=20ptrdiff_t=20end_pos=20=3D=20= BYTE_TO_CHAR=20(end_byte);=0A+=0A=20=20=20ptrdiff_t=20old_begv=20=3D=20= BEGV;=0A=20=20=20ptrdiff_t=20old_begv_byte=20=3D=20BEGV_BYTE;=0A=20=20=20= ptrdiff_t=20old_zv=20=3D=20ZV;=0A@@=20-2537,63=20+2588,78=20@@=20= treesit_predicate_match=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A=20=20=20ZV=20=3D=20old_zv;=0A=20=20=20ZV_BYTE=20=3D=20= old_zv_byte;=0A=20=0A-=20=20set_buffer_internal=20(old_buffer);=0A-=0A=20= =20=20return=20(val=20>=200);=0A=20}=0A=20=0A=20/*=20Handles=20predicate=20= (#pred=20FN=20ARG...).=20=20Return=20true=20if=20FN=20returns=0A=20=20=20= =20non-nil;=20return=20false=20otherwise.=20=20The=20arity=20of=20FN=20= must=20match=20the=0A-=20=20=20number=20of=20ARGs=20=20*/=0A+=20=20=20= number=20of=20ARGs.=20=20If=20something=20went=20wrong,=20set=20= signal_data,=0A+=20=20=20otherwise=20set=20it=20to=20Qnil.=20=20IOW,=20= caller=20should=20check=20the=20nullness=20of=0A+=20=20=20signal_data=20= for=20errors.=20=20*/=0A=20static=20bool=0A-treesit_predicate_pred=20= (Lisp_Object=20args,=20struct=20capture_range=20captures)=0A= +treesit_predicate_pred=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09Lisp_Object=20*signal_data)=0A=20= {=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20<=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`pred'=20requires=20"=0A-=09=09=20=20=20=20=20=20=20=20=20=20= =20=20"at=20least=20two=20arguments,=20"=0A-=09=09=20=20=20=20=20=20=20=20= =20=20=20=20"but=20was=20only=20given"),=0A-=09=20=20=20=20=20=20Flength=20= (args));=0A-=0A+=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20= list2=20(build_string=20("Predicate=20`pred'=20requires=20"=0A+=09=09=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= "at=20least=20two=20arguments,=20"=0A+=09=09=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"but=20was=20only=20= given"),=0A+=09=09=09=20=20=20=20Flength=20(args));=0A+=20=20=20=20=20=20= return=20false;=0A+=20=20=20=20}=0A=20=20=20Lisp_Object=20fn=20=3D=20= Fintern=20(XCAR=20(args),=20Qnil);=0A=20=20=20Lisp_Object=20nodes=20=3D=20= Qnil;=0A=20=20=20Lisp_Object=20tail=20=3D=20XCDR=20(args);=0A+=20=20= Lisp_Object=20parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A=20= =20=20FOR_EACH_TAIL=20(tail)=0A-=20=20=20=20nodes=20=3D=20Fcons=20= (treesit_predicate_capture_name_to_node=20(XCAR=20(tail),=0A-=09=09=09=09= =09=09=09=20=20=20captures),=0A-=09=09=20=20=20nodes);=0A+=20=20{=0A+=20=20= =20=20TSNode=20ts_node;=0A+=20=20=20=20if=20(!treesit_capture_id_to_node=20= (&ts_node,=20XCAR=20(tail),=20context,=0A+=09=09=09=09=20=20=20=20=20= signal_data))=0A+=20=20=20=20=20=20return=20false;=0A+=20=20=20=20= Lisp_Object=20lisp_node=20=3D=20make_treesit_node=20(parser,=20ts_node);=0A= +=20=20=20=20nodes=20=3D=20Fcons=20(lisp_node,=20nodes);=0A+=20=20}=0A=20= =20=20nodes=20=3D=20Fnreverse=20(nodes);=0A=20=0A=20=20=20return=20!NILP=20= (CALLN=20(Fapply,=20fn,=20nodes));=0A=20}=0A=20=0A=20/*=20If=20all=20= predicates=20in=20PREDICATES=20passes,=20return=20true;=20otherwise=0A-=20= =20=20return=20false.=20=20*/=0A+=20=20=20return=20false.=20=20If=20= something=20went=20wrong,=20set=20signal_data,=20otherwise=0A+=20=20=20= set=20it=20to=20Qnil.=20=20IOW,=20caller=20should=20check=20the=20= nullness=20of=0A+=20=20=20signal_data=20for=20errors.=20=20*/=0A=20= static=20bool=0A-treesit_eval_predicates=20(struct=20capture_range=20= captures,=20Lisp_Object=20predicates)=0A+treesit_eval_predicates=20= (Lisp_Object=20predicates,=0A+=09=09=09=20struct=20predicate_context=20= *context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A=20{=0A=20=20=20= bool=20pass=20=3D=20true;=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20= /*=20Evaluate=20each=20predicates.=20=20*/=0A=20=20=20for=20(Lisp_Object=20= tail=20=3D=20predicates;=0A-=20=20=20=20=20=20=20!NILP=20(tail);=20tail=20= =3D=20XCDR=20(tail))=0A+=20=20=20=20=20=20=20!NILP=20(tail)=20&&=20pass;=20= tail=20=3D=20XCDR=20(tail))=0A=20=20=20=20=20{=0A=20=20=20=20=20=20=20= Lisp_Object=20predicate=20=3D=20XCAR=20(tail);=0A=20=20=20=20=20=20=20= Lisp_Object=20fn=20=3D=20XCAR=20(predicate);=0A=20=20=20=20=20=20=20= Lisp_Object=20args=20=3D=20XCDR=20(predicate);=0A=20=20=20=20=20=20=20if=20= (!NILP=20(Fstring_equal=20(fn,=20Vtreesit_str_equal)))=0A-=09pass=20&=3D=20= treesit_predicate_equal=20(args,=20captures);=0A+=09pass=20&=3D=20= treesit_predicate_equal=20(args,=20context,=20signal_data);=0A=20=20=20=20= =20=20=20else=20if=20(!NILP=20(Fstring_equal=20(fn,=20= Vtreesit_str_match)))=0A-=09pass=20&=3D=20treesit_predicate_match=20= (args,=20captures);=0A+=09pass=20&=3D=20treesit_predicate_match=20(args,=20= context,=20signal_data);=0A=20=20=20=20=20=20=20else=20if=20(!NILP=20= (Fstring_equal=20(fn,=20Vtreesit_str_pred)))=0A-=09pass=20&=3D=20= treesit_predicate_pred=20(args,=20captures);=0A+=09pass=20&=3D=20= treesit_predicate_pred=20(args,=20context,=20signal_data);=0A=20=20=20=20= =20=20=20else=0A-=09xsignal3=20(Qtreesit_query_error,=0A-=09=09=20=20= build_string=20("Invalid=20predicate"),=0A-=09=09=20=20fn,=20= build_string=20("Currently=20Emacs=20only=20supports"=0A-=09=09=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20equal,=20match,=20= and=20pred"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20"=20predicate"));=0A+=09{=0A+=09=20=20*signal_data=20=3D=20list3=20= (build_string=20("Invalid=20predicate"),=0A+=09=09=09=09fn,=20= build_string=20("Currently=20Emacs=20only=20supports"=0A+=09=09=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"=20equal,=20match,=20and=20pred"=0A+=09=09=09=09=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20predicate"));=0A+=09=20=20= break;=0A+=09}=0A=20=20=20=20=20}=0A-=20=20/*=20If=20all=20predicates=20= passed,=20add=20captures=20to=20result=20list.=20=20*/=0A=20=20=20return=20= pass;=0A=20}=0A=20=0A@@=20-2831,10=20+2897,34=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20Lisp_Object=20result=20=3D=20Qnil;=0A= =20=20=20Lisp_Object=20prev_result=20=3D=20result;=0A=20=20=20= Lisp_Object=20predicates_table=20=3D=20make_vector=20(patterns_count,=20= Qt);=0A+=0A+=20=20struct=20buffer=20*old_buf=20=3D=20current_buffer;=0A+=20= =20set_buffer_internal=20(buf);=0A+=0A+=20=20signal_data=20=3D=20Qnil;=0A= =20=20=20while=20(ts_query_cursor_next_match=20(cursor,=20&match))=0A=20=20= =20=20=20{=0A=20=20=20=20=20=20=20/*=20Record=20the=20checkpoint=20that=20= we=20may=20roll=20back=20to.=20=20*/=0A=20=20=20=20=20=20=20prev_result=20= =3D=20result;=0A+=0A+=20=20=20=20=20=20/*=20Get=20predicates.=20=20*/=0A= +=20=20=20=20=20=20Lisp_Object=20predicates=20=3D=20AREF=20= (predicates_table,=20match.pattern_index);=0A+=20=20=20=20=20=20if=20(EQ=20= (predicates,=20Qt))=0A+=09{=0A+=09=20=20predicates=20=3D=20= treesit_predicates_for_pattern=20(treesit_query,=0A+=09=09=09=09=09=09=20= =20=20=20=20=20=20match.pattern_index);=0A+=09=20=20ASET=20= (predicates_table,=20match.pattern_index,=20predicates);=0A+=09}=0A+=0A+=20= =20=20=20=20=20/*=20Evaluate=20predicates.=20=20*/=0A+=20=20=20=20=20=20= struct=20predicate_context=20context=0A+=09=3D=20{=20treesit_query,=20= &match,=20lisp_node,=20result,=20prev_result=20};=0A+=20=20=20=20=20=20= bool=20pass=20=3D=20treesit_eval_predicates=20(predicates,=20&context,=20= &signal_data);=0A+=20=20=20=20=20=20if=20(!NILP=20(signal_data))=0A+=09= break;=0A+=20=20=20=20=20=20else=20if=20(!pass)=0A+=09continue;=0A+=0A=20= =20=20=20=20=20=20/*=20Get=20captured=20nodes.=20=20*/=0A=20=20=20=20=20=20= =20const=20TSQueryCapture=20*captures=20=3D=20match.captures;=0A=20=20=20= =20=20=20=20for=20(int=20idx=20=3D=200;=20idx=20<=20match.capture_count;=20= idx++)=0A@@=20-2858,26=20+2948,15=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=0A=20=09=20=20result=20=3D=20Fcons=20= (cap,=20result);=0A=20=09}=0A-=20=20=20=20=20=20/*=20Get=20predicates.=20= =20*/=0A-=20=20=20=20=20=20Lisp_Object=20predicates=20=3D=20AREF=20= (predicates_table,=20match.pattern_index);=0A-=20=20=20=20=20=20if=20(EQ=20= (predicates,=20Qt))=0A-=09{=0A-=09=20=20predicates=20=3D=20= treesit_predicates_for_pattern=20(treesit_query,=0A-=09=09=09=09=09=09=20= =20=20=20=20=20=20match.pattern_index);=0A-=09=20=20ASET=20= (predicates_table,=20match.pattern_index,=20predicates);=0A-=09}=0A-=0A-=20= =20=20=20=20=20/*=20captures_lisp=20=3D=20Fnreverse=20(captures_lisp);=20= */=0A-=20=20=20=20=20=20struct=20capture_range=20captures_range=20=3D=20= {=20result,=20prev_result=20};=0A-=20=20=20=20=20=20if=20= (!treesit_eval_predicates=20(captures_range,=20predicates))=0A-=09/*=20= Predicates=20didn't=20pass,=20roll=20back.=20=20*/=0A-=09result=20=3D=20= prev_result;=0A=20=20=20=20=20}=0A+=20=20set_buffer_internal=20= (old_buf);=0A=20=20=20if=20(needs_to_free_query_and_cursor)=0A=20=20=20=20= =20{=0A=20=20=20=20=20=20=20ts_query_delete=20(treesit_query);=0A=20=20=20= =20=20=20=20ts_query_cursor_delete=20(cursor);=0A=20=20=20=20=20}=0A+=20=20= if=20(!NILP=20(signal_data))=0A+=20=20=20=20xsignal=20= (Qtreesit_query_error,=20signal_data);=0A=20=20=20return=20Fnreverse=20= (result);=0A=20}=0A=20=0A--=20=0A2.33.1=0A=0A= --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2-- From unknown Sun Jun 15 08:44:13 2025 X-Loop: help-debbugs@gnu.org Subject: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture Resent-From: Dmitry Gutov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 23 Mar 2023 00:43:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 62368 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Yuan Fu , 62368@debbugs.gnu.org Received: via spool by 62368-submit@debbugs.gnu.org id=B62368.16795321526735 (code B ref 62368); Thu, 23 Mar 2023 00:43:02 +0000 Received: (at 62368) by debbugs.gnu.org; 23 Mar 2023 00:42:32 +0000 Received: from localhost ([127.0.0.1]:36909 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pf92G-0001kY-7a for submit@debbugs.gnu.org; Wed, 22 Mar 2023 20:42:32 -0400 Received: from mail-ed1-f49.google.com ([209.85.208.49]:44826) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pf92E-0001kJ-0U for 62368@debbugs.gnu.org; Wed, 22 Mar 2023 20:42:30 -0400 Received: by mail-ed1-f49.google.com with SMTP id eh3so80048684edb.11 for <62368@debbugs.gnu.org>; Wed, 22 Mar 2023 17:42:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1679532143; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :sender:from:to:cc:subject:date:message-id:reply-to; bh=MrZAqbFSjXdXi1qSTk8u5uJJ/4fd+c/ptbJWYU7b10c=; b=HHzmDpsLDyQBFeniRaCrq9W9X5sBbriTrIdvKcv3JaMx50b3ksNimIBD+LRrEjHBxN AoopoOE5/kgLSOW+0G/zIXSBbtMEFqBsL5zd/iE0GeeWP1qEnUF5ryW1PPvuF/lw2YwC SY6lDX2AWrNfd6MSmWaiZNrZRYw1jQIGhqhevKeXQnHMemZn6W3UvD/Gbf2jTdc2Xbej +0lpnVftv+qJ2kk5ZcPE6OsMyULl7udBjRRQr/MVJbgw1zisuVJVWh2EsRkV+q/BwJvW 8llizEFlT13CyjbgH310l+iBtBWe4jBcR3leUaVaAGtZRWmZMMB4/lkLyu5nOgkzFXwy FB+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679532143; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :sender:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=MrZAqbFSjXdXi1qSTk8u5uJJ/4fd+c/ptbJWYU7b10c=; b=FM6nHmxKYie02GxhC+L6454cx/3WZz/2zlm1qLYUADzaxVW0Dud4V1RHT6gtNTbai7 LQpneD3VUzEq5fNDGuOFWrsqmuf1iUIpZmunRuKDqEq2pqZ18QyIsLFP1S5cry1QhELU LFsnOu6cIvnc/fdhH4F5EVC9yAwY2cRiBo02gGwoRqg7jNSPLq0nRTSOk0DPzN6Sh4uA swEYrfefFs63E+Fsv7DKUCHdd/ThSHCYXZEiM2zyPTcuM3ZyzNWVDoS/Pa6zyBS3kDVZ hx0OZlEzEGPHXIDNfVbSOkJxEsyA0vQRiElFo87CbVuxNb8GQqPxt39a4ATkQQlw4vrx WzNw== X-Gm-Message-State: AO0yUKUiHsEPbEkeVEGVIrc/9XPriN+GvCDaYn+581p9aOT2s6wXsC8F tee1lFTGXGgePNd2hwWt8Fs= X-Google-Smtp-Source: AK7set+mxsYSmAjDcaJO7+4Vkhj3u+Gtq18VpMKRtgrVuutWSZyO/w30vtaXqczoBZPxq0y/9PsWcg== X-Received: by 2002:a17:906:2009:b0:92e:d6e6:f3ad with SMTP id 9-20020a170906200900b0092ed6e6f3admr9328299ejo.6.1679532143059; Wed, 22 Mar 2023 17:42:23 -0700 (PDT) Received: from [192.168.0.2] ([85.132.229.92]) by smtp.googlemail.com with ESMTPSA id jx3-20020a170907760300b00930876176e2sm7936940ejc.29.2023.03.22.17.42.22 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Mar 2023 17:42:22 -0700 (PDT) Message-ID: Date: Thu, 23 Mar 2023 02:42:20 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.8.0 Content-Language: en-US References: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> From: Dmitry Gutov In-Reply-To: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Score: -0.9 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.9 (-) Hi Yuan! On 22/03/2023 06:49, Yuan Fu wrote: > X-Debbugs-CC:dgutov@yandex.ru > > Dmitry, when you have time, could you try your benchmark in bug#60953 > with this patch? I made predicates evaluate before we create any nodes, > so #equal and #match should be more efficient now, when there are a lot > of rejections. In the same time #pred is made slightly worst since they > now create a lisp node and discard it. (But this can be fixed with a > little more complexity.) Thank you, I was curious what would the improvement be if we could delay allocation of node structures until :match is checked. But for my benchmark the difference is on the order of 4-5%. It seems we are scraping the barrel in terms of improving allocations/reducing GC because according to 'benchmark-run', where the whole run of a 100 iterations of the scenario takes ~1.1s, the time spent in GC is 0.150s. And the improved version takes like 1.04s, with 0.1s in GC. So if you ask me, I think I'd prefer to hold off on applying this patch until we either find scenarios where the improvement is more significant, or we find and eliminate some other bigger bottleneck first, after which these 5% grow to become 10-20% or more, of remaining runtime. The current approach is pretty Lisp-y, so I kind of like it. And there's the issue of #pred, of course, which which could swing the difference in the other direction (I didn't test any code which uses it). We could also try a smaller change: where the initial list of conses for result is build with capture_id's in car's, and then substituted with capture_name if the predicates all match. Then tthe treesit_node pseudovectors would still be created eagerly, though. Here's the current perf report for my benchmark, most of the time is spent in libtree-sitter: 17.02% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_current_status ◆ 10.94% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_goto_next_sibling ▒ 9.93% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_goto_first_child ▒ 9.55% emacs emacs [.] process_mark_stack ▒ 4.56% emacs libtree-sitter.so.0.0 [.] ts_node_start_point ▒ 3.90% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_parent_node ▒ 3.69% emacs emacs [.] re_match_2_internal ▒ 3.08% emacs libtree-sitter.so.0.0 [.] ts_language_symbol_metadata ▒ 1.61% emacs emacs [.] exec_byte_code ▒ 1.47% emacs libtree-sitter.so.0.0 [.] ts_node_end_point ▒ 1.44% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_current_node ▒ 1.13% emacs emacs [.] allocate_vectorlike ▒ 1.11% emacs emacs [.] sweep_strings ▒ 1.04% emacs libtree-sitter.so.0.0 [.] ts_node_end_byte ▒ 0.94% emacs emacs [.] next_interval ▒ 0.91% emacs libtree-sitter.so.0.0 [.] ts_tree_cursor_goto_parent ▒ 0.88% emacs emacs [.] lookup_char_property ▒ 0.81% emacs emacs [.] find_interval ▒ 0.68% emacs emacs [.] pdumper_marked_p_impl ▒ 0.67% emacs emacs [.] assq_no_quit ▒ 0.56% emacs libtree-sitter.so.0.0 [.] ts_node_symbol ▒ 0.56% emacs emacs [.] mark_char_table ▒ 0.55% emacs emacs [.] execute_charset ▒ 0.49% emacs libtree-sitter.so.0.0 [.] 0x000000000001ae3e ▒ 0.49% emacs emacs [.] re_search_2 ▒ 0.48% emacs emacs [.] funcall_subr ▒ 0.46% emacs libc.so.6 [.] __strncmp_sse42 ▒ 0.42% emacs libtree-sitter.so.0.0 [.] ts_language_public_symbol ▒ 0.41% emacs libtree-sitter.so.0.0 [.] ts_node_is_named ▒ 0.40% emacs libtree-sitter.so.0.0 [.] ts_node_new ▒ 0.34% emacs emacs [.] Fassq ▒ 0.34% emacs emacs [.] sweep_vectors From unknown Sun Jun 15 08:44:13 2025 X-Loop: help-debbugs@gnu.org Subject: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture Resent-From: Yuan Fu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 23 Mar 2023 03:17:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 62368 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Dmitry Gutov Cc: 62368@debbugs.gnu.org Received: via spool by 62368-submit@debbugs.gnu.org id=B62368.167954139523029 (code B ref 62368); Thu, 23 Mar 2023 03:17:01 +0000 Received: (at 62368) by debbugs.gnu.org; 23 Mar 2023 03:16:35 +0000 Received: from localhost ([127.0.0.1]:37012 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pfBRK-0005zN-RU for submit@debbugs.gnu.org; Wed, 22 Mar 2023 23:16:35 -0400 Received: from mail-pj1-f47.google.com ([209.85.216.47]:46913) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pfBRI-0005yx-2i for 62368@debbugs.gnu.org; Wed, 22 Mar 2023 23:16:33 -0400 Received: by mail-pj1-f47.google.com with SMTP id f6-20020a17090ac28600b0023b9bf9eb63so637593pjt.5 for <62368@debbugs.gnu.org>; Wed, 22 Mar 2023 20:16:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1679541386; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=LLNRFoM/WdIe6yovVe6mu7SnKSeLGPQ1mvFYOibg8Lk=; b=GPCKtC3+CTFh9Zu7Mqr1F12MsDrIVa7AVcczArCnSQqmLNsTgSKrMk6mKiN9Z2fDvy rU4GRSXuQ/Ey3RXCGiH3w3VCLZ4TwOZ3kzFidzkqwGehc/zWxN3+tFtWcqj3/0rfE0Az Gg1EdJDAprxxsChmv9/nWJBypvU2un7QrojMjYC0q5wJBTLnhUq8bBeGh4NKf7SchfB8 d7A90hJSTlMMIaRqiCgmPdw9uFArUC/ruoCCN6L/QEIH4I8JjVfnI0Ro/tUOaRo36aUw WqD/3Vn+yWlMf0LLW9/twLxzxqwNiD08Z5QmRifNzmVV/S14MDK6fbcJfbgu5Cw+zHak bekg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679541386; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LLNRFoM/WdIe6yovVe6mu7SnKSeLGPQ1mvFYOibg8Lk=; b=F3Sf6OxyHaond2+iVgUSNZLxEH0uD20YdDa6lJb9jBG+pUZ3p4bE9c8ewpHxrJ+n+S G+Q9ehB+anpfErb6sfSkfacJvylLbTvjg+P4gPTDLUFGWYAfZt6VY3Gpp4QcHKbGk5b2 XBBrSVFfL8ZEzpjQrWI3qibmr66PVvfKQzXLtYce+MbN/eNz7noZgu3fIRU23GSJ/EZv s2eow6obs0Fw5HGW4txZpq242TF7hFremCulpEYaBK3Y0BevTFXBL3z5XMTFmM7WPQy3 3j7THolzolucjSsgCVMjU9ye4wRiJ+hokhUC0E8KgYaIgWdnthSh+FbVoLid6oPHF59t UblA== X-Gm-Message-State: AO0yUKV3YkiiOVaDEONYPiGQai6jQKu5ByOFY08cFiUdqtC3fGoUHUU0 OsvyBAI6Yb5iO2BOBpXn0mA= X-Google-Smtp-Source: AK7set9N8qNsVEX9tGDEe/viWIxD0Bt7jrF2Ap6/RwwsyHeDWLlSsEdI2nD2E30OjNvwKgfn4D38uA== X-Received: by 2002:a17:903:300c:b0:1a0:4b23:84a with SMTP id o12-20020a170903300c00b001a04b23084amr3579718pla.46.1679541386278; Wed, 22 Mar 2023 20:16:26 -0700 (PDT) Received: from smtpclient.apple (cpe-172-117-161-177.socal.res.rr.com. [172.117.161.177]) by smtp.gmail.com with ESMTPSA id p14-20020a170902a40e00b00198e7d97171sm11226529plq.128.2023.03.22.20.16.25 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 22 Mar 2023 20:16:25 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.400.51.1.1\)) From: Yuan Fu In-Reply-To: Date: Wed, 22 Mar 2023 20:16:14 -0700 Content-Transfer-Encoding: quoted-printable Message-Id: References: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> X-Mailer: Apple Mail (2.3731.400.51.1.1) X-Spam-Score: 1.0 (+) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) > On Mar 22, 2023, at 5:42 PM, Dmitry Gutov wrote: >=20 > Hi Yuan! >=20 > On 22/03/2023 06:49, Yuan Fu wrote: >> X-Debbugs-CC:dgutov@yandex.ru >> Dmitry, when you have time, could you try your benchmark in bug#60953 >> with this patch? I made predicates evaluate before we create any = nodes, >> so #equal and #match should be more efficient now, when there are a = lot >> of rejections. In the same time #pred is made slightly worst since = they >> now create a lisp node and discard it. (But this can be fixed with a >> little more complexity.) >=20 > Thank you, I was curious what would the improvement be if we could = delay allocation of node structures until :match is checked. >=20 > But for my benchmark the difference is on the order of 4-5%. It seems = we are scraping the barrel in terms of improving allocations/reducing GC = because according to 'benchmark-run', where the whole run of a 100 = iterations of the scenario takes ~1.1s, the time spent in GC is 0.150s. = And the improved version takes like 1.04s, with 0.1s in GC. >=20 > So if you ask me, I think I'd prefer to hold off on applying this = patch until we either find scenarios where the improvement is more = significant, or we find and eliminate some other bigger bottleneck = first, after which these 5% grow to become 10-20% or more, of remaining = runtime. The current approach is pretty Lisp-y, so I kind of like it. >=20 > And there's the issue of #pred, of course, which which could swing the = difference in the other direction (I didn't test any code which uses = it). >=20 > We could also try a smaller change: where the initial list of conses = for result is build with capture_id's in car's, and then substituted = with capture_name if the predicates all match. Then tthe treesit_node = pseudovectors would still be created eagerly, though. Thank you very much! Yeah, it doesn=E2=80=99t seem to worth it. I guess = we can keep this in our back sleeve for now ;-) I think using symbols is fine for now, since I don=E2=80=99t think it = would make much difference. Yuan= From unknown Sun Jun 15 08:44:13 2025 X-Loop: help-debbugs@gnu.org Subject: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture Resent-From: Stefan Kangas Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 12 Sep 2023 00:07:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 62368 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Yuan Fu Cc: 62368@debbugs.gnu.org, Dmitry Gutov Received: via spool by 62368-submit@debbugs.gnu.org id=B62368.169447716224942 (code B ref 62368); Tue, 12 Sep 2023 00:07:01 +0000 Received: (at 62368) by debbugs.gnu.org; 12 Sep 2023 00:06:02 +0000 Received: from localhost ([127.0.0.1]:55327 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qfqun-0006U5-OV for submit@debbugs.gnu.org; Mon, 11 Sep 2023 20:06:02 -0400 Received: from mail-lj1-x236.google.com ([2a00:1450:4864:20::236]:42256) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qfqum-0006Ti-6H for 62368@debbugs.gnu.org; Mon, 11 Sep 2023 20:06:00 -0400 Received: by mail-lj1-x236.google.com with SMTP id 38308e7fff4ca-2bcb54226e7so61093671fa.1 for <62368@debbugs.gnu.org>; Mon, 11 Sep 2023 17:05:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1694477149; x=1695081949; darn=debbugs.gnu.org; h=content-transfer-encoding:cc:to:subject:message-id:date :mime-version:references:in-reply-to:from:from:to:cc:subject:date :message-id:reply-to; bh=TvC9SzfVH13sAljg42M1lCLq8CgefUfVJYglJovTzEM=; b=lpxXANHkOmt8I1okSNw7GmWR/otEgxhJ+kyVRHNXFWxgSXmfScLjZQFWmOo87/VMT4 j1RFLbzMjWft1J9VzfFTGcz7zxl43OHOxY2Tz4sSemQOpRhebg7HrZWwVC+wld0iqT49 uKOrnwyAyHZeIfWs3CmFaxvJno2QyAIcA4P1Nci6bgfHNoomGyVwgDJSf5tqBAV4qS+O 7Vfr7RNYRVxuKAyT7SEQ90GmgSZ93bXNwy8e9NQrYCNrOFm5D9G9D5Fk06dtCDRbQwtV Srez+r1v4mSldF+Fvar34RIhqPsUx3wJXRjpRgvH2EIRT7OQqCEXX+xUPXjKcWPkfUBF kwFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694477149; x=1695081949; h=content-transfer-encoding:cc:to:subject:message-id:date :mime-version:references:in-reply-to:from:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=TvC9SzfVH13sAljg42M1lCLq8CgefUfVJYglJovTzEM=; b=O9Gsf8lvc6TaWRIZGdvwqeKYX3cy+zzfqNKJvZSqckwzi9QwhmJTMvWQ2C0znjRlBk qA5E4Ihy9NkyDohgj5p/KVhhnnsMN4EKgz9s8tLpKYUbGX99JlO3ZXqA3TiMuY03bGWA KgH8/NJZyN+H5OIBO6RZ6dVy4+kHDMQbaqSlvgcQt+QxYBsP0GbMfTroLrHgWy1+YXDi pdMSJh92bEZUbyZ7FSUlNg1U3sdDaNu66vNP3WFyr5azt8fxS3x7x8Xam63wsJC6ibf8 BiHwT40wyRcC3QkT2HPJKZBhlYBMynxHVZQf5vtysBl08HY/MxQkfMhkBhb0yuNKASYT OETA== X-Gm-Message-State: AOJu0YyoCT0Gq2hNBCeULxp/Bvbw1bjZbj8r2g7sGeT2MwOv+McsU55L Zrb58nV6ec9it53BjaFi3jIuAYFiP2XJq5jMDD8= X-Google-Smtp-Source: AGHT+IGG3HUwaLu1/cScXLmCPPYGQpAAO8SWUNJ0fe5rLkQPyvYySYSXpQ0r7xQEuYQmJ+T0w6t8V9muVlTBDgIba20= X-Received: by 2002:a2e:a276:0:b0:2bd:7bd:1a45 with SMTP id k22-20020a2ea276000000b002bd07bd1a45mr415869ljm.13.1694477148775; Mon, 11 Sep 2023 17:05:48 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Mon, 11 Sep 2023 17:05:48 -0700 From: Stefan Kangas In-Reply-To: (Yuan Fu's message of "Wed, 22 Mar 2023 20:16:14 -0700") References: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> MIME-Version: 1.0 Date: Mon, 11 Sep 2023 17:05:48 -0700 Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Score: 1.0 (+) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Yuan Fu writes: >> On Mar 22, 2023, at 5:42 PM, Dmitry Gutov wrote: >> >> Hi Yuan! >> >> On 22/03/2023 06:49, Yuan Fu wrote: >>> X-Debbugs-CC:dgutov@yandex.ru Dmitry, when you have time, could you >>> try your benchmark in bug#60953 with this patch? I made predicates >>> evaluate before we create any nodes, so #equal and #match should be >>> more efficient now, when there are a lot of rejections. In the same >>> time #pred is made slightly worst since they now create a lisp node >>> and discard it. (But this can be fixed with a little more >>> complexity.) >> >> Thank you, I was curious what would the improvement be if we could >> delay allocation of node structures until :match is checked. >> >> But for my benchmark the difference is on the order of 4-5%. It seems >> we are scraping the barrel in terms of improving allocations/reducing >> GC because according to 'benchmark-run', where the whole run of a 100 >> iterations of the scenario takes ~1.1s, the time spent in GC is >> 0.150s. And the improved version takes like 1.04s, with 0.1s in GC. >> >> So if you ask me, I think I'd prefer to hold off on applying this >> patch until we either find scenarios where the improvement is more >> significant, or we find and eliminate some other bigger bottleneck >> first, after which these 5% grow to become 10-20% or more, of >> remaining runtime. The current approach is pretty Lisp-y, so I kind >> of like it. >> >> And there's the issue of #pred, of course, which which could swing >> the difference in the other direction (I didn't test any code which >> uses it). >> >> We could also try a smaller change: where the initial list of conses >> for result is build with capture_id's in car's, and then substituted >> with capture_name if the predicates all match. Then tthe treesit_node >> pseudovectors would still be created eagerly, though. > > Thank you very much! Yeah, it doesn=E2=80=99t seem to worth it. I guess w= e can > keep this in our back sleeve for now ;-) > > I think using symbols is fine for now, since I don=E2=80=99t think it wou= ld > make much difference. So should this bug be closed, then? From unknown Sun Jun 15 08:44:13 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: Yuan Fu Subject: bug#62368: closed (Re: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture) Message-ID: References: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> X-Gnu-PR-Message: they-closed 62368 X-Gnu-PR-Package: emacs Reply-To: 62368@debbugs.gnu.org Date: Tue, 12 Sep 2023 00:39:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1694479142-16568-1" This is a multi-part message in MIME format... ------------=_1694479142-16568-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #62368: 29.0.60; Evaluating predicates before creating captured nodes in t= reesit-query-capture which was filed against the emacs package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 62368@debbugs.gnu.org. --=20 62368: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D62368 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1694479142-16568-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 62368-done) by debbugs.gnu.org; 12 Sep 2023 00:38:15 +0000 Received: from localhost ([127.0.0.1]:55439 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qfrPy-0004IF-PN for submit@debbugs.gnu.org; Mon, 11 Sep 2023 20:38:15 -0400 Received: from mail-pf1-x42a.google.com ([2607:f8b0:4864:20::42a]:59804) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qfrPv-0004Hy-Kt for 62368-done@debbugs.gnu.org; Mon, 11 Sep 2023 20:38:13 -0400 Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-68fe39555a0so436157b3a.3 for <62368-done@debbugs.gnu.org>; Mon, 11 Sep 2023 17:38:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1694479081; x=1695083881; darn=debbugs.gnu.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=pFFhUEyvjouUCl/sHrU4SpVEajq8qDNs62w840bhgyA=; b=G9dYdPpdbApumr8YN6m8yysUIH3y+P8SNc2CYQEb72rO3I60PNbNZo7sc7JKY2THtB in6WiPJzk91GfwaU3Ttx9jDSNwNuh1+l9HJC5f+DcXIIwGhcuEa924wNo9yAThz6Qe4H IVw27+pM0JmxMprfC2d1tDL8kbaKXFsqtWRlDhUZ6NelHdLC0IZ/pKOiO+PpCvGELGLk DtIEWGKEwr/p6pxbX6jQDlg6MUjNGP1LhzpsQKufMciCmeVs337hAYN7XoJdADNQWeEO jYA3vCNysxCqPuq9F586wRihFKpDgB4nIJtmndrbPFniDe5eJ1BIdEOt3zcDrPJJqLWO gdJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694479081; x=1695083881; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pFFhUEyvjouUCl/sHrU4SpVEajq8qDNs62w840bhgyA=; b=bX3KD20az7rrkyORYKYzNoZ1hnqmBQdiekUVlCW+0+KTmuzATiRZVigcYfcGOEwCT1 lYgaeEHRQlBGaO9tUzPdeiLfeNYm4Mn5xQnqxxyhjOiHW6+5VpX8+Q+cbBJ8fdZCQ/EW 0abvJ97GTpaWpBHw6rXE4eEm0KwYwwy4bCtoKVb8xJFPpKUhIjIxP9rWbHSjqi3yE02S KJWV6NtN6XFAJbSBqRPuTYJ1ulG9Bkvf8SHiUz2jvmwSZqiaZOOCBRHS/eiKhexy/0Xo 9xui6ILT2+Sshy0KLxWpUpEK3xJ2Er29xBwE0xqVkbZ2wXFHR0Yvm1k/6BgdYZ9Lcgt6 oSOQ== X-Gm-Message-State: AOJu0YwkDtPJbvH3Gp7SD69jiPLN7xWytFPboI1OzJ0YClb80j5C1gj2 OroPDs+iciLavl0nr+lQ27M= X-Google-Smtp-Source: AGHT+IH99XUYjyBeX0KnzYU+lrtEy5D+Ud7QHhfHu3IN98LO5SmBh1jUEIpzvWZa7afC4TWXOLLLWg== X-Received: by 2002:a05:6a21:196:b0:133:f0b9:856d with SMTP id le22-20020a056a21019600b00133f0b9856dmr15743265pzb.17.1694479081316; Mon, 11 Sep 2023 17:38:01 -0700 (PDT) Received: from smtpclient.apple (cpe-172-117-161-177.socal.res.rr.com. [172.117.161.177]) by smtp.gmail.com with ESMTPSA id j9-20020aa79289000000b0066a31111cc5sm6138345pfa.152.2023.09.11.17.38.00 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 11 Sep 2023 17:38:01 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.700.6\)) Subject: Re: bug#62368: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture From: Yuan Fu In-Reply-To: Date: Mon, 11 Sep 2023 17:37:49 -0700 Content-Transfer-Encoding: quoted-printable Message-Id: References: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> To: Stefan Kangas X-Mailer: Apple Mail (2.3731.700.6) X-Spam-Score: 1.0 (+) X-Debbugs-Envelope-To: 62368-done Cc: 62368-done@debbugs.gnu.org, Dmitry Gutov X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) > On Sep 11, 2023, at 5:05 PM, Stefan Kangas = wrote: >=20 > Yuan Fu writes: >=20 >>> On Mar 22, 2023, at 5:42 PM, Dmitry Gutov wrote: >>>=20 >>> Hi Yuan! >>>=20 >>> On 22/03/2023 06:49, Yuan Fu wrote: >>>> X-Debbugs-CC:dgutov@yandex.ru Dmitry, when you have time, could you >>>> try your benchmark in bug#60953 with this patch? I made predicates >>>> evaluate before we create any nodes, so #equal and #match should be >>>> more efficient now, when there are a lot of rejections. In the same >>>> time #pred is made slightly worst since they now create a lisp node >>>> and discard it. (But this can be fixed with a little more >>>> complexity.) >>>=20 >>> Thank you, I was curious what would the improvement be if we could >>> delay allocation of node structures until :match is checked. >>>=20 >>> But for my benchmark the difference is on the order of 4-5%. It = seems >>> we are scraping the barrel in terms of improving = allocations/reducing >>> GC because according to 'benchmark-run', where the whole run of a = 100 >>> iterations of the scenario takes ~1.1s, the time spent in GC is >>> 0.150s. And the improved version takes like 1.04s, with 0.1s in GC. >>>=20 >>> So if you ask me, I think I'd prefer to hold off on applying this >>> patch until we either find scenarios where the improvement is more >>> significant, or we find and eliminate some other bigger bottleneck >>> first, after which these 5% grow to become 10-20% or more, of >>> remaining runtime. The current approach is pretty Lisp-y, so I kind >>> of like it. >>>=20 >>> And there's the issue of #pred, of course, which which could swing >>> the difference in the other direction (I didn't test any code which >>> uses it). >>>=20 >>> We could also try a smaller change: where the initial list of conses >>> for result is build with capture_id's in car's, and then substituted >>> with capture_name if the predicates all match. Then tthe = treesit_node >>> pseudovectors would still be created eagerly, though. >>=20 >> Thank you very much! Yeah, it doesn=E2=80=99t seem to worth it. I = guess we can >> keep this in our back sleeve for now ;-) >>=20 >> I think using symbols is fine for now, since I don=E2=80=99t think it = would >> make much difference. >=20 > So should this bug be closed, then? We can close this for now. Thanks Stefan. Yuan ------------=_1694479142-16568-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 22 Mar 2023 04:49:54 +0000 Received: from localhost ([127.0.0.1]:33194 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1peqQ6-0007m3-Dv for submit@debbugs.gnu.org; Wed, 22 Mar 2023 00:49:54 -0400 Received: from lists.gnu.org ([209.51.188.17]:39286) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1peqQ5-0007lw-7p for submit@debbugs.gnu.org; Wed, 22 Mar 2023 00:49:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1peqQ4-0005Aj-NM for bug-gnu-emacs@gnu.org; Wed, 22 Mar 2023 00:49:52 -0400 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1peqQ3-0001Di-2j for bug-gnu-emacs@gnu.org; Wed, 22 Mar 2023 00:49:52 -0400 Received: by mail-pl1-x62a.google.com with SMTP id iw3so18234384plb.6 for ; Tue, 21 Mar 2023 21:49:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1679460589; h=to:date:message-id:subject:mime-version:from:from:to:cc:subject :date:message-id:reply-to; bh=ocXgcamwd7J0CklU/TAkU+V4oFdupUANhofKGbeD4vw=; b=dvFb2EuUr79a1Yt/bFRp6JDlD+mVwSlwsA56C+h5KhYQWbUdP2StEVkzKQHiKfuZ6K gBQK6WcFURMGeUKjqVhrsGWG84+64vPV4vlMmZjAbqtgOSKVOzju8zoryd+7L+ypZ5Wp P/+BJFEdL6h1rVEWtparJVMsUWOnh0e4mPv0PD+E2Gz1vMuVGZY0pZPqUAKsK64faZBT Nwu1WKcm4waAMzjMg7AghuprOTD/Kbd/crCWPzRIqzYbwAk3mtVy0R8eDQHU0TTvq/um ds6b5owWeT+lue+j1EQORst70tVJVU7n118OZg010TiESnHolXn+8q2C3vQJ1IKyjmyu v65w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679460589; h=to:date:message-id:subject:mime-version:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=ocXgcamwd7J0CklU/TAkU+V4oFdupUANhofKGbeD4vw=; b=uCGY9cFRHy3B36F5u0XrI7vtr9axn9GHKYdnKsF1ug1uE3kBK9XP/V5ycugxih4gNS s3nZJLQfh+BHpqQQ/qWu3/U4Zy4Ie9jEu5vD+tJ5yNCBB6H4spp1zEAC/cJvT8iihZoI 7BPc6H0T2pqzDS0/W7F4MGUP5b8ogufAKvNFXrTHtCIStQsc2rD7tDInC+PhuleMQNRG 5Yo3uUV3dh/E4Ln+Oyy7+QZSmxYDhZw4WEyMMmbMubssP0V4iQpoHGbb0/9jorSqOWem MUzPUTFkcpZZuse4EsvtpGXcUbW/ptjf5qTqU0akdEPVJCD6yMjTEA2/aWV0k5GjFSIU yKkw== X-Gm-Message-State: AO0yUKXaDHGWg/xxNm84tfPzBs59j/Yx9ch68lUh9/YFOewgaiBXdLED 69FpX/Cma8imMAiVbG2TK95WczUE93o= X-Google-Smtp-Source: AK7set/On5A98uEbgrkuQec/rKS79FhewHawsSerUKXGvPA04H773DX/JaL7QtYwzfyQIG5AW8o1lw== X-Received: by 2002:a05:6a20:4b07:b0:d4:c41c:24e0 with SMTP id fp7-20020a056a204b0700b000d4c41c24e0mr4362427pzb.20.1679460588806; Tue, 21 Mar 2023 21:49:48 -0700 (PDT) Received: from smtpclient.apple (cpe-172-117-161-177.socal.res.rr.com. [172.117.161.177]) by smtp.gmail.com with ESMTPSA id s3-20020aa78d43000000b00625c96db7desm8677870pfe.198.2023.03.21.21.49.47 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Mar 2023 21:49:48 -0700 (PDT) From: Yuan Fu Content-Type: multipart/mixed; boundary="Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.400.51.1.1\)) Subject: 29.0.60; Evaluating predicates before creating captured nodes in treesit-query-capture Message-Id: <09A7EAB7-332E-4123-A6DB-8921FBD325C4@gmail.com> Date: Tue, 21 Mar 2023 21:49:37 -0700 To: Bug Report Emacs X-Mailer: Apple Mail (2.3731.400.51.1.1) Received-SPF: pass client-ip=2607:f8b0:4864:20::62a; envelope-from=casouri@gmail.com; helo=mail-pl1-x62a.google.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, FREEMAIL_REPLY=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Score: -0.3 (/) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-Debbugs-CC: dgutov@yandex.ru Dmitry, when you have time, could you try your benchmark in bug#60953 with this patch? I made predicates evaluate before we create any nodes, so #equal and #match should be more efficient now, when there are a lot of rejections. In the same time #pred is made slightly worst since they now create a lisp node and discard it. (But this can be fixed with a little more complexity.) Yuan --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2 Content-Disposition: attachment; filename=pred-first.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="pred-first.patch" Content-Transfer-Encoding: quoted-printable =46rom=20312063d389ea4e4f17ab82ab3da093c172e4142d=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=20= 21=20Mar=202023=2016:03:08=20-0700=0ASubject:=20[PATCH=201/3]=20Refactor=20= Ftreesit_query_capture=0A=0ARefactor=20some=20part=20of=20= Ftreesit_query_capture=20out=20into=20separate=0Afunctions,=20to=20pave=20= the=20way=20for=20other=20query-based=20functions.=0A=0A*=20= src/treesit.c=20(treesit_resolve_node):=20New=20function.=0A= (treesit_initialize_query):=20New=20function.=0A= (Ftreesit_query_capture):=20Refactor=20some=20part=20into=20new=20= functions.=0A---=0A=20src/treesit.c=20|=20153=20= ++++++++++++++++++++++++++++++++------------------=0A=201=20file=20= changed,=2097=20insertions(+),=2056=20deletions(-)=0A=0Adiff=20--git=20= a/src/treesit.c=20b/src/treesit.c=0Aindex=205a4fe3e8803..e728d697c9d=20= 100644=0A---=20a/src/treesit.c=0A+++=20b/src/treesit.c=0A@@=20-2631,8=20= +2631,8=20@@=20DEFUN=20("treesit-query-compile",=0A=20=20=20=20=20=20=20= Lisp_Object=20signal_symbol=20=3D=20Qnil;=0A=20=20=20=20=20=20=20= Lisp_Object=20signal_data=20=3D=20Qnil;=0A=20=20=20=20=20=20=20TSQuery=20= *treesit_query=20=3D=20treesit_ensure_query_compiled=20(lisp_query,=0A-=09= =09=09=09=09=09=09=20&signal_symbol,=0A-=09=09=09=09=09=09=09=20= &signal_data);=0A+=09=09=09=09=09=09=09=20=20=20=20=20=20&signal_symbol,=0A= +=09=09=09=09=09=09=09=20=20=20=20=20=20&signal_data);=0A=20=0A=20=20=20=20= =20=20=20if=20(treesit_query=20=3D=3D=20NULL)=0A=20=09xsignal=20= (signal_symbol,=20signal_data);=0A@@=20-2641,6=20+2641,92=20@@=20DEFUN=20= ("treesit-query-compile",=0A=20=20=20=20=20}=0A=20}=0A=20=0A+/*=20= Resolve=20OBJ=20into=20a=20tree-sitter=20node=20Lisp_Object.=20=20OBJ=20= can=20be=20a=0A+=20=20=20node,=20a=20parser,=20or=20a=20language=20= symbol.=20=20Note=20that=20this=20function=20can=0A+=20=20=20signal.=20=20= */=0A+static=20Lisp_Object=20treesit_resolve_node=20(Lisp_Object=20obj)=0A= +{=0A+=20=20if=20(TS_NODEP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= treesit_check_node=20(obj);=20/*=20Check=20if=20up-to-date.=20=20*/=0A+=20= =20=20=20=20=20return=20obj;=0A+=20=20=20=20}=0A+=20=20else=20if=20= (TS_PARSERP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= treesit_check_parser=20(obj);=20/*=20Check=20if=20deleted.=20=20*/=0A+=20= =20=20=20=20=20return=20Ftreesit_parser_root_node=20(obj);=0A+=20=20=20=20= }=0A+=20=20else=20if=20(SYMBOLP=20(obj))=0A+=20=20=20=20{=0A+=20=20=20=20= =20=20Lisp_Object=20parser=0A+=09=3D=20Ftreesit_parser_create=20(obj,=20= Fcurrent_buffer=20(),=20Qnil);=0A+=20=20=20=20=20=20return=20= Ftreesit_parser_root_node=20(parser);=0A+=20=20=20=20}=0A+=20=20else=0A+=20= =20=20=20xsignal2=20(Qwrong_type_argument,=0A+=09=20=20=20=20=20=20list4=20= (Qor,=20Qtreesit_node_p,=20Qtreesit_parser_p,=20Qsymbolp),=0A+=09=20=20=20= =20=20=20obj);=0A+}=0A+=0A+/*=20Create=20and=20initialize=20QUERY.=20=20= When=20success,=20initialize=20TS_QUERY,=0A+=20=20=20CURSOR,=20and=20= NEED_FREE,=20and=20return=20true;=20if=20failed,=20initialize=0A+=20=20=20= SIGNAL_SYMBOL=20and=20SIGNAL_DATA,=20and=20return=20false.=20=20If=20= NEED_FREE=20is=0A+=20=20=20initialized=20to=20true,=20the=20TS_QUERY=20= and=20CURSOR=20needs=20to=20be=20freed=0A+=20=20=20after=20use;=20= otherwise=20they=20shouldn't=20be=20freed=20by=20hand.=0A+=0A+=20=20=20= Basically=20this=20function=20looks=20at=20QUERY=20and=20check=20its=20= type,=20if=20QUERY=0A+=20=20=20is=20a=20compiled=20query,=20this=20= function=20takes=20out=20its=20query=20and=20cursor;=0A+=20=20=20if=20= QUERY=20is=20a=20string=20or=20a=20cons,=20this=20function=20creates=20a=20= new=20query=0A+=20=20=20and=20cursor=20(so=20they=20need=20to=20be=20= manually=20freed).=0A+=0A+=20=20=20This=20function=20assumes=20QUERY=20= is=20either=20a=20compiled=20query,=20a=20string=20or=0A+=20=20=20a=20= cons,=20the=20caller=20should=20make=20sure=20QUERY=20is=20valid.=0A+=0A= +=20=20=20LANG=20is=20the=20language=20to=20use=20if=20we=20need=20to=20= create=20the=20query=20and=0A+=20=20=20cursor.=20=20*/=0A+static=20bool=0A= +treesit_initialize_query=20(Lisp_Object=20query,=20const=20TSLanguage=20= *lang,=0A+=09=09=09=20=20TSQuery=20**ts_query,=20TSQueryCursor=20= **cursor,=0A+=09=09=09=20=20bool=20*need_free,=20Lisp_Object=20= *signal_symbol,=0A+=09=09=09=20=20Lisp_Object=20*signal_data)=0A+{=0A+=20= =20if=20(TS_COMPILED_QUERY_P=20(query))=0A+=20=20=20=20{=0A+=20=20=20=20=20= =20*ts_query=20=3D=20treesit_ensure_query_compiled=20(query,=20= signal_symbol,=0A+=09=09=09=09=09=09=20signal_data);=0A+=20=20=20=20=20=20= *cursor=20=3D=20XTS_COMPILED_QUERY=20(query)->cursor;=0A+=20=20=20=20=20=20= /*=20We=20don't=20need=20to=20free=20ts_query=20and=20cursor=20because=20= they=0A+=09=20are=20stored=20in=20a=20lisp=20object,=20which=20is=20= tracked=20by=20gc.=20=20*/=0A+=20=20=20=20=20=20*need_free=20=3D=20= false;=0A+=20=20=20=20=20=20return=20(*ts_query=20!=3D=20NULL);=0A+=20=20= =20=20}=0A+=20=20else=0A+=20=20=20=20{=0A+=20=20=20=20=20=20/*=20Since=20= query=20is=20not=20TS_COMPILED_QUERY,=20it=20can=20only=20be=20a=20= string=0A+=09=20or=20a=20cons.=20=20*/=0A+=20=20=20=20=20=20if=20(CONSP=20= (query))=0A+=09query=20=3D=20Ftreesit_query_expand=20(query);=0A+=20=20=20= =20=20=20char=20*query_string=20=3D=20SSDATA=20(query);=0A+=20=20=20=20=20= =20uint32_t=20error_offset;=0A+=20=20=20=20=20=20TSQueryError=20= error_type;=0A+=20=20=20=20=20=20*ts_query=20=3D=20ts_query_new=20(lang,=20= query_string,=20strlen=20(query_string),=0A+=09=09=09=09&error_offset,=20= &error_type);=0A+=20=20=20=20=20=20if=20(*ts_query=20=3D=3D=20NULL)=0A+=09= {=0A+=09=20=20*signal_symbol=20=3D=20Qtreesit_query_error;=0A+=09=20=20= *signal_data=20=3D=20treesit_compose_query_signal_data=20(error_offset,=0A= +=09=09=09=09=09=09=09=20=20=20=20error_type,=20query);=0A+=09=20=20= return=20false;=0A+=09}=0A+=20=20=20=20=20=20else=0A+=09{=0A+=09=20=20= *cursor=20=3D=20ts_query_cursor_new=20();=0A+=09=20=20*need_free=20=3D=20= true;=0A+=09=20=20return=20true;=0A+=09}=0A+=20=20=20=20}=0A+}=0A+=0A=20= DEFUN=20("treesit-query-capture",=0A=20=20=20=20=20=20=20=20= Ftreesit_query_capture,=0A=20=20=20=20=20=20=20=20= Streesit_query_capture,=202,=205,=200,=0A@@=20-2681,27=20+2767,7=20@@=20= DEFUN=20("treesit-query-capture",=0A=20=20=20treesit_initialize=20();=0A=20= =0A=20=20=20/*=20Resolve=20NODE=20into=20an=20actual=20node.=20=20*/=0A-=20= =20Lisp_Object=20lisp_node;=0A-=20=20if=20(TS_NODEP=20(node))=0A-=20=20=20= =20{=0A-=20=20=20=20=20=20treesit_check_node=20(node);=20/*=20Check=20if=20= up-to-date.=20=20*/=0A-=20=20=20=20=20=20lisp_node=20=3D=20node;=0A-=20=20= =20=20}=0A-=20=20else=20if=20(TS_PARSERP=20(node))=0A-=20=20=20=20{=0A-=20= =20=20=20=20=20treesit_check_parser=20(node);=20/*=20Check=20if=20= deleted.=20=20*/=0A-=20=20=20=20=20=20lisp_node=20=3D=20= Ftreesit_parser_root_node=20(node);=0A-=20=20=20=20}=0A-=20=20else=20if=20= (SYMBOLP=20(node))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20Lisp_Object=20= parser=0A-=09=3D=20Ftreesit_parser_create=20(node,=20Fcurrent_buffer=20= (),=20Qnil);=0A-=20=20=20=20=20=20lisp_node=20=3D=20= Ftreesit_parser_root_node=20(parser);=0A-=20=20=20=20}=0A-=20=20else=0A-=20= =20=20=20xsignal2=20(Qwrong_type_argument,=0A-=09=20=20=20=20=20=20list4=20= (Qor,=20Qtreesit_node_p,=20Qtreesit_parser_p,=20Qsymbolp),=0A-=09=20=20=20= =20=20=20node);=0A+=20=20Lisp_Object=20lisp_node=20=3D=20= treesit_resolve_node=20(node);=0A=20=0A=20=20=20/*=20Extract=20C=20= values=20from=20Lisp=20objects.=20=20*/=0A=20=20=20TSNode=20treesit_node=0A= @@=20-2725,40=20+2791,15=20@@=20DEFUN=20("treesit-query-capture",=0A=20=20= =20TSQuery=20*treesit_query;=0A=20=20=20TSQueryCursor=20*cursor;=0A=20=20= =20bool=20needs_to_free_query_and_cursor;=0A-=20=20if=20= (TS_COMPILED_QUERY_P=20(query))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20= Lisp_Object=20signal_symbol=20=3D=20Qnil;=0A-=20=20=20=20=20=20= Lisp_Object=20signal_data=20=3D=20Qnil;=0A-=20=20=20=20=20=20= treesit_query=20=3D=20treesit_ensure_query_compiled=20(query,=20= &signal_symbol,=0A-=09=09=09=09=09=09=20=20=20=20=20&signal_data);=0A-=20= =20=20=20=20=20cursor=20=3D=20XTS_COMPILED_QUERY=20(query)->cursor;=0A-=20= =20=20=20=20=20/*=20We=20don't=20need=20to=20free=20ts_query=20and=20= cursor=20because=20they=0A-=09=20are=20stored=20in=20a=20lisp=20object,=20= which=20is=20tracked=20by=20gc.=20=20*/=0A-=20=20=20=20=20=20= needs_to_free_query_and_cursor=20=3D=20false;=0A-=20=20=20=20=20=20if=20= (treesit_query=20=3D=3D=20NULL)=0A-=09xsignal=20(signal_symbol,=20= signal_data);=0A-=20=20=20=20}=0A-=20=20else=0A-=20=20=20=20{=0A-=20=20=20= =20=20=20/*=20Since=20query=20is=20not=20TS_COMPILED_QUERY,=20it=20can=20= only=20be=20a=20string=0A-=09=20or=20a=20cons.=20=20*/=0A-=20=20=20=20=20= =20if=20(CONSP=20(query))=0A-=09query=20=3D=20Ftreesit_query_expand=20= (query);=0A-=20=20=20=20=20=20char=20*query_string=20=3D=20SSDATA=20= (query);=0A-=20=20=20=20=20=20uint32_t=20error_offset;=0A-=20=20=20=20=20= =20TSQueryError=20error_type;=0A-=20=20=20=20=20=20treesit_query=20=3D=20= ts_query_new=20(lang,=20query_string,=20strlen=20(query_string),=0A-=09=09= =09=09=20=20=20=20&error_offset,=20&error_type);=0A-=20=20=20=20=20=20if=20= (treesit_query=20=3D=3D=20NULL)=0A-=09xsignal=20(Qtreesit_query_error,=0A= -=09=09=20treesit_compose_query_signal_data=20(error_offset,=0A-=09=09=09= =09=09=09=20=20=20=20error_type,=20query));=0A-=20=20=20=20=20=20cursor=20= =3D=20ts_query_cursor_new=20();=0A-=20=20=20=20=20=20= needs_to_free_query_and_cursor=20=3D=20true;=0A-=20=20=20=20}=0A+=20=20= Lisp_Object=20signal_symbol;=0A+=20=20Lisp_Object=20signal_data;=0A+=20=20= if=20(!treesit_initialize_query=20(query,=20lang,=20&treesit_query,=20= &cursor,=0A+=09=09=09=09=20&needs_to_free_query_and_cursor,=0A+=09=09=09=09= =20&signal_symbol,=20&signal_data))=0A+=20=20=20=20xsignal=20= (signal_symbol,=20signal_data);=0A=20=0A-=20=20/*=20WARN:=20After=20this=20= point,=20free=20treesit_query=20and=20cursor=20before=20every=0A-=20=20=20= =20=20signal=20and=20return.=20=20*/=0A+=20=20/*=20WARN:=20After=20this=20= point,=20free=20TREESIT_QUERY=20and=20CURSOR=20before=20every=0A+=20=20=20= =20=20signal=20and=20return=20if=20NEEDS_TO_FREE_QUERY_AND_CURSOR=20is=20= true.=20=20*/=0A=20=0A=20=20=20/*=20Set=20query=20range.=20=20*/=0A=20=20= =20if=20(!NILP=20(beg)=20&&=20!NILP=20(end))=0A--=20=0A2.33.1=0A=0A=0A= =46rom=20b166cb228cfe23ede54718d4b5ab6d1753d8337e=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=20= 21=20Mar=202023=2016:13:23=20-0700=0ASubject:=20[PATCH=202/3]=20;=20= Minor=20refactor=20of=20Ftreesit_query_capture=0A=0A*=20src/treesit.c=20= (Ftreesit_query_capture):=20Move=20around=20some=20variable=0A= initialization.=0A---=0A=20src/treesit.c=20|=2011=20+++++------=0A=201=20= file=20changed,=205=20insertions(+),=206=20deletions(-)=0A=0Adiff=20= --git=20a/src/treesit.c=20b/src/treesit.c=0Aindex=20= e728d697c9d..cd98ff38293=20100644=0A---=20a/src/treesit.c=0A+++=20= b/src/treesit.c=0A@@=20-2770,12=20+2770,9=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20Lisp_Object=20lisp_node=20=3D=20= treesit_resolve_node=20(node);=0A=20=0A=20=20=20/*=20Extract=20C=20= values=20from=20Lisp=20objects.=20=20*/=0A-=20=20TSNode=20treesit_node=0A= -=20=20=20=20=3D=20XTS_NODE=20(lisp_node)->node;=0A-=20=20Lisp_Object=20= lisp_parser=0A-=20=20=20=20=3D=20XTS_NODE=20(lisp_node)->parser;=0A-=20=20= ptrdiff_t=20visible_beg=0A-=20=20=20=20=3D=20XTS_PARSER=20(XTS_NODE=20= (lisp_node)->parser)->visible_beg;=0A+=20=20TSNode=20treesit_node=20=3D=20= XTS_NODE=20(lisp_node)->node;=0A+=20=20Lisp_Object=20lisp_parser=20=3D=20= XTS_NODE=20(lisp_node)->parser;=0A+=0A=20=20=20const=20TSLanguage=20= *lang=0A=20=20=20=20=20=3D=20ts_parser_language=20(XTS_PARSER=20= (lisp_parser)->parser);=0A=20=0A@@=20-2804,6=20+2801,8=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20/*=20Set=20query=20range.=20=20*/=0A= =20=20=20if=20(!NILP=20(beg)=20&&=20!NILP=20(end))=0A=20=20=20=20=20{=0A= +=20=20=20=20=20=20ptrdiff_t=20visible_beg=0A+=09=3D=20XTS_PARSER=20= (XTS_NODE=20(lisp_node)->parser)->visible_beg;=0A=20=20=20=20=20=20=20= ptrdiff_t=20beg_byte=20=3D=20CHAR_TO_BYTE=20(XFIXNUM=20(beg));=0A=20=20=20= =20=20=20=20ptrdiff_t=20end_byte=20=3D=20CHAR_TO_BYTE=20(XFIXNUM=20= (end));=0A=20=20=20=20=20=20=20/*=20We=20never=20let=20tree-sitter=20run=20= on=20buffers=20too=20large,=20so=20these=0A--=20=0A2.33.1=0A=0A=0A=46rom=20= 5c6c111a92c1da0a81b97a42a0b84fe8d9f03524=20Mon=20Sep=2017=2000:00:00=20= 2001=0AFrom:=20Yuan=20Fu=20=0ADate:=20Tue,=2021=20Mar=20= 2023=2021:10:59=20-0700=0ASubject:=20[PATCH=203/3]=20Evaluate=20= tree-sitter=20predicate=20functions=20before=20create=0A=20node=0A=0ABy=20= evaluating=20predicates=20before=20creating=20nodes,=20we=20can=20= eliminate=20some=0Awasteful=20consing=20when=20there=20are=20many=20= rejections=20(bug#60953).=20=20The=20one=0Adown=20side=20is=20that=20= #pred=20predicate=20now=20creates=20superfluous=20nodes:=20it=0Acreates=20= a=20node=20to=20feed=20to=20the=20function,=20but=20then=20discard=20it.=20= =20We=20can=0Aimprove=20it=20later=20if=20it=20proves=20problematic.=0A=0A= *=20src/treesit.c:=0A(capture_range):=20Remove.=0A(predicate_context):=20= New=20struct.=0A(treesit_predicates_for_pattern):=20Capture=20names=20= are=0Anot=20symbols=20anymore,=20but=20rather=20index=20numbers.=0A= (treesit_capture_id_to_name):=20New=20subroutine=20function=20that=20= converts=0Aan=20index=20number=20to=20the=20capture=20name.=20=20This=20= is=20only=20used=20by=20error=0Areporting.=0A= (treesit_predicate_capture_name_to_node):=20Remove.=0A= (treesit_capture_id_to_node):=20New=20function.=0A= (treesit_predicate_capture_name_to_text):=20Remove.=0A= (treesit_capture_id_to_text):=20New=20function.=0A= (treesit_predicate_equal)=0A(treesit_predicate_match)=0A= (treesit_predicate_pred)=0A(treesit_eval_predicates):=20Change=20to=20= the=20new=20index-based=20format.=20=20Also=0Anow=20we=20return=20the=20= signal=20data=20rather=20than=20signaling=20directly.=0A= (Ftreesit_query_capture):=20Now=20we=20evaluate=20predicates=20before=20= creating=0Anodes.=20=20We=20also=20set=20the=20current=20buffer=20to=20= that=20of=20the=20node=20we=20are=0Aworking=20on,=20so=20that=20the=20= predicate=20functions=20don't=20need=20to=20switch=0Abuffers=20= back-and-forth.=20=20Also,=20handle=20signals=20gracefully=20so=20we=20= don't=0Aleak=20memory.=0A---=0A=20src/treesit.c=20|=20337=20= +++++++++++++++++++++++++++++++-------------------=0A=201=20file=20= changed,=20208=20insertions(+),=20129=20deletions(-)=0A=0Adiff=20--git=20= a/src/treesit.c=20b/src/treesit.c=0Aindex=20cd98ff38293..c751223fc19=20= 100644=0A---=20a/src/treesit.c=0A+++=20b/src/treesit.c=0A@@=20-2349,23=20= +2349,38=20@@=20DEFUN=20("treesit-query-expand",=0A=20=20=20return=20= Fmapconcat=20(Qtreesit_pattern_expand,=20query,=20Vtreesit_str_space);=0A= =20}=0A=20=0A-/*=20This=20struct=20is=20used=20for=20passing=20captures=20= to=20be=20check=20against=0A-=20=20=20predicates.=20=20Captures=20we=20= check=20for=20are=20the=20ones=20in=20START=20before=0A-=20=20=20END.=20=20= For=20example,=20if=20START=20and=20END=20are=0A+/*=20This=20struct=20is=20= used=20passing=20context=20for=20evaluating=20predicates.=0A+=20=20=20= QUERY=20and=20MATCH=20are=20self-explanatory,=20ROOT_NODE=20is=20the=20= node=20we=20are=0A+=20=20=20querying.=0A=20=0A-=20=20=20START=20=20=20=20= =20=20=20END=0A+=20=20=20START=20and=20END=20points=20to=20the=20list=20= of=20captured=20nodes=20we=20are=20returning=0A+=20=20=20from=20= Ftreesit_query_capture.=20=20They=20mark=20the=20nodes=20we=20captured=20= in=0A+=20=20=20this=20match.=20=20Because=20we=20evaluate=20predicates=20= before=20adding=20captured=0A+=20=20=20nodes=20to=20the=20result=20list,=20= right=20now=20START=20simply=20equal=20to=20END.=0A+=0A+=20=20=20But=20= if=20we=20later=20decide=20we=20want=20to=20optimize=20for=20#pred=20= predicate,=0A+=20=20=20these=20two=20pointer=20will=20be=20useful.=0A+=0A= +=20=20=20An=20example:=0A+=0A+=20=20=20=20START=20=20=20=20=20=20=20=20=20= =20END=0A=20=20=20=20=20v=20=20=20=20=20=20=20=20=20=20=20=20=20=20v=0A-=20= =20=20(1=20.=20(2=20.=20(3=20.=20(4=20.=20(5=20.=20(6=20.=20nil))))))=0A= +=20=20=20(1=20.=20(2=20.=20(3=20.=20(4=20.=20(5=20.=20(6=20.=20= nil))))))=20->=20complete=20result=20list=0A=20=0A-=20=20=20We=20only=20= look=20at=20captures=201=202=203.=20=20*/=0A-struct=20capture_range=0A+=20= =20=201=202=203=20are=20the=20nodes=20captured=20by=20the=20current=20= match.=20=20*/=0A+struct=20predicate_context=0A=20{=0A+=20=20TSQuery=20= *query;=0A+=20=20TSQueryMatch=20*match;=0A+=20=20Lisp_Object=20= root_node;=0A=20=20=20Lisp_Object=20start;=0A=20=20=20Lisp_Object=20end;=0A= =20};=0A=20=0A=20/*=20Collect=20predicates=20for=20this=20match=20and=20= return=20them=20in=20a=20list.=20=20Each=0A-=20=20=20predicate=20is=20a=20= list=20of=20strings=20and=20symbols.=20=20*/=0A+=20=20=20predicate=20is=20= a=20list=20of=20strings=20and=20numbers.=20=20A=20number=20represents=0A= +=20=20=20the=20id=20of=20a=20capture=20name,=20the=20same=20thing=20as=20= the=20index=20attribute=20of=0A+=20=20=20a=20TSQueryCapture.=20=20*/=0A=20= static=20Lisp_Object=0A=20treesit_predicates_for_pattern=20(TSQuery=20= *query,=20uint32_t=20pattern_index)=0A=20{=0A@@=20-2381,12=20+2396,7=20= @@=20treesit_predicates_for_pattern=20(TSQuery=20*query,=20uint32_t=20= pattern_index)=0A=20=09{=0A=20=09case=20TSQueryPredicateStepTypeCapture:=0A= =20=09=20=20{=0A-=09=20=20=20=20uint32_t=20str_len;=0A-=09=20=20=20=20= const=20char=20*str=20=3D=20ts_query_capture_name_for_id=20(query,=0A-=09= =09=09=09=09=09=09=20=20=20=20step.value_id,=0A-=09=09=09=09=09=09=09=20=20= =20=20&str_len);=0A-=09=20=20=20=20predicate=20=3D=20Fcons=20= (intern_c_string_1=20(str,=20str_len),=0A-=09=09=09=20=20=20=20=20=20=20= predicate);=0A+=09=20=20=20=20predicate=20=3D=20Fcons=20(make_fixnum=20= (step.value_id),=20predicate);=0A=20=09=20=20=20=20break;=0A=20=09=20=20= }=0A=20=09case=20TSQueryPredicateStepTypeString:=0A@@=20-2407,118=20= +2417,159=20@@=20treesit_predicates_for_pattern=20(TSQuery=20*query,=20= uint32_t=20pattern_index)=0A=20=20=20return=20Fnreverse=20(result);=0A=20= }=0A=20=0A-/*=20Translate=20a=20capture=20NAME=20(symbol)=20to=20a=20= node.=0A-=20=20=20Signals=20treesit-query-error=20if=20such=20node=20is=20= not=20captured.=20=20*/=0A=20static=20Lisp_Object=0A= -treesit_predicate_capture_name_to_node=20(Lisp_Object=20name,=0A-=09=09=09= =09=09struct=20capture_range=20captures)=0A+treesit_capture_id_to_name=20= (TSQuery=20*query,=20ptrdiff_t=20id)=0A=20{=0A-=20=20Lisp_Object=20node=20= =3D=20Qnil;=0A-=20=20for=20(Lisp_Object=20tail=20=3D=20captures.start;=20= !EQ=20(tail,=20captures.end);=0A-=20=20=20=20=20=20=20tail=20=3D=20XCDR=20= (tail))=0A-=20=20=20=20{=0A-=20=20=20=20=20=20if=20(EQ=20(XCAR=20(XCAR=20= (tail)),=20name))=0A-=09{=0A-=09=20=20node=20=3D=20XCDR=20(XCAR=20= (tail));=0A-=09=20=20break;=0A-=09}=0A-=20=20=20=20}=0A-=0A-=20=20if=20= (NILP=20(node))=0A-=20=20=20=20xsignal3=20(Qtreesit_query_error,=0A-=09=20= =20=20=20=20=20build_string=20("Cannot=20find=20captured=20node"),=0A-=09= =20=20=20=20=20=20name,=20build_string=20("A=20predicate=20can=20only=20= refer"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20= to=20captured=20nodes=20in=20the=20"=0A-=09=09=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20"same=20pattern"));=0A-=20=20return=20node;=0A= +=20=20uint32_t=20len;=0A+=20=20const=20char*=20name_str=20=3D=20= ts_query_capture_name_for_id=20(query,=20(uint32_t)=20id,=0A+=09=09=09=09= =09=09=20=20=20=20=20=20=20&len);=0A+=20=20return=20make_string=20= (name_str,=20(ptrdiff_t)=20len);=0A=20}=0A=20=0A-/*=20Translate=20a=20= capture=20NAME=20(symbol)=20to=20the=20text=20of=20the=20captured=20= node.=0A-=20=20=20Signals=20treesit-query-error=20if=20such=20node=20is=20= not=20captured.=20=20*/=0A-static=20Lisp_Object=0A= -treesit_predicate_capture_name_to_text=20(Lisp_Object=20name,=0A-=09=09=09= =09=09struct=20capture_range=20captures)=0A+/*=20Translate=20a=20capture=20= id=20(fixnum)=20into=20the=20captured=20TSNode=20and=20set=20to=0A+=20=20= =20NODE.=20=20If=20we=20can't=20find=20the=20captured=20node,=20set=20= SIGNAL_DATA=20and=0A+=20=20=20return=20false,=20otherwise=20return=20= true.=20=20*/=0A+static=20bool=0A+treesit_capture_id_to_node=20(TSNode=20= *node,=20Lisp_Object=20id,=0A+=09=09=09=20=20=20=20struct=20= predicate_context=20*context,=0A+=09=09=09=20=20=20=20Lisp_Object=20= *signal_data)=0A=20{=0A-=20=20Lisp_Object=20node=20=3D=20= treesit_predicate_capture_name_to_node=20(name,=20captures);=0A+=20=20= const=20TSQueryCapture=20*captures=20=3D=20context->match->captures;=0A+=20= =20for=20(int=20idx=20=3D=200;=20idx=20<=20= context->match->capture_count;=20idx++)=0A+=20=20=20=20{=0A+=20=20=20=20=20= =20if=20(captures[idx].index=20=3D=3D=20XFIXNUM=20(id))=0A+=09{=0A+=09=20= =20*node=20=3D=20captures->node;=0A+=09=20=20return=20true;=0A+=09}=0A+=20= =20=20=20}=0A+=20=20Lisp_Object=20name=20=3D=20= treesit_capture_id_to_name=20(context->query,=20XFIXNUM=20(id));=0A+=20=20= *signal_data=20=3D=20list3=20(build_string=20("Cannot=20find=20captured=20= node"),=0A+=09=09=09name,=20build_string=20("A=20predicate=20can=20only=20= refer"=0A+=09=09=09=09=09=20=20=20=20"=20to=20captured=20nodes=20in=20= the=20"=0A+=09=09=09=09=09=20=20=20=20"same=20pattern"));=0A+=20=20= return=20false;=0A+}=0A=20=0A-=20=20struct=20buffer=20*old_buffer=20=3D=20= current_buffer;=0A-=20=20set_buffer_internal=20(XBUFFER=20(XTS_PARSER=20= (XTS_NODE=20(node)->parser)->buffer));=0A-=20=20Lisp_Object=20text=20=3D=20= Fbuffer_substring=20(Ftreesit_node_start=20(node),=0A-=09=09=09=09=09= Ftreesit_node_end=20(node));=0A-=20=20set_buffer_internal=20= (old_buffer);=0A-=20=20return=20text;=0A+/*=20Translate=20a=20capture=20= id=20(fixnum)=20into=20the=20text=20of=20the=20captured=20node=0A+=20=20=20= in=20the=20current=20buffer,=20and=20populate=20TEXT=20with=20it.=20=20= (Assumes=20current=0A+=20=20=20buffer=20is=20the=20buffer=20in=20which=20= the=20captured=20node=20and=20ROOT_NODE=20is).=0A+=20=20=20ROOT_NODE=20= is=20the=20root=20node=20of=20the=20query.=20=20If=20we=20can't=20find=20= the=0A+=20=20=20captured=20node,=20set=20SIGNAL_DATA=20and=20return=20= false,=20otherwise=20return=0A+=20=20=20true.=20=20*/=0A+static=20bool=0A= +treesit_capture_id_to_text=20(Lisp_Object=20*text,=20Lisp_Object=20id,=0A= +=09=09=09=20=20=20=20struct=20predicate_context=20*context,=0A+=09=09=09= =20=20=20=20Lisp_Object=20*signal_data)=0A+{=0A+=20=20TSNode=20node;=0A+=20= =20if=20(!treesit_capture_id_to_node=20(&node,=20id,=20context,=20= signal_data))=0A+=20=20=20=20return=20false;=0A+=0A+=20=20Lisp_Object=20= parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A+=20=20= ptrdiff_t=20begin_v=20=3D=20XTS_PARSER=20(parser)->visible_beg;=0A+=0A+=20= =20ptrdiff_t=20start_byte=20=3D=20(ptrdiff_t)=20ts_node_start_byte=20= (node)=20+=20begin_v;=0A+=20=20ptrdiff_t=20end_byte=20=3D=20(ptrdiff_t)=20= ts_node_end_byte=20(node)=20+=20begin_v;=0A+=0A+=20=20ptrdiff_t=20start=20= =3D=20BYTE_TO_CHAR=20(start_byte);=0A+=20=20ptrdiff_t=20end=20=3D=20= BYTE_TO_CHAR=20(end_byte);=0A+=0A+=20=20*text=20=3D=20= make_buffer_string_both=20(start,=20start_byte,=0A+=09=09=09=09=20=20=20= end,=20end_byte,=20false);=0A+=20=20return=20true;=0A=20}=0A=20=0A=20/*=20= Handles=20predicate=20(#equal=20A=20B).=20=20Return=20true=20if=20A=20= equals=20B;=20return=0A-=20=20=20false=20otherwise.=20=20A=20and=20B=20= can=20be=20either=20string,=20or=20a=20capture=20name.=0A-=20=20=20The=20= capture=20name=20evaluates=20to=20the=20text=20its=20captured=20node=20= spans=20in=0A-=20=20=20the=20buffer.=20=20*/=0A+=20=20=20false=20= otherwise.=20=20A=20and=20B=20can=20be=20a=20either=20string=20or=20a=20= capture=20id.=0A+=20=20=20The=20capture=20id=20evaluates=20to=20the=20= text=20spanned=20by=20the=20captured=20node=0A+=20=20=20in=20the=20= buffer.=20=20Assume=20current=20buffer=20is=20the=20buffer=20of=20the=20= captured=0A+=20=20=20node=20and=20ROOT_NODE.=20=20If=20something=20went=20= wrong,=20set=20signal_data,=0A+=20=20=20otherwise=20set=20it=20to=20= Qnil.=20=20IOW,=20caller=20should=20check=20the=20nullness=20of=0A+=20=20= =20signal_data=20for=20errors.=20=20*/=0A=20static=20bool=0A= -treesit_predicate_equal=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A+treesit_predicate_equal=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A= =20{=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20!=3D=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`equal'=20requires=20"=0A-=09=09=20=20=20=20=20=20=20=20=20= =20=20=20"two=20arguments=20but=20only=20given"),=0A-=09=20=20=20=20=20=20= Flength=20(args));=0A-=0A+=20=20=20=20{=0A+=20=20=20=20=20=20= *signal_data=20=3D=20list2=20(build_string=20("Predicate=20`equal'=20= requires=20"=0A+=09=09=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"two=20arguments=20but=20was=20given"),=0A+=09= =09=09=20=20=20=20Flength=20(args));=0A+=20=20=20=20=20=20return=20= false;=0A+=20=20=20=20}=0A=20=20=20Lisp_Object=20arg1=20=3D=20XCAR=20= (args);=0A=20=20=20Lisp_Object=20arg2=20=3D=20XCAR=20(XCDR=20(args));=0A= -=20=20Lisp_Object=20text1=20=3D=20(STRINGP=20(arg1)=0A-=09=09=20=20=20=20= =20=20=20?=20arg1=0A-=09=09=20=20=20=20=20=20=20:=20= treesit_predicate_capture_name_to_text=20(arg1,=0A-=09=09=09=09=09=09=09=09= =20captures));=0A-=20=20Lisp_Object=20text2=20=3D=20(STRINGP=20(arg2)=0A= -=09=09=20=20=20=20=20=20=20?=20arg2=0A-=09=09=20=20=20=20=20=20=20:=20= treesit_predicate_capture_name_to_text=20(arg2,=0A-=09=09=09=09=09=09=09=09= =20captures));=0A+=20=20Lisp_Object=20text1=20=3D=20arg1;=0A+=20=20= Lisp_Object=20text2=20=3D=20arg2;=0A+=20=20if=20(FIXNUMP=20(arg1))=0A+=20= =20=20=20{=0A+=20=20=20=20=20=20if=20(!treesit_capture_id_to_text=20= (&text1,=20arg1,=20context,=20signal_data))=0A+=09return=20false;=0A=20=0A= +=20=20=20=20}=0A+=20=20if=20(FIXNUMP=20(arg2))=0A+=20=20=20=20{=0A+=20=20= =20=20=20=20if=20(!treesit_capture_id_to_text=20(&text2,=20arg2,=20= context,=20signal_data))=0A+=09return=20false;=0A+=20=20=20=20}=0A=20=20=20= return=20!NILP=20(Fstring_equal=20(text1,=20text2));=0A=20}=0A=20=0A=20= /*=20Handles=20predicate=20(#match=20"regexp"=20@node).=20=20Return=20= true=20if=20"regexp"=0A-=20=20=20matches=20the=20text=20spanned=20by=20= @node;=20return=20false=20otherwise.=20=20Matching=0A-=20=20=20is=20= case-sensitive.=20=20*/=0A+=20=20=20matches=20the=20text=20spanned=20by=20= @node;=20return=20false=20otherwise.=0A+=20=20=20Matching=20is=20= case-sensitive.=20=20Assume=20current=20buffer=20is=20the=20buffer=20of=0A= +=20=20=20the=20captured=20node=20and=20ROOT_NODE.=20=20If=20something=20= went=20wrong,=20set=0A+=20=20=20signal_data,=20otherwise=20set=20it=20to=20= Qnil.=20=20IOW,=20caller=20should=20check=0A+=20=20=20the=20nullness=20= of=20signal_data=20for=20errors.=20=20*/=0A=20static=20bool=0A= -treesit_predicate_match=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A+treesit_predicate_match=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A= =20{=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20!=3D=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`match'=20requires=20two=20"=0A-=09=09=20=20=20=20=20=20=20= =20=20=20=20=20"arguments=20but=20only=20given"),=0A-=09=20=20=20=20=20=20= Flength=20(args));=0A+=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20= =3D=20list2=20(build_string=20("Predicate=20`match'=20requires=20two=20"=0A= +=09=09=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"arguments=20but=20only=20given"),=0A+=09=09=09=20=20=20=20= Flength=20(args));=0A+=20=20=20=20=20=20return=20false;=0A+=20=20=20=20}=0A= =20=0A=20=20=20Lisp_Object=20regexp=20=3D=20XCAR=20(args);=0A-=20=20= Lisp_Object=20capture_name=20=3D=20XCAR=20(XCDR=20(args));=0A+=20=20= Lisp_Object=20capture_id=20=3D=20XCAR=20(XCDR=20(args));=0A=20=0A=20=20=20= /*=20It's=20probably=20common=20to=20get=20the=20argument=20order=20= backwards.=20=20Catch=0A=20=20=20=20=20=20this=20mistake=20early=20and=20= show=20helpful=20explanation,=20because=20Emacs=0A=20=20=20=20=20=20= loves=20you.=20=20(We=20put=20the=20regexp=20first=20because=20that's=20= what=0A=20=20=20=20=20=20string-match=20does.)=20=20*/=0A=20=20=20if=20= (!STRINGP=20(regexp))=0A-=20=20=20=20xsignal1=20(Qtreesit_query_error,=0A= -=09=20=20=20=20=20=20build_string=20("The=20first=20argument=20to=20= `match'=20should=20"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20"be=20= a=20regexp=20string,=20not=20a=20capture=20name"));=0A-=20=20if=20= (!SYMBOLP=20(capture_name))=0A-=20=20=20=20xsignal1=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20("The=20= second=20argument=20to=20`match'=20should=20"=0A-=09=09=20=20=20=20=20=20= =20=20=20=20=20=20"be=20a=20capture=20name,=20not=20a=20string"));=0A+=20= =20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20build_string=20= ("The=20first=20argument=20to=20`match'=20should=20"=0A+=09=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"be=20= a=20regexp=20string,=20not=20a=20capture=20name");=0A+=20=20=20=20=20=20= return=20false;=0A+=20=20=20=20}=0A+=20=20if=20(!FIXNUMP=20(capture_id))=0A= +=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20build_string=20= ("The=20second=20argument=20to=20`match'=20should=20"=0A+=09=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"be=20= a=20capture=20name,=20not=20a=20string");=0A+=20=20=20=20=20=20return=20= false;=0A+=20=20=20=20}=0A=20=0A-=20=20Lisp_Object=20node=20=3D=20= treesit_predicate_capture_name_to_node=20(capture_name,=0A-=09=09=09=09=09= =09=09=20=20=20=20=20captures);=0A+=20=20TSNode=20treesit_node;=0A+=20=20= if=20(!treesit_capture_id_to_node=20(&treesit_node,=20capture_id,=20= context,=0A+=09=09=09=09=20=20=20signal_data))=0A+=20=20=20=20return=20= false;=0A=20=0A-=20=20struct=20buffer=20*old_buffer=20=3D=20= current_buffer;=0A-=20=20struct=20buffer=20*buffer=20=3D=20XBUFFER=20= (XTS_PARSER=20(XTS_NODE=20(node)->parser)->buffer);=0A-=20=20= set_buffer_internal=20(buffer);=0A-=0A-=20=20TSNode=20treesit_node=20=3D=20= XTS_NODE=20(node)->node;=0A-=20=20ptrdiff_t=20visible_beg=20=3D=20= XTS_PARSER=20(XTS_NODE=20(node)->parser)->visible_beg;=0A+=20=20= Lisp_Object=20parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A= +=20=20ptrdiff_t=20visible_beg=20=3D=20XTS_PARSER=20= (parser)->visible_beg;=0A=20=20=20uint32_t=20start_byte_offset=20=3D=20= ts_node_start_byte=20(treesit_node);=0A=20=20=20uint32_t=20= end_byte_offset=20=3D=20ts_node_end_byte=20(treesit_node);=0A-=20=20= ptrdiff_t=20start_byte=20=3D=20visible_beg=20+=20start_byte_offset;=0A-=20= =20ptrdiff_t=20end_byte=20=3D=20visible_beg=20+=20end_byte_offset;=0A+=20= =20ptrdiff_t=20start_byte=20=3D=20visible_beg=20+=20(ptrdiff_t)=20= start_byte_offset;=0A+=20=20ptrdiff_t=20end_byte=20=3D=20visible_beg=20+=20= (ptrdiff_t)=20end_byte_offset;=0A=20=20=20ptrdiff_t=20start_pos=20=3D=20= BYTE_TO_CHAR=20(start_byte);=0A=20=20=20ptrdiff_t=20end_pos=20=3D=20= BYTE_TO_CHAR=20(end_byte);=0A+=0A=20=20=20ptrdiff_t=20old_begv=20=3D=20= BEGV;=0A=20=20=20ptrdiff_t=20old_begv_byte=20=3D=20BEGV_BYTE;=0A=20=20=20= ptrdiff_t=20old_zv=20=3D=20ZV;=0A@@=20-2537,63=20+2588,78=20@@=20= treesit_predicate_match=20(Lisp_Object=20args,=20struct=20capture_range=20= captures)=0A=20=20=20ZV=20=3D=20old_zv;=0A=20=20=20ZV_BYTE=20=3D=20= old_zv_byte;=0A=20=0A-=20=20set_buffer_internal=20(old_buffer);=0A-=0A=20= =20=20return=20(val=20>=200);=0A=20}=0A=20=0A=20/*=20Handles=20predicate=20= (#pred=20FN=20ARG...).=20=20Return=20true=20if=20FN=20returns=0A=20=20=20= =20non-nil;=20return=20false=20otherwise.=20=20The=20arity=20of=20FN=20= must=20match=20the=0A-=20=20=20number=20of=20ARGs=20=20*/=0A+=20=20=20= number=20of=20ARGs.=20=20If=20something=20went=20wrong,=20set=20= signal_data,=0A+=20=20=20otherwise=20set=20it=20to=20Qnil.=20=20IOW,=20= caller=20should=20check=20the=20nullness=20of=0A+=20=20=20signal_data=20= for=20errors.=20=20*/=0A=20static=20bool=0A-treesit_predicate_pred=20= (Lisp_Object=20args,=20struct=20capture_range=20captures)=0A= +treesit_predicate_pred=20(Lisp_Object=20args,=20struct=20= predicate_context=20*context,=0A+=09=09=09Lisp_Object=20*signal_data)=0A=20= {=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20if=20(XFIXNUM=20= (Flength=20(args))=20<=202)=0A-=20=20=20=20xsignal2=20= (Qtreesit_query_error,=0A-=09=20=20=20=20=20=20build_string=20= ("Predicate=20`pred'=20requires=20"=0A-=09=09=20=20=20=20=20=20=20=20=20=20= =20=20"at=20least=20two=20arguments,=20"=0A-=09=09=20=20=20=20=20=20=20=20= =20=20=20=20"but=20was=20only=20given"),=0A-=09=20=20=20=20=20=20Flength=20= (args));=0A-=0A+=20=20=20=20{=0A+=20=20=20=20=20=20*signal_data=20=3D=20= list2=20(build_string=20("Predicate=20`pred'=20requires=20"=0A+=09=09=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= "at=20least=20two=20arguments,=20"=0A+=09=09=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"but=20was=20only=20= given"),=0A+=09=09=09=20=20=20=20Flength=20(args));=0A+=20=20=20=20=20=20= return=20false;=0A+=20=20=20=20}=0A=20=20=20Lisp_Object=20fn=20=3D=20= Fintern=20(XCAR=20(args),=20Qnil);=0A=20=20=20Lisp_Object=20nodes=20=3D=20= Qnil;=0A=20=20=20Lisp_Object=20tail=20=3D=20XCDR=20(args);=0A+=20=20= Lisp_Object=20parser=20=3D=20XTS_NODE=20(context->root_node)->parser;=0A=20= =20=20FOR_EACH_TAIL=20(tail)=0A-=20=20=20=20nodes=20=3D=20Fcons=20= (treesit_predicate_capture_name_to_node=20(XCAR=20(tail),=0A-=09=09=09=09= =09=09=09=20=20=20captures),=0A-=09=09=20=20=20nodes);=0A+=20=20{=0A+=20=20= =20=20TSNode=20ts_node;=0A+=20=20=20=20if=20(!treesit_capture_id_to_node=20= (&ts_node,=20XCAR=20(tail),=20context,=0A+=09=09=09=09=20=20=20=20=20= signal_data))=0A+=20=20=20=20=20=20return=20false;=0A+=20=20=20=20= Lisp_Object=20lisp_node=20=3D=20make_treesit_node=20(parser,=20ts_node);=0A= +=20=20=20=20nodes=20=3D=20Fcons=20(lisp_node,=20nodes);=0A+=20=20}=0A=20= =20=20nodes=20=3D=20Fnreverse=20(nodes);=0A=20=0A=20=20=20return=20!NILP=20= (CALLN=20(Fapply,=20fn,=20nodes));=0A=20}=0A=20=0A=20/*=20If=20all=20= predicates=20in=20PREDICATES=20passes,=20return=20true;=20otherwise=0A-=20= =20=20return=20false.=20=20*/=0A+=20=20=20return=20false.=20=20If=20= something=20went=20wrong,=20set=20signal_data,=20otherwise=0A+=20=20=20= set=20it=20to=20Qnil.=20=20IOW,=20caller=20should=20check=20the=20= nullness=20of=0A+=20=20=20signal_data=20for=20errors.=20=20*/=0A=20= static=20bool=0A-treesit_eval_predicates=20(struct=20capture_range=20= captures,=20Lisp_Object=20predicates)=0A+treesit_eval_predicates=20= (Lisp_Object=20predicates,=0A+=09=09=09=20struct=20predicate_context=20= *context,=0A+=09=09=09=20Lisp_Object=20*signal_data)=0A=20{=0A=20=20=20= bool=20pass=20=3D=20true;=0A+=20=20*signal_data=20=3D=20Qnil;=0A=20=20=20= /*=20Evaluate=20each=20predicates.=20=20*/=0A=20=20=20for=20(Lisp_Object=20= tail=20=3D=20predicates;=0A-=20=20=20=20=20=20=20!NILP=20(tail);=20tail=20= =3D=20XCDR=20(tail))=0A+=20=20=20=20=20=20=20!NILP=20(tail)=20&&=20pass;=20= tail=20=3D=20XCDR=20(tail))=0A=20=20=20=20=20{=0A=20=20=20=20=20=20=20= Lisp_Object=20predicate=20=3D=20XCAR=20(tail);=0A=20=20=20=20=20=20=20= Lisp_Object=20fn=20=3D=20XCAR=20(predicate);=0A=20=20=20=20=20=20=20= Lisp_Object=20args=20=3D=20XCDR=20(predicate);=0A=20=20=20=20=20=20=20if=20= (!NILP=20(Fstring_equal=20(fn,=20Vtreesit_str_equal)))=0A-=09pass=20&=3D=20= treesit_predicate_equal=20(args,=20captures);=0A+=09pass=20&=3D=20= treesit_predicate_equal=20(args,=20context,=20signal_data);=0A=20=20=20=20= =20=20=20else=20if=20(!NILP=20(Fstring_equal=20(fn,=20= Vtreesit_str_match)))=0A-=09pass=20&=3D=20treesit_predicate_match=20= (args,=20captures);=0A+=09pass=20&=3D=20treesit_predicate_match=20(args,=20= context,=20signal_data);=0A=20=20=20=20=20=20=20else=20if=20(!NILP=20= (Fstring_equal=20(fn,=20Vtreesit_str_pred)))=0A-=09pass=20&=3D=20= treesit_predicate_pred=20(args,=20captures);=0A+=09pass=20&=3D=20= treesit_predicate_pred=20(args,=20context,=20signal_data);=0A=20=20=20=20= =20=20=20else=0A-=09xsignal3=20(Qtreesit_query_error,=0A-=09=09=20=20= build_string=20("Invalid=20predicate"),=0A-=09=09=20=20fn,=20= build_string=20("Currently=20Emacs=20only=20supports"=0A-=09=09=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20equal,=20match,=20= and=20pred"=0A-=09=09=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20"=20predicate"));=0A+=09{=0A+=09=20=20*signal_data=20=3D=20list3=20= (build_string=20("Invalid=20predicate"),=0A+=09=09=09=09fn,=20= build_string=20("Currently=20Emacs=20only=20supports"=0A+=09=09=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"=20equal,=20match,=20and=20pred"=0A+=09=09=09=09=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20"=20predicate"));=0A+=09=20=20= break;=0A+=09}=0A=20=20=20=20=20}=0A-=20=20/*=20If=20all=20predicates=20= passed,=20add=20captures=20to=20result=20list.=20=20*/=0A=20=20=20return=20= pass;=0A=20}=0A=20=0A@@=20-2831,10=20+2897,34=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=20=20Lisp_Object=20result=20=3D=20Qnil;=0A= =20=20=20Lisp_Object=20prev_result=20=3D=20result;=0A=20=20=20= Lisp_Object=20predicates_table=20=3D=20make_vector=20(patterns_count,=20= Qt);=0A+=0A+=20=20struct=20buffer=20*old_buf=20=3D=20current_buffer;=0A+=20= =20set_buffer_internal=20(buf);=0A+=0A+=20=20signal_data=20=3D=20Qnil;=0A= =20=20=20while=20(ts_query_cursor_next_match=20(cursor,=20&match))=0A=20=20= =20=20=20{=0A=20=20=20=20=20=20=20/*=20Record=20the=20checkpoint=20that=20= we=20may=20roll=20back=20to.=20=20*/=0A=20=20=20=20=20=20=20prev_result=20= =3D=20result;=0A+=0A+=20=20=20=20=20=20/*=20Get=20predicates.=20=20*/=0A= +=20=20=20=20=20=20Lisp_Object=20predicates=20=3D=20AREF=20= (predicates_table,=20match.pattern_index);=0A+=20=20=20=20=20=20if=20(EQ=20= (predicates,=20Qt))=0A+=09{=0A+=09=20=20predicates=20=3D=20= treesit_predicates_for_pattern=20(treesit_query,=0A+=09=09=09=09=09=09=20= =20=20=20=20=20=20match.pattern_index);=0A+=09=20=20ASET=20= (predicates_table,=20match.pattern_index,=20predicates);=0A+=09}=0A+=0A+=20= =20=20=20=20=20/*=20Evaluate=20predicates.=20=20*/=0A+=20=20=20=20=20=20= struct=20predicate_context=20context=0A+=09=3D=20{=20treesit_query,=20= &match,=20lisp_node,=20result,=20prev_result=20};=0A+=20=20=20=20=20=20= bool=20pass=20=3D=20treesit_eval_predicates=20(predicates,=20&context,=20= &signal_data);=0A+=20=20=20=20=20=20if=20(!NILP=20(signal_data))=0A+=09= break;=0A+=20=20=20=20=20=20else=20if=20(!pass)=0A+=09continue;=0A+=0A=20= =20=20=20=20=20=20/*=20Get=20captured=20nodes.=20=20*/=0A=20=20=20=20=20=20= =20const=20TSQueryCapture=20*captures=20=3D=20match.captures;=0A=20=20=20= =20=20=20=20for=20(int=20idx=20=3D=200;=20idx=20<=20match.capture_count;=20= idx++)=0A@@=20-2858,26=20+2948,15=20@@=20DEFUN=20= ("treesit-query-capture",=0A=20=0A=20=09=20=20result=20=3D=20Fcons=20= (cap,=20result);=0A=20=09}=0A-=20=20=20=20=20=20/*=20Get=20predicates.=20= =20*/=0A-=20=20=20=20=20=20Lisp_Object=20predicates=20=3D=20AREF=20= (predicates_table,=20match.pattern_index);=0A-=20=20=20=20=20=20if=20(EQ=20= (predicates,=20Qt))=0A-=09{=0A-=09=20=20predicates=20=3D=20= treesit_predicates_for_pattern=20(treesit_query,=0A-=09=09=09=09=09=09=20= =20=20=20=20=20=20match.pattern_index);=0A-=09=20=20ASET=20= (predicates_table,=20match.pattern_index,=20predicates);=0A-=09}=0A-=0A-=20= =20=20=20=20=20/*=20captures_lisp=20=3D=20Fnreverse=20(captures_lisp);=20= */=0A-=20=20=20=20=20=20struct=20capture_range=20captures_range=20=3D=20= {=20result,=20prev_result=20};=0A-=20=20=20=20=20=20if=20= (!treesit_eval_predicates=20(captures_range,=20predicates))=0A-=09/*=20= Predicates=20didn't=20pass,=20roll=20back.=20=20*/=0A-=09result=20=3D=20= prev_result;=0A=20=20=20=20=20}=0A+=20=20set_buffer_internal=20= (old_buf);=0A=20=20=20if=20(needs_to_free_query_and_cursor)=0A=20=20=20=20= =20{=0A=20=20=20=20=20=20=20ts_query_delete=20(treesit_query);=0A=20=20=20= =20=20=20=20ts_query_cursor_delete=20(cursor);=0A=20=20=20=20=20}=0A+=20=20= if=20(!NILP=20(signal_data))=0A+=20=20=20=20xsignal=20= (Qtreesit_query_error,=20signal_data);=0A=20=20=20return=20Fnreverse=20= (result);=0A=20}=0A=20=0A--=20=0A2.33.1=0A=0A= --Apple-Mail=_F0AA0D58-CC72-4D8F-8886-266955D615F2-- ------------=_1694479142-16568-1--