GNU bug report logs - #47408
Emacs etags support for Mercury [v0.2]

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: fabrice nicol <fabrnicol@HIDDEN>; Keywords: patch; dated Fri, 26 Mar 2021 08:28:02 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 47408 <at> debbugs.gnu.org:


Received: (at 47408) by debbugs.gnu.org; 28 Mar 2021 15:48:57 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Mar 28 11:48:57 2021
Received: from localhost ([127.0.0.1]:46810 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1lQXeq-0006GS-SL
	for submit <at> debbugs.gnu.org; Sun, 28 Mar 2021 11:48:57 -0400
Received: from mail-wr1-f41.google.com ([209.85.221.41]:43912)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <fabrnicol@HIDDEN>) id 1lQXen-0006G9-KB
 for 47408 <at> debbugs.gnu.org; Sun, 28 Mar 2021 11:48:55 -0400
Received: by mail-wr1-f41.google.com with SMTP id x7so10367625wrw.10
 for <47408 <at> debbugs.gnu.org>; Sun, 28 Mar 2021 08:48:53 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
 h=from:subject:references:to:message-id:date:user-agent:mime-version
 :in-reply-to:content-language;
 bh=CbPAWbD3/rI7ibXFy1FyoAVEtEq8KSaCWmsdgB2dtSg=;
 b=HG1UVTkiqnTfj0DVVIY9YreHRR6pOwXhpRSmOBJql5e/Y4mXEzVlKRPWEfgSwsYe4a
 VwWEX3KUSlbgUcxxIyDIDbszgZeuh3NDkR9EC6yAnfqAioPc1gFs7ES1+cCQL3+6iiR2
 TmIPnMNe+cD3qd2szc66pHq4qkP02Rhim4i+XE2iLX9FRz/p1zHgLojDi/SkqPFvhQ1+
 bKNjZayaWsog6TGIU2loxWOyVk/+Wyx5OmlVSTUIHEP7ZpDLZ3HvA6e2WFnxA1yTusRo
 Sj1nhvOLegN3eBEmGVAPDeN6SMWVMOOCmT8kZgEwvS/uUCpW8XzJ6r7nLQ8yAan7f63P
 d9wA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:from:subject:references:to:message-id:date
 :user-agent:mime-version:in-reply-to:content-language;
 bh=CbPAWbD3/rI7ibXFy1FyoAVEtEq8KSaCWmsdgB2dtSg=;
 b=E3t5X3DpwBjaeU7x1GBBeOGCOMbf4cQ0Ltduu3XqTuFFihTEtK+gbeU0wsfaWTdow2
 wk9aOA0yxh8NLCynrRrCL0n7nXeBMyDB1EPjcVBjEOeG48+fCGYAWrQU08F6qOrfqlEz
 pCOUl//9C6xKYmpfu6LXXFx3qcpH47qoSguLIFLPnU7uymc69aT9K/kq95IDDQsMFTcq
 4LkJu2du931uFpXkqBXVicJ2SlubTqDWw/r9j4fOscS5W1UUR3+kmjcwwdferFGLBZlW
 m7AkDKtndnvH1m7po6GbO/CEhBSEDkfbF2utMi/zZcwVnthWsiJAo5v43OASpBMle5Ub
 RQJg==
X-Gm-Message-State: AOAM530oVeJ2ztAhsNBLnKYUQjf9tRdYhuwYb5zQwuk+X2JxDT/3BYJT
 /Gf4In+s0dQTu8GykVtW1Qv0qh6PHtc=
X-Google-Smtp-Source: ABdhPJyG1ONmj/lnCi295chVkdKURaIhn1SnhpAEQihcHqbQqr8pGySykpmHFsnoYyhVpCEng31tGQ==
X-Received: by 2002:adf:ec83:: with SMTP id z3mr24118831wrn.59.1616946527547; 
 Sun, 28 Mar 2021 08:48:47 -0700 (PDT)
Received: from ?IPv6:2a01:cb1d:88b9:5c00:7b73:7901:965e:8523?
 ([2a01:cb1d:88b9:5c00:7b73:7901:965e:8523])
 by smtp.gmail.com with ESMTPSA id c131sm21537368wma.37.2021.03.28.08.48.47
 for <47408 <at> debbugs.gnu.org>
 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
 Sun, 28 Mar 2021 08:48:47 -0700 (PDT)
From: fabrice nicol <fabrnicol@HIDDEN>
Subject: Re: bug#47408: Etags support for Mercury [v0.3]
References: <ccb782a9-e9bf-67f8-ebef-a03bdd83f75d@HIDDEN>
 <5ba2fec3-3f61-fb7e-35eb-7188fa6064a4@HIDDEN> <834kgvo220.fsf@HIDDEN>
To: 47408 <at> debbugs.gnu.org
Message-ID: <97f573da-ec63-7362-13c2-ca28a6634480@HIDDEN>
Date: Sun, 28 Mar 2021 17:49:20 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
 Thunderbird/78.9.0
MIME-Version: 1.0
In-Reply-To: <834kgvo220.fsf@HIDDEN>
Content-Type: multipart/alternative;
 boundary="------------F072051EFF8E1E91D0356A3F"
Content-Language: en-US
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 47408
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

This is a multi-part message in MIME format.
--------------F072051EFF8E1E91D0356A3F
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit

Thanks for this review.

Changes will be implemented soon as indicated.

(1) There is just one point that I would like to discuss before changing 
things around: the proposed -m/-M short option issue.


I left this couple of options in (following Francesco Potorti only for 
long options --declarations/--no-defines), for two reasons:

1. The ambiguity between Objective C and Mercury

Both languages having the same file extension .m, it was necessary to 
add in a heuristic test function, in the absence of explicit language 
identification input from command line.

Yet all heuristics may fail in rare cases. Tests show a fairly low 
failure rate on the Mercury compiler source code.  Less than 0.5 % of .m 
files are not identified as Mercury files by the test (this should have 
been documented somewhere).  File concerned by test failure are some 
Mercury test files and documentary test files with only (or almost only) 
comments and blank lines.

While this could be improved by tweaking the heuristic test, it would 
make it more complex, bug-prone and ultimately hard to maintain.

So -m/-M are useful to deal with these rare files, as they do not rely 
on the heuristic test function at all but on their own semantics, which 
explicitly identifies Mercury.

The only alternative I see is to explicitly warn users about adding '-l 
mercury' to command line when using long options (in etags.1 and 
possibly other docs).

Whether this is less intrusive (or more) than -m/-M is not crystal-clear 
to me.  Both solutions look on a par wrt this criterion, but -m/-M may 
be more user-friendly.

If two short options are one too many, I propose redesigning the short 
option pair as just one -m option with a binary argument (like: '-m 
defines / -m all', or -m 0 / -m 1).


2. The social side of things

As indicated previously, I also consulted the Mercury review list, and 
the feedback was positive on -m/-M (see below):

>     Accommodating different people's different preferences is a good idea
>     if it can be done at acceptable cost.
>
>>     Instead of -M, you should use --declarations
>>
>>     Instead of -m, you should use --no-defines
>     There is no need for "instead"; you can support both forms of both options.
>
So I opted for a compromise: renaming long options, following F. 
Potorti, and keeping -m/-M, following Z. Somogyi.


(2) Your following question:


>     diff --git a/lisp/speedbar.el b/lisp/speedbar.el
>     index 12e57b1108..63f3cd6ca1 100644
>     --- a/lisp/speedbar.el
>     +++ b/lisp/speedbar.el
>     @@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
>            speedbar-parse-c-or-c++tag)
>           ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
>            "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
>     +      ("^\\.m$\\'" .
>     +     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
>       ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
>       ;      speedbar-parse-fortran77-tag)
>           ("\\.tex\\'" . speedbar-parse-tex-string)
    What about ObjC here? or are these keywords good for ObjC as well?

has the following reply: Objective C .m files are not parsed by 
speedbar.el in current repository code, so the added feature does not 
break anything.  Issues will only arise if/when Emacs maintainers for 
Objective C support decide on adding this file format to the speedbar 
parser.   It would be premature (and out-of-place) for me to settle this 
on my own.  Should this move happen, the heuristics used in etags.c 
(function test_objc_is_mercury) could then be ported to elisp code.


>> +.TP
>> +.B \-M, \-\-no\-defines
>> +For the Mercury programming language, tag both declarations and
>> +definitions.  Declarations start a line with \fI:\-\fP optionally followed by a
>> +quantifier over a variable (\fIsome [T]\fP or \fIall [T]\fP), then by
>> +a builtin operator like \fIpred\fP or \fIfunc\fP.
>> +Definitions are first rules of clauses, as in Prolog.
>> +Implies \-\-language=mercury.
>> +.TP
>> +.B \-m, \-\-declarations
>> +For the Mercury programming language, tag declarations as with \fB\-M\fP, but do not
>> +tag definitions. Implies \-\-language=mercury.
> This is not what Francesco Potortì suggested to do.  He suggested that
> you use the existing options --no-defines and --declarations, but give
> them Mercury-specific meanings when processing Mercury source files.
> IOW, let's not introduce the new -m and -M shorthands for these options,
> and let's describe the Mercury-specific meaning of the existing
> options where they are currently described in etags.1.  OK?

> +** Etags support for the Mercury programming language (https://mercurylang.org).
> +** New etags command line options '-M/-m' or --declarations/--no-defines'.
> +Tags all Mercury declarations.  For compatibility with Prolog etags support,
> +predicates and functions appearing first in clauses will be tagged if etags is
> +run with the option '-M' or '--declarations'.  If run with '-m' or
> +'--no-defines', declarations will be tagged but definitions will not.
> +Both options imply --language=mercury.
> This should be amended for the changes in the options I described
> above.
> As mentioned, let's not introduce -m and -M.
>
>> +      case 'M':
>> +	with_mercury_definitions = true; FALLTHROUGH;
>> +      case 'm':
>> +	{
>> +	  language lang =
>> +	    { "mercury", Mercury_help, Mercury_functions, Mercury_suffixes };
>> +
>> +	  argbuffer[current_arg].lang = &lang;
>> +	  argbuffer[current_arg].arg_type = at_language;
>> +	}
>> +	break;
> Shouldn't be needed anymore.
>
>> diff --git a/lisp/speedbar.el b/lisp/speedbar.el
>> index 12e57b1108..63f3cd6ca1 100644
>> --- a/lisp/speedbar.el
>> +++ b/lisp/speedbar.el
>> @@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
>>        speedbar-parse-c-or-c++tag)
>>       ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
>>        "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
>> +      ("^\\.m$\\'" .
>> +     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
>>   ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
>>   ;      speedbar-parse-fortran77-tag)
>>       ("\\.tex\\'" . speedbar-parse-tex-string)
> What about ObjC here? or are these keywords good for ObjC as well?
>
> Last, but not least: if you can, please provide a test file for the
> etags test suite, see test/manual/etags/.
>
> Thanks again for working on this.

--------------F072051EFF8E1E91D0356A3F
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 8bit

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><font face="Courier 10 Pitch">Thanks for this review. <br>
      </font></p>
    <p><font face="Courier 10 Pitch">Changes will be implemented soon as
        indicated. </font><br>
      <font face="Courier 10 Pitch"><font face="Courier 10 Pitch"><br>
        </font></font></p>
    <p><font face="Courier 10 Pitch"><font face="Courier 10 Pitch">(1) 
          There is just one point that I would like to discuss before
          changing things around: the proposed -m/-M short option issue.</font></font></p>
    <p><font face="Courier 10 Pitch"><font face="Courier 10 Pitch"><br>
        </font></font></p>
    <p><font face="Courier 10 Pitch">I left this couple of options in
        (following Francesco Potorti only for long options
        --declarations/--no-defines), for two reasons:</font></p>
    <p><font face="Courier 10 Pitch">1. The ambiguity between Objective
        C and Mercury</font></p>
    <p><font face="Courier 10 Pitch">Both languages having the same file
        extension .m, it was necessary to add in a heuristic test
        function, in the absence of explicit language identification
        input from command line. <br>
      </font></p>
    <p><font face="Courier 10 Pitch">Yet all heuristics may fail in rare
        cases. Tests show a fairly low failure rate on the Mercury
        compiler source code.  Less than 0.5 % of .m files are not
        identified as Mercury files by the test (this should have been
        documented somewhere).  File concerned by test failure are some
        Mercury test files and documentary test files with only (or
        almost only) comments and blank lines. <br>
      </font></p>
    <p><font face="Courier 10 Pitch">While this could be improved by
        tweaking the heuristic test, it would make it more complex,
        bug-prone and ultimately hard to maintain.</font></p>
    <p><font face="Courier 10 Pitch">So -m/-M are useful to deal with
        these rare files, as they do not rely on the heuristic test
        function at all but on their own semantics, which explicitly
        identifies Mercury.    <br>
      </font></p>
    <p><font face="Courier 10 Pitch">The only alternative I see is to
        explicitly warn users about adding '-l mercury' to command line
        when using long options (in etags.1 and possibly other docs). <br>
      </font></p>
    <p><font face="Courier 10 Pitch">Whether this is less intrusive (or
        more) than -m/-M is not crystal-clear to me.  Both solutions
        look on a par wrt this criterion, but -m/-M may be more
        user-friendly. <br>
      </font></p>
    <p><font face="Courier 10 Pitch">If two short options are one too
        many, I propose redesigning the short option pair as just one -m
        option with a binary argument (like: '-m defines / -m all', or
        -m 0 / -m 1).<br>
      </font></p>
    <p><font face="Courier 10 Pitch"><br>
      </font></p>
    <p><font face="Courier 10 Pitch">2. The social side of things<br>
      </font></p>
    <p><font face="Courier 10 Pitch">As indicated previously, I also
        consulted the Mercury review list, and the feedback was positive
        on -m/-M (see below):</font><br>
    </p>
    <blockquote>
      <p><font face="Courier 10 Pitch"> </font></p>
      <blockquote type="cite"><font face="Courier 10 Pitch">
          <pre class="moz-quote-pre" wrap="">Accommodating different people's different preferences is a good idea
if it can be done at acceptable cost.

</pre>
          <blockquote type="cite" style="color: #007cff;">
            <pre class="moz-quote-pre" wrap="">Instead of -M, you should use --declarations

Instead of -m, you should use --no-defines
</pre>
          </blockquote>
          <pre class="moz-quote-pre" wrap="">There is no need for "instead"; you can support both forms of both options.

</pre>
        </font></blockquote>
      <font face="Courier 10 Pitch"> </font> </blockquote>
    <p>So I opted for a compromise: renaming long options, following F.
      Potorti, and keeping -m/-M, following Z. Somogyi. <br>
    </p>
    <p><font face="Courier 10 Pitch"><br>
      </font></p>
    <p><font face="Courier 10 Pitch">(2) Your following question:</font></p>
    <blockquote>
      <p><font face="Courier 10 Pitch"><br>
        </font></p>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index 12e57b1108..63f3cd6ca1 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
      speedbar-parse-c-or-c++tag)
     ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
      "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
+      ("^\\.m$\\'" .
+     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
 ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
 ;      speedbar-parse-fortran77-tag)
     ("\\.tex\\'" . speedbar-parse-tex-string)
</pre>
      </blockquote>
      <font size="-1"> <font face="Courier">What about ObjC here? or
          are these keywords good for ObjC as well?</font></font><br>
      <br>
    </blockquote>
    has the following reply: Objective C .m files are not parsed by
    speedbar.el in current repository code, so the added feature does
    not break anything.  Issues will only arise if/when Emacs
    maintainers for Objective C support decide on adding this file
    format to the speedbar parser.   It would be premature (and
    out-of-place) for me to settle this on my own.  Should this move
    happen, the heuristics used in etags.c (function
    test_objc_is_mercury) could then be ported to elisp code.
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:834kgvo220.fsf@HIDDEN">
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">+.TP
+.B \-M, \-\-no\-defines
+For the Mercury programming language, tag both declarations and
+definitions.  Declarations start a line with \fI:\-\fP optionally followed by a
+quantifier over a variable (\fIsome [T]\fP or \fIall [T]\fP), then by
+a builtin operator like \fIpred\fP or \fIfunc\fP.
+Definitions are first rules of clauses, as in Prolog.
+Implies \-\-language=mercury.
+.TP
+.B \-m, \-\-declarations
+For the Mercury programming language, tag declarations as with \fB\-M\fP, but do not
+tag definitions. Implies \-\-language=mercury.
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">This is not what Francesco Potortì suggested to do.  He suggested that
you use the existing options --no-defines and --declarations, but give
them Mercury-specific meanings when processing Mercury source files.
IOW, let's not introduce the new -m and -M shorthands for these options,
and let's describe the Mercury-specific meaning of the existing
options where they are currently described in etags.1.  OK?
</pre>
    </blockquote>
    <br>
    <blockquote type="cite" cite="mid:834kgvo220.fsf@HIDDEN">
      <pre class="moz-quote-pre" wrap="">+** Etags support for the Mercury programming language (<a class="moz-txt-link-freetext" href="https://mercurylang.org">https://mercurylang.org</a>).
+** New etags command line options '-M/-m' or --declarations/--no-defines'.
+Tags all Mercury declarations.  For compatibility with Prolog etags support,
+predicates and functions appearing first in clauses will be tagged if etags is
+run with the option '-M' or '--declarations'.  If run with '-m' or
+'--no-defines', declarations will be tagged but definitions will not.
+Both options imply --language=mercury.
</pre>
      <pre class="moz-quote-pre" wrap="">This should be amended for the changes in the options I described
above.
As mentioned, let's not introduce -m and -M.

</pre>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">+      case 'M':
+	with_mercury_definitions = true; FALLTHROUGH;
+      case 'm':
+	{
+	  language lang =
+	    { "mercury", Mercury_help, Mercury_functions, Mercury_suffixes };
+
+	  argbuffer[current_arg].lang = &amp;lang;
+	  argbuffer[current_arg].arg_type = at_language;
+	}
+	break;
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">Shouldn't be needed anymore.

</pre>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index 12e57b1108..63f3cd6ca1 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
      speedbar-parse-c-or-c++tag)
     ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
      "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
+      ("^\\.m$\\'" .
+     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
 ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
 ;      speedbar-parse-fortran77-tag)
     ("\\.tex\\'" . speedbar-parse-tex-string)
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">What about ObjC here? or are these keywords good for ObjC as well?

Last, but not least: if you can, please provide a test file for the
etags test suite, see test/manual/etags/.

Thanks again for working on this.
</pre>
    </blockquote>
  </body>
</html>

--------------F072051EFF8E1E91D0356A3F--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#47408; Package emacs. Full text available.

Message received at 47408 <at> debbugs.gnu.org:


Received: (at 47408) by debbugs.gnu.org; 28 Mar 2021 13:11:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Mar 28 09:11:54 2021
Received: from localhost ([127.0.0.1]:45534 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1lQVCr-00022w-OM
	for submit <at> debbugs.gnu.org; Sun, 28 Mar 2021 09:11:54 -0400
Received: from eggs.gnu.org ([209.51.188.92]:57758)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1lQVCp-00022k-LI
 for 47408 <at> debbugs.gnu.org; Sun, 28 Mar 2021 09:11:52 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e]:52212)
 by eggs.gnu.org with esmtp (Exim 4.90_1)
 (envelope-from <eliz@HIDDEN>)
 id 1lQVCk-0003GK-F6; Sun, 28 Mar 2021 09:11:46 -0400
Received: from 84.94.185.95.cable.012.net.il ([84.94.185.95]:4147
 helo=home-c4e4a596f7)
 by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256)
 (Exim 4.82) (envelope-from <eliz@HIDDEN>)
 id 1lQVCj-0008BR-NP; Sun, 28 Mar 2021 09:11:46 -0400
Date: Sun, 28 Mar 2021 16:11:51 +0300
Message-Id: <834kgvo220.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: fabrice nicol <fabrnicol@HIDDEN>
In-Reply-To: <5ba2fec3-3f61-fb7e-35eb-7188fa6064a4@HIDDEN> (message from
 fabrice nicol on Sat, 27 Mar 2021 11:51:22 +0100)
Subject: Re: bug#47408: Etags support for Mercury [v0.3]
References: <ccb782a9-e9bf-67f8-ebef-a03bdd83f75d@HIDDEN>
 <5ba2fec3-3f61-fb7e-35eb-7188fa6064a4@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.7 (/)
X-Debbugs-Envelope-To: 47408
Cc: 47408 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)

> From: fabrice nicol <fabrnicol@HIDDEN>
> Date: Sat, 27 Mar 2021 11:51:22 +0100
> 
> I'm sending a new patch for this Mercury feature request.

Thanks, I have some comments below.

> >From 50f3f9a0d46d11d0ac096f79f0d5aa1bc17b7920 Mon Sep 17 00:00:00 2001
> From: Fabrice Nicol <fabrnicol@HIDDEN>
> Date: Sat, 27 Mar 2021 10:16:44 +0100
> Subject: [PATCH] Fixed regressions caused by Objc/Mercury ambiguous file
>  extension .m.

Please accompany the changeset with a ChangeLog-style commit log
message, you can see the style we are using via "git log" and also
find some instructions in CONTRIBUTE.

>  .B \-V, \-\-version
>  Print the current version of the program (same as the version of the
>  emacs \fBetags\fP is shipped with).
> +.TP
> +.B \-, \-\-version
> +Print the current version of the program (same as the version of the
> +emacs \fBetags\fP is shipped with).

Copy/paste mistake? or why are you duplicating the --version
description?

> +.TP
> +.B \-M, \-\-no\-defines
> +For the Mercury programming language, tag both declarations and
> +definitions.  Declarations start a line with \fI:\-\fP optionally followed by a
> +quantifier over a variable (\fIsome [T]\fP or \fIall [T]\fP), then by
> +a builtin operator like \fIpred\fP or \fIfunc\fP.
> +Definitions are first rules of clauses, as in Prolog.
> +Implies \-\-language=mercury.
> +.TP
> +.B \-m, \-\-declarations
> +For the Mercury programming language, tag declarations as with \fB\-M\fP, but do not
> +tag definitions. Implies \-\-language=mercury.

This is not what Francesco Potortì suggested to do.  He suggested that
you use the existing options --no-defines and --declarations, but give
them Mercury-specific meanings when processing Mercury source files.
IOW, let's not introduce the new -m and -M shorthands for these options,
and let's describe the Mercury-specific meaning of the existing
options where they are currently described in etags.1.  OK?

> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -93,6 +93,15 @@ useful on systems such as FreeBSD which ships only with "etc/termcap".
>  
>  * Changes in Emacs 28.1
>  
> +---
   ^^^
This should be "+++", since you submitted the changes for the
documentation as part of the changeset.

> +** Etags support for the Mercury programming language (https://mercurylang.org).
> +** New etags command line options '-M/-m' or --declarations/--no-defines'.
> +Tags all Mercury declarations.  For compatibility with Prolog etags support,
> +predicates and functions appearing first in clauses will be tagged if etags is
> +run with the option '-M' or '--declarations'.  If run with '-m' or
> +'--no-defines', declarations will be tagged but definitions will not.
> +Both options imply --language=mercury.

This should be amended for the changes in the options I described
above.

> +/* Define MERCURY_HEURISTICS_RATIO as it was necessary to disambiguate
> +   Mercury from Objective C, which have same file extensions .m */

This comment should explain how the value is used to disambiguate, so
that people could decide what alternative value to use.

> +static void test_objc_is_mercury(char *, language **);
                                  ^^
Our style is to leave one space between the function's name and the
opening parenthesis.  Please follow that here and elsewhere in your
patch.

> @@ -621,7 +629,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
>  "In Java code, all the tags constructs of C and C++ code are\n\
>  tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
>  
> -
>  static const char *Cobol_suffixes [] =
>    { "COB", "cob", NULL };
>  static char Cobol_help [] =

Why remove this empty line?

>  static const char *Objc_suffixes [] =
> -  { "lm",			/* Objective lex file */
> -    "m",			/* Objective C file */
> -     NULL };
> +  {"lm",
> +   "m",  /* By default, Objective C will be assumed. */
> +   NULL};

This loses the explanation that a .lm file is an ObjC lex file.

> @@ -773,7 +792,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
>  'TEXTAGS' to a colon-separated list like, for example,\n\
>       TEXTAGS=\"mycommand:myothercommand\".";
>  
> -
>  static const char *Texinfo_suffixes [] =
>    { "texi", "texinfo", "txi", NULL };
>  static const char Texinfo_help [] =

Again, an empty line removed -- why?

> +  puts ("-m, --declarations\n\
> +        For the Mercury programming language, only tag declarations.\n\
> +	Declarations start a line with :- \n\
> +        Implies --language=mercury.");
> +
> +  puts ("-M, --no-defines\n\
> +        For the Mercury programming language, include both declarations and\n\
> +	definitions.  Declarations start a line with :- while definitions\n\
> +	are first rules for a given item, as for Prolog.\n\
> +        Implies --language=mercury.");
> +

This should be merged with the existing description of the long
options.

>    /* When the optstring begins with a '-' getopt_long does not rearrange the
>       non-options arguments to be at the end, but leaves them alone. */
> -  optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH",
> +  optstring = concat ("-ac:Cf:Il:Mmo:Qr:RSVhHW",
>  		      (CTAGS) ? "BxdtTuvw" : "Di:",
>  		      "");

As mentioned, let's not introduce -m and -M.

> +      case 'M':
> +	with_mercury_definitions = true; FALLTHROUGH;
> +      case 'm':
> +	{
> +	  language lang =
> +	    { "mercury", Mercury_help, Mercury_functions, Mercury_suffixes };
> +
> +	  argbuffer[current_arg].lang = &lang;
> +	  argbuffer[current_arg].arg_type = at_language;
> +	}
> +	break;

Shouldn't be needed anymore.

>  	/* Etags options */
> -      case 'D': constantypedefs = false;			break;
> +      case 'D': constantypedefs = false;                        break;

This whitespace change is for the worse: our conventions are to use
mixed spaces-with-tabs style for indentation in C source files, not
just spaces.

> +static void test_objc_is_mercury(char *this_file, language **lang)

Our style is to write function definitions like this:

static void
test_objc_is_mercury (char *this_file, language **lang)

IOW, break the line between the return type and the function's name.

> +  FILE* fp = fopen(this_file, "r");
> +  if (fp == NULL) return;

No error/warning if the file couldn't be open?

In any case, this leaks a FILE object: you open a file, but never
close it.

> +  uint64_t lines = 1;
> +  uint64_t mercury_decls = 0;

We don't use such types elsewhere in etags.c; why do you need them
here?  can you use intmax_t instead, as we do elsewhere?

> +	case  '%': FALLTHROUGH;
> +        case  ' ': FALLTHROUGH;
> +        case '\t':
> +	  start_of_line = false;

FALLTHROUGH isn't needed here, as there's no code under the first 2
'case' lines.

> +      /* Change the language from Objective C to Mercury */

Our style for comments is to end each comment with a period and 2
spaces, like this:

   /* Change the language from Objective C to Mercury.  */

Please follow this style, here and elsewhere in the changeset.

> +  uint8_t decl_type_length = pos - origpos;

Please use 'unsigned char' instead of uint8_t.

> +  if (( (s[len] == '.'  /* This is a statement dot, not a module dot. */
> +	 || (s[len] == '(' && (len += 1))
> +         || (s[len] == ':'  /* Stopping in case of a rule. */
> +	     && s[len + 1] == '-'
> +	     && (len += 2)))
> +	&& (lastlen != len || memcmp (s, last, len) != 0)
> +	)
> +      /* Types are often declared on several lines so keeping just
> +	 the first line */
> +      || is_mercury_type
> +      )

Please avoid parentheses alone on their lines.

> diff --git a/lisp/speedbar.el b/lisp/speedbar.el
> index 12e57b1108..63f3cd6ca1 100644
> --- a/lisp/speedbar.el
> +++ b/lisp/speedbar.el
> @@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
>       speedbar-parse-c-or-c++tag)
>      ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
>       "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
> +      ("^\\.m$\\'" .
> +     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
>  ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
>  ;      speedbar-parse-fortran77-tag)
>      ("\\.tex\\'" . speedbar-parse-tex-string)

What about ObjC here? or are these keywords good for ObjC as well?

Last, but not least: if you can, please provide a test file for the
etags test suite, see test/manual/etags/.

Thanks again for working on this.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#47408; Package emacs. Full text available.

Message received at 47408 <at> debbugs.gnu.org:


Received: (at 47408) by debbugs.gnu.org; 27 Mar 2021 15:39:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 27 11:39:49 2021
Received: from localhost ([127.0.0.1]:44743 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1lQB2S-0005cC-Fo
	for submit <at> debbugs.gnu.org; Sat, 27 Mar 2021 11:39:49 -0400
Received: from mail-wm1-f47.google.com ([209.85.128.47]:40705)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <fabrnicol@HIDDEN>) id 1lQ6Ww-0002hG-Ma
 for 47408 <at> debbugs.gnu.org; Sat, 27 Mar 2021 06:51:00 -0400
Received: by mail-wm1-f47.google.com with SMTP id
 y124-20020a1c32820000b029010c93864955so6130070wmy.5
 for <47408 <at> debbugs.gnu.org>; Sat, 27 Mar 2021 03:50:58 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
 h=to:from:subject:message-id:date:user-agent:mime-version
 :content-language;
 bh=1qXB6CLllaOx/Ifp4Aco1zGgbQWqYPrr4sSfXEli/GA=;
 b=fifhjBHTnrSWNlTak8Q9PYqkyqiDtaww9Dguxje7XXcdv38kAcwgZzMxVTAO6+QQhn
 KNIQeeuqaaZKERfnzXOoTgb89qwm59y8vImZ5CoLTTWMxwu0A6aE6gZBQ77aWWB5Qks1
 OcXTWPo1gUGIwERLMjSsTBUfMUyrI4JBkXGcmdmvTzhWTiG7+kHM9jlH/9lDg5Zx+411
 jxnY7CSZCiws2Me0KcRn32IJqkqM15oZ8wIUZOWXeevU4OTvru0f8ydrjxJTqfOW5fQQ
 ZEpXBattbIyE3kENH2qfQrhEHPHZ4TjEhXB9DLbZPeHPeLfis4KOP7L6Hj1F+zAhX6+C
 wLbA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:to:from:subject:message-id:date:user-agent
 :mime-version:content-language;
 bh=1qXB6CLllaOx/Ifp4Aco1zGgbQWqYPrr4sSfXEli/GA=;
 b=avDN1PkR18mmYF/KQ1kV+TtB7VzSYPmOCcy1V4wmNSGFS5DFgsSl5bPzR2sGy4EXnW
 F5Vfrgg274GJ5ublWOhdZZDbJImZDVD+WPhO9HElmv7QX8MMk4pzebe6J7T2yFSeoxYI
 EYq+qX2FuzbqBMGrwdMK3yCV+iELVxvTbpEzPPSpDO2n5nGTQWc71skJPxckypWgY3TZ
 LrmUGNmkiorCensFGtV68J2/0GHQj9FPoqQv//iVXt+r4WQJsjYXZVn0OBehDcjTGyrc
 ONaJvbDSWUZrdvrErmN6CvoDooCRZ7D2fZ7jK4KU/P0LCp48wQtKn7vCY1xLpkf577az
 CZbQ==
X-Gm-Message-State: AOAM532ZgerlHcCTijaqoDppr4Bnhi04Qubo0m9GnAPOCE9xdJnKnbb1
 oxf1GMOT+nlyVJSxvV/p5BqQ1mzmHRs=
X-Google-Smtp-Source: ABdhPJzCifPzjiPqzc0L2+jjjG7KkY0BeP3lGIVuizRXOtzkjd5EihsHJz2vkdqlBgN0qCh+mr8A3Q==
X-Received: by 2002:a1c:c1:: with SMTP id 184mr9049991wma.143.1616842252567;
 Sat, 27 Mar 2021 03:50:52 -0700 (PDT)
Received: from ?IPv6:2a01:cb1d:88b9:5c00:7b73:7901:965e:8523?
 ([2a01:cb1d:88b9:5c00:7b73:7901:965e:8523])
 by smtp.gmail.com with ESMTPSA id l1sm17363939wrv.87.2021.03.27.03.50.51
 for <47408 <at> debbugs.gnu.org>
 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
 Sat, 27 Mar 2021 03:50:51 -0700 (PDT)
To: 47408 <at> debbugs.gnu.org
From: fabrice nicol <fabrnicol@HIDDEN>
Subject: Etags support for Mercury [v0.3]
Message-ID: <5ba2fec3-3f61-fb7e-35eb-7188fa6064a4@HIDDEN>
Date: Sat, 27 Mar 2021 11:51:22 +0100
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
 Thunderbird/78.8.1
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------CAE36B3A8BD255920925A15F"
Content-Language: en-US
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 47408
X-Mailman-Approved-At: Sat, 27 Mar 2021 11:39:47 -0400
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

This is a multi-part message in MIME format.
--------------CAE36B3A8BD255920925A15F
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

I'm sending a new patch for this Mercury feature request.

The attached patch fixes a previously unnoticed regression that affects 
Objective C parsing (Mercury and Objective C have same file extensions .m).

I had to resort to an added heuristics (implemented in 
`test_objc_is_mercury') to disambiguate Mercury from Objective C source 
files with extension .m.

The patch is cumulative and replaces the former one.

Best,

Fabrice Nicol


--------------CAE36B3A8BD255920925A15F
Content-Type: text/x-patch; charset=UTF-8;
 name="0001-Fixed-regressions-caused-by-Objc-Mercury-ambiguous-f.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0001-Fixed-regressions-caused-by-Objc-Mercury-ambiguous-f.pa";
 filename*1="tch"

From 50f3f9a0d46d11d0ac096f79f0d5aa1bc17b7920 Mon Sep 17 00:00:00 2001
From: Fabrice Nicol <fabrnicol@HIDDEN>
Date: Sat, 27 Mar 2021 10:16:44 +0100
Subject: [PATCH] Fixed regressions caused by Objc/Mercury ambiguous file
 extension .m.

---
 doc/man/etags.1  |  25 ++-
 etc/NEWS         |   9 +
 lib-src/etags.c  | 444 ++++++++++++++++++++++++++++++++++++++++++++---
 lisp/speedbar.el |   2 +
 4 files changed, 455 insertions(+), 25 deletions(-)

diff --git a/doc/man/etags.1 b/doc/man/etags.1
index c5c15fb182..903e38a145 100644
--- a/doc/man/etags.1
+++ b/doc/man/etags.1
@@ -1,5 +1,5 @@
 .\" See section COPYING for copyright and redistribution information.
-.TH ETAGS 1 "2019-06-24" "GNU Tools" "GNU"
+.TH ETAGS 1 "2021-03-25" "GNU Tools" "GNU"
 .de BP
 .sp
 .ti -.2i
@@ -50,9 +50,9 @@ format understood by
 .BR vi ( 1 )\c
 \&.  Both forms of the program understand
 the syntax of C, Objective C, C++, Java, Fortran, Ada, Cobol, Erlang,
-Forth, Go, HTML, LaTeX, Emacs Lisp/Common Lisp, Lua, Makefile, Pascal, Perl,
-Ruby, PHP, PostScript, Python, Prolog, Scheme and
-most assembler\-like syntaxes.
+Forth, Go, HTML, LaTeX, Emacs Lisp/Common Lisp, Lua, Makefile, Mercury, Pascal,
+Perl, Ruby, PHP, PostScript, Python, Prolog, Scheme and most assembler\-like
+syntaxes.
 Both forms read the files specified on the command line, and write a tag
 table (defaults: \fBTAGS\fP for \fBetags\fP, \fBtags\fP for
 \fBctags\fP) in the current working directory.
@@ -270,6 +270,23 @@ prints detailed information about how tags are created for LANG.
 .B \-V, \-\-version
 Print the current version of the program (same as the version of the
 emacs \fBetags\fP is shipped with).
+.TP
+.B \-, \-\-version
+Print the current version of the program (same as the version of the
+emacs \fBetags\fP is shipped with).
+.TP
+.B \-M, \-\-no\-defines
+For the Mercury programming language, tag both declarations and
+definitions.  Declarations start a line with \fI:\-\fP optionally followed by a
+quantifier over a variable (\fIsome [T]\fP or \fIall [T]\fP), then by
+a builtin operator like \fIpred\fP or \fIfunc\fP.
+Definitions are first rules of clauses, as in Prolog.
+Implies \-\-language=mercury.
+.TP
+.B \-m, \-\-declarations
+For the Mercury programming language, tag declarations as with \fB\-M\fP, but do not
+tag definitions. Implies \-\-language=mercury.
+
 
 .SH "SEE ALSO"
 "\|\fBemacs\fP\|" entry in \fBinfo\fP; \fIGNU Emacs Manual\fP, Richard
diff --git a/etc/NEWS b/etc/NEWS
index 68812c64cc..4af4e76371 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -93,6 +93,15 @@ useful on systems such as FreeBSD which ships only with "etc/termcap".
 
 * Changes in Emacs 28.1
 
+---
+** Etags support for the Mercury programming language (https://mercurylang.org).
+** New etags command line options '-M/-m' or --declarations/--no-defines'.
+Tags all Mercury declarations.  For compatibility with Prolog etags support,
+predicates and functions appearing first in clauses will be tagged if etags is
+run with the option '-M' or '--declarations'.  If run with '-m' or
+'--no-defines', declarations will be tagged but definitions will not.
+Both options imply --language=mercury.
+
 +++
 ** New command 'font-lock-update', bound to 'C-x x f'.
 This command updates the syntax highlighting in this buffer.
diff --git a/lib-src/etags.c b/lib-src/etags.c
index b5c18e0e01..53e04794dd 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -142,7 +142,13 @@ Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2021 Free Software
 # define CTAGS false
 #endif
 
-/* Copy to DEST from SRC (containing LEN bytes), and append a NUL byte.  */
+/* Define MERCURY_HEURISTICS_RATIO as it was necessary to disambiguate
+   Mercury from Objective C, which have same file extensions .m */
+#ifndef  MERCURY_HEURISTICS_RATIO
+# define MERCURY_HEURISTICS_RATIO 0.02
+#endif
+
+/* COPY to DEST from SRC (containing LEN bytes), and append a NUL byte.  */
 static void
 memcpyz (void *dest, void const *src, ptrdiff_t len)
 {
@@ -359,6 +365,7 @@ #define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
 static void Lisp_functions (FILE *);
 static void Lua_functions (FILE *);
 static void Makefile_targets (FILE *);
+static void Mercury_functions (FILE *);
 static void Pascal_functions (FILE *);
 static void Perl_functions (FILE *);
 static void PHP_functions (FILE *);
@@ -378,6 +385,7 @@ #define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
 static bool nocase_tail (const char *);
 static void get_tag (char *, char **);
 static void get_lispy_tag (char *);
+static void test_objc_is_mercury(char *, language **);
 
 static void analyze_regex (char *);
 static void free_regexps (void);
@@ -621,7 +629,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 "In Java code, all the tags constructs of C and C++ code are\n\
 tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
 
-
 static const char *Cobol_suffixes [] =
   { "COB", "cob", NULL };
 static char Cobol_help [] =
@@ -683,10 +690,22 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 "In makefiles, targets are tags; additionally, variables are tags\n\
 unless you specify '--no-globals'.";
 
+/* Mercury and Objective C share the same .m file extensions. */
+static const char *Mercury_suffixes [] =
+  {"m", /* Use option -l mercury to switch from Objective C to Mercury. */
+   NULL};
+static const char Mercury_help [] =
+  "In Mercury code, tags are all declarations beginning a line with :-\n\
+and optionally Prolog-like definitions (first rule for a predicate or \
+function).\n\
+To enable this behavior, run etags using -M or --declarations.";
+static bool with_mercury_definitions = false;
+double mercury_heuristics_ratio = MERCURY_HEURISTICS_RATIO;
+
 static const char *Objc_suffixes [] =
-  { "lm",			/* Objective lex file */
-    "m",			/* Objective C file */
-     NULL };
+  {"lm",
+   "m",  /* By default, Objective C will be assumed. */
+   NULL};
 static const char Objc_help [] =
 "In Objective C code, tags include Objective C definitions for classes,\n\
 class categories, methods and protocols.  Tags for variables and\n\
@@ -773,7 +792,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 'TEXTAGS' to a colon-separated list like, for example,\n\
      TEXTAGS=\"mycommand:myothercommand\".";
 
-
 static const char *Texinfo_suffixes [] =
   { "texi", "texinfo", "txi", NULL };
 static const char Texinfo_help [] =
@@ -824,7 +842,9 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
   { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
   { "lua",       Lua_help,Lua_functions,Lua_suffixes,NULL,Lua_interpreters},
   { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
+  /* objc listed before mercury as it is a better default for .m extensions. */
   { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
+  { "mercury",   Mercury_help,   Mercury_functions, Mercury_suffixes   },
   { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
   { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
   { "php",       PHP_help,       PHP_functions,     PHP_suffixes       },
@@ -1061,6 +1081,17 @@ print_help (argument *argbuffer)
         which you like.");
     }
 
+  puts ("-m, --declarations\n\
+        For the Mercury programming language, only tag declarations.\n\
+	Declarations start a line with :- \n\
+        Implies --language=mercury.");
+
+  puts ("-M, --no-defines\n\
+        For the Mercury programming language, include both declarations and\n\
+	definitions.  Declarations start a line with :- while definitions\n\
+	are first rules for a given item, as for Prolog.\n\
+        Implies --language=mercury.");
+
   puts ("-V, --version\n\
         Print the version of the program.\n\
 -h, --help\n\
@@ -1111,7 +1142,7 @@ main (int argc, char **argv)
 
   /* When the optstring begins with a '-' getopt_long does not rearrange the
      non-options arguments to be at the end, but leaves them alone. */
-  optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH",
+  optstring = concat ("-ac:Cf:Il:Mmo:Qr:RSVhHW",
 		      (CTAGS) ? "BxdtTuvw" : "Di:",
 		      "");
 
@@ -1202,9 +1233,20 @@ main (int argc, char **argv)
       case 'Q':
 	class_qualify = 1;
 	break;
+      case 'M':
+	with_mercury_definitions = true; FALLTHROUGH;
+      case 'm':
+	{
+	  language lang =
+	    { "mercury", Mercury_help, Mercury_functions, Mercury_suffixes };
+
+	  argbuffer[current_arg].lang = &lang;
+	  argbuffer[current_arg].arg_type = at_language;
+	}
+	break;
 
 	/* Etags options */
-      case 'D': constantypedefs = false;			break;
+      case 'D': constantypedefs = false;                        break;
       case 'i': included_files[nincluded_files++] = optarg;	break;
 
 	/* Ctags options. */
@@ -1298,19 +1340,19 @@ main (int argc, char **argv)
 	  analyze_regex (argbuffer[i].what);
 	  break;
 	case at_filename:
-	      this_file = argbuffer[i].what;
-	      /* Input file named "-" means read file names from stdin
-		 (one per line) and use them. */
-	      if (streq (this_file, "-"))
-		{
-		  if (parsing_stdin)
-		    fatal ("cannot parse standard input "
-			   "AND read file names from it");
-		  while (readline_internal (&filename_lb, stdin, "-") > 0)
-		    process_file_name (filename_lb.buffer, lang);
-		}
-	      else
-		process_file_name (this_file, lang);
+	  this_file = argbuffer[i].what;
+	  /* Input file named "-" means read file names from stdin
+	     (one per line) and use them. */
+	  if (streq (this_file, "-"))
+	    {
+	      if (parsing_stdin)
+		fatal ("cannot parse standard input "
+		       "AND read file names from it");
+	      while (readline_internal (&filename_lb, stdin, "-") > 0)
+		process_file_name (filename_lb.buffer, lang);
+	    }
+	  else
+	    process_file_name (this_file, lang);
 	  break;
         case at_stdin:
           this_file = argbuffer[i].what;
@@ -1775,6 +1817,11 @@ find_entries (FILE *inf)
   if (parser == NULL)
     {
       lang = get_language_from_filename (curfdp->infname, true);
+
+      /* Disambiguate file names between Objc and Mercury */
+      if (lang != NULL && strcmp(lang->name, "objc") == 0)
+	test_objc_is_mercury(curfdp->infname, &lang);
+
       if (lang != NULL && lang->function != NULL)
 	{
 	  curfdp->lang = lang;
@@ -6019,6 +6066,361 @@ prolog_atom (char *s, size_t pos)
     return 0;
 }
 
+
+/*
+ * Support for Mercury
+ *
+ * Assumes that the declarationa starts at column 0.
+ * Original code by Sunichirou Sugou (1989) for Prolog.
+ * Rewritten by Anders Lindgren (1996) for Prolog.
+ * Adapted by Fabrice Nicol (2021) for Mercury.
+ * Note: Prolog-support behavior is preserved if
+ * -M/--declarations is used, corresponding to
+ * with_mercury_definitions=true.
+ */
+
+static ptrdiff_t mercury_pr (char *, char *, ptrdiff_t);
+static void mercury_skip_comment (linebuffer *, FILE *);
+static bool is_mercury_type = false;
+static bool is_mercury_quantifier = false;
+static bool is_mercury_declaration = false;
+
+/* To robustly disambiguate between Objective C and Mercury, parse file
+   with the following heuristics hook:
+   (number of occurrences of non-blank, non-fully-commented lines
+   comprising  ':-' at the start of line)/ number of lines > mercury_heuristics_ratio */
+
+static void test_objc_is_mercury(char *this_file, language **lang)
+{
+  if (this_file == NULL) return;
+  FILE* fp = fopen(this_file, "r");
+  if (fp == NULL) return;
+  int c;
+  uint64_t lines = 1;
+  uint64_t mercury_decls = 0;
+  bool blank_line = false;
+  bool start_of_line = true;
+
+  while ((c = fgetc(fp)) != EOF)
+    {
+      switch (c)
+	{
+	case '\n':
+	  if (! blank_line) ++lines;
+	  blank_line = true;
+	  start_of_line = true;
+	  break;
+	case  '%': FALLTHROUGH;
+        case  ' ': FALLTHROUGH;
+        case '\t':
+	  start_of_line = false;
+	  break;
+        case ':':
+	  if (! start_of_line) break;
+	  start_of_line = false;
+	  c = fgetc(fp);
+	  if (c == '-') ++mercury_decls;
+	  break;
+	default:
+	  start_of_line = false;
+	  blank_line = false;
+	}
+    }
+
+  double ratio = 0;
+  ratio = ((double) mercury_decls ) / lines;
+  if (ratio > mercury_heuristics_ratio)
+    {
+      /* Change the language from Objective C to Mercury */
+      static language lang0 = { "mercury", Mercury_help, Mercury_functions,
+				Mercury_suffixes };
+      *lang = &lang0;
+    }
+}
+
+static void
+Mercury_functions (FILE *inf)
+{
+  char *cp, *last = NULL;
+  ptrdiff_t lastlen = 0, allocated = 0;
+  if (declarations) with_mercury_definitions = true;
+
+  LOOP_ON_INPUT_LINES (inf, lb, cp)
+    {
+      if (cp[0] == '\0')   /* Empty line */
+	continue;
+      else if (c_isspace (cp[0]) || cp[0] == '%')
+	/*  a Prolog-type comment or anything other than a declaration */
+	continue;
+      else if (cp[0] == '/' && cp[1] == '*')  /* Mercury C-type comment. */
+        mercury_skip_comment (&lb, inf);
+      else
+	{
+	  is_mercury_declaration = (cp[0] == ':' && cp[1] == '-');
+
+          if (is_mercury_declaration
+	      || with_mercury_definitions)
+	    {
+	      ptrdiff_t len = mercury_pr (cp, last, lastlen);
+	      if (0 < len)
+		{
+		  /* Store the declaration to avoid generating duplicate
+		     tags later.  */
+		  if (allocated <= len)
+		    {
+		      xrnew (last, len + 1, 1);
+		      allocated = len + 1;
+		    }
+		  memcpyz (last, cp, len);
+		  lastlen = len;
+		}
+	    }
+	}
+    }
+  free (last);
+}
+
+static void
+mercury_skip_comment (linebuffer *plb, FILE *inf)
+{
+  char *cp;
+
+  do
+    {
+      for (cp = plb->buffer; *cp != '\0'; ++cp)
+	if (cp[0] == '*' && cp[1] == '/')
+	  return;
+      readline (plb, inf);
+    }
+  while (perhaps_more_input (inf));
+}
+
+/*
+ * A declaration is added if it matches:
+ *     <beginning of line>:-<whitespace><Mercury Term><whitespace>(
+ * If with_mercury_definitions == true, we also add:
+ *     <beginning of line><Mercury item><whitespace>(
+ * or  <beginning of line><Mercury item><whitespace>:-
+ * As for Prolog support, different arities and types are not taken into
+ * consideration.
+ * Item is added to the tags database if it doesn't match the
+ * name of the previous declaration.
+ *
+ * Consume a Mercury declaration.
+ * Return the number of bytes consumed, or 0 if there was an error.
+ *
+ * A Mercury declaration must be one of:
+ *  :- type
+ *  :- solver type
+ *  :- pred
+ *  :- func
+ *  :- inst
+ *  :- mode
+ *  :- typeclass
+ *  :- instance
+ *  :- pragma
+ *  :- promise
+ *  :- initialise
+ *  :- finalise
+ *  :- mutable
+ *  :- module
+ *  :- interface
+ *  :- implementation
+ *  :- import_module
+ *  :- use_module
+ *  :- include_module
+ *  :- end_module
+ * followed on the same line by an alphanumeric sequence, starting with a lower
+ * case letter or by a single-quoted arbitrary string.
+ * Single quotes can escape themselves.  Backslash quotes everything.
+ *
+ * Return the size of the name of the declaration or 0 if no header was found.
+ * As quantifiers may precede functions or predicates, we must list them too.
+ */
+
+static const char *Mercury_decl_tags[] = {"type", "solver type", "pred",
+  "func", "inst", "mode", "typeclass", "instance", "pragma", "promise",
+  "initialise", "finalise", "mutable", "module", "interface", "implementation",
+  "import_module", "use_module", "include_module", "end_module", "some", "all"};
+
+static size_t
+mercury_decl (char *s, size_t pos)
+{
+  if (s == NULL) return 0;
+
+  size_t origpos;
+  origpos = pos;
+
+  while (s + pos != NULL && (c_isalnum (s[pos]) || s[pos] == '_')) ++pos;
+
+  uint8_t decl_type_length = pos - origpos;
+  char buf[decl_type_length + 1];
+  memset(buf, 0, decl_type_length + 1);
+
+  /* Mercury declaration tags.  Consume them, then check the declaration item
+     following :- is legitimate, then go on as in the prolog case. */
+
+  memcpy(buf, &s[origpos], decl_type_length);
+
+  bool found_decl_tag = false;
+
+  if (is_mercury_quantifier)
+    {
+      if (strcmp(buf, "pred") != 0 && strcmp(buf, "func") != 0) /* Bad syntax */
+	return 0;
+      is_mercury_quantifier = false; /* Beset to base value. */
+      found_decl_tag = true;
+    }
+  else
+    {
+      for (int j = 0; j < sizeof(Mercury_decl_tags)/sizeof(char*); ++j)
+	{
+	  if (strcmp(buf, Mercury_decl_tags[j]) == 0)
+	    {
+	      found_decl_tag = true;
+	      if (strcmp(buf, "type") == 0)
+		is_mercury_type = true;
+
+	      if (strcmp(buf, "some") == 0
+		  || strcmp(buf, "all") == 0) {
+		is_mercury_quantifier = true;
+	      }
+
+	      break;  /* Found declaration tag of rank j. */
+	    }
+	  else
+	    /* 'solver type' has a blank in the middle,
+	       so this is the hard case */
+	    if (strcmp(buf, "solver") == 0)
+	      {
+		++pos;
+		while (s + pos != NULL && (c_isalnum (s[pos]) || s[pos] == '_'))
+		  ++pos;
+
+		decl_type_length = pos - origpos;
+		char buf2[decl_type_length + 1];
+		memset(buf2, 0, decl_type_length + 1);
+		memcpy(buf2, &s[origpos], decl_type_length);
+
+		if (strcmp(buf2, "solver type") == 0)
+		  {
+		    found_decl_tag = false;
+		    break;  /* Found declaration tag of rank j. */
+		  }
+	      }
+	}
+    }
+
+  /* If with_mercury_definitions == false
+   * this is a Mercury syntax error, ignoring... */
+
+  if (with_mercury_definitions)
+    {
+      if (found_decl_tag)
+	pos = skip_spaces (s + pos) - s; /* Skip len blanks again */
+      else
+	/* Prolog-like behavior
+	 * we have parsed the predicate once, yet inappropriately
+	 * so restarting again the parsing step */
+	pos = 0;
+    }
+  else
+    {
+      if (found_decl_tag)
+	pos = skip_spaces (s + pos) - s; /* Skip len blanks again */
+      else
+	return 0;
+    }
+
+  /* From now on it is the same as for Prolog except for module dots */
+
+  if (c_islower (s[pos]) || s[pos] == '_' )
+    {
+      /* The name is unquoted.
+         Do not confuse module dots with end-of-declaration dots. */
+
+      while (c_isalnum (s[pos])
+             || s[pos] == '_'
+             || (s[pos] == '.' /* A module dot */
+                 && s + pos + 1 != NULL
+                 && (c_isalnum (s[pos + 1]) || s[pos + 1] == '_')))
+	++pos;
+
+      return pos - origpos;
+    }
+  else if (s[pos] == '\'')
+    {
+      ++pos;
+      for (;;)
+	{
+	  if (s[pos] == '\'')
+	    {
+	      ++pos;
+	      if (s[pos] != '\'')
+		break;
+	      ++pos; /* A double quote */
+	    }
+	  else if (s[pos] == '\0')  /* Multiline quoted atoms are ignored. */
+	    return 0;
+	  else if (s[pos] == '\\')
+	    {
+	      if (s[pos+1] == '\0')
+		return 0;
+	      pos += 2;
+	    }
+	  else
+	    ++pos;
+	}
+      return pos - origpos;
+    }
+  else if (is_mercury_quantifier && s[pos] == '[')   /* :- some [T] pred/func */
+    {
+      for (++pos; s + pos != NULL && s[pos] != ']'; ++pos) {}
+      if (s + pos == NULL) return 0;
+      ++pos;
+      pos = skip_spaces (s + pos) - s;
+      return mercury_decl(s, pos) + pos - origpos;
+    }
+  else
+    return 0;
+}
+
+static ptrdiff_t
+mercury_pr (char *s, char *last, ptrdiff_t lastlen)
+{
+  size_t len0 = 0;
+  is_mercury_type = false;
+  is_mercury_quantifier = false;
+
+  if (is_mercury_declaration)
+    {
+      /* Skip len0 blanks only for declarations. */
+      len0 = skip_spaces (s + 2) - s;
+    }
+
+  size_t len = mercury_decl (s , len0);
+  if (len == 0) return 0;
+  len += len0;
+
+  if (( (s[len] == '.'  /* This is a statement dot, not a module dot. */
+	 || (s[len] == '(' && (len += 1))
+         || (s[len] == ':'  /* Stopping in case of a rule. */
+	     && s[len + 1] == '-'
+	     && (len += 2)))
+	&& (lastlen != len || memcmp (s, last, len) != 0)
+	)
+      /* Types are often declared on several lines so keeping just
+	 the first line */
+      || is_mercury_type
+      )
+    {
+      make_tag (s, 0, true, s, len, lineno, linecharno);
+      return len;
+    }
+
+  return 0;
+}
+
 
 /*
  * Support for Erlang
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index 12e57b1108..63f3cd6ca1 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
      speedbar-parse-c-or-c++tag)
     ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
      "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
+      ("^\\.m$\\'" .
+     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
 ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
 ;      speedbar-parse-fortran77-tag)
     ("\\.tex\\'" . speedbar-parse-tex-string)
-- 
2.26.3


--------------CAE36B3A8BD255920925A15F--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#47408; Package emacs. Full text available.
Added tag(s) patch. Request was from Lars Ingebrigtsen <larsi@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 26 Mar 2021 08:27:10 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Mar 26 04:27:10 2021
Received: from localhost ([127.0.0.1]:40321 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1lPhoC-0004i2-L7
	for submit <at> debbugs.gnu.org; Fri, 26 Mar 2021 04:27:10 -0400
Received: from lists.gnu.org ([209.51.188.17]:51940)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <fabrnicol@HIDDEN>) id 1lPgat-0000hV-NO
 for submit <at> debbugs.gnu.org; Fri, 26 Mar 2021 03:09:21 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:47074)
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <fabrnicol@HIDDEN>)
 id 1lPgat-0000qV-IQ
 for bug-gnu-emacs@HIDDEN; Fri, 26 Mar 2021 03:09:19 -0400
Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]:42653)
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <fabrnicol@HIDDEN>)
 id 1lPgap-00034r-Ui
 for bug-gnu-emacs@HIDDEN; Fri, 26 Mar 2021 03:09:19 -0400
Received: by mail-wr1-x42d.google.com with SMTP id x13so4577288wrs.9
 for <bug-gnu-emacs@HIDDEN>; Fri, 26 Mar 2021 00:09:15 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
 h=subject:references:to:from:message-id:date:user-agent:mime-version
 :in-reply-to:content-language;
 bh=qK74/CctGBCnCxq8MW26S3AJQV/Z+/US3sVJhRJws+I=;
 b=nsCx4/zn54AyOhBmm7d64xDG3OtQMUsmnlNfLBLiR+w4XL5AwZdA+BKpPNBg9uy2p3
 EtLs1d7ntVMvzhtSSi8BvfnPkw35HEcdbh5L6O5zbzN4HGRbgaQSxKMNL/BXpyuCK6MV
 3eZEk+QQVdDBmnXHcncRBF0oKnymOkGW/zX/h9rJi0oTiHPR8KjHYmlHCdOLWdqpCuOT
 Sosu49m3aijVtGS3hpYmGmABBOXVA1ckwVLVprxo8S7iofZ+iHSUsL/0yQ54Gtq0nf+S
 Anl6CahxYOed73RqR5Nmc3iejWrp5HN5KuqO7ybwoeOtgzajlVP0zwbTnrJW5Q7FDai8
 oM7w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:subject:references:to:from:message-id:date
 :user-agent:mime-version:in-reply-to:content-language;
 bh=qK74/CctGBCnCxq8MW26S3AJQV/Z+/US3sVJhRJws+I=;
 b=OGKGq+qWwDAufSd+L3xJM3DofGxn7wNrZB+OrOwZVZkg/mHY5iyDGr/yr0VMEkSnQw
 5rbBZpAnDeiY+sImAtZaZQbbpEv6EZF4F/6rFymz4oCMeJI5EhtfXfAEZRhvRMZzFKTQ
 uLsWtta+V2mZnqubFPyJiI8FWNb6NMtk+9I+FpihtCSPr+ASXP7P9YFDMMnOaxaNoIwi
 ++I27AkjS2HHjlaMxaXs/9fZSMaU5ug2XkQLa2Gmnxs0ZOc/dQgx3TsKukVnigEdCO8l
 vj+QRNDYD5LJwiF1q/SY5ygK2Py8IsJlfDFqpsp5bGXRfq9rpqj5T4yYtZDIPZQ28LKl
 z3oQ==
X-Gm-Message-State: AOAM530hu8x75IsRBBCVpd06eFq39ZbnFred/IiuP7JKGTIEHsTnX7V8
 Fz+Haf1edxkLAnr1I8+9Nozg1EfjLLsLOA==
X-Google-Smtp-Source: ABdhPJy2DgbjgwnCjJFVe+yP8k+8vOtbho+d7zt/Ov5KBnu+F4k33XtgXBESzhPOT5CFFpOImo8aLw==
X-Received: by 2002:adf:f8cd:: with SMTP id f13mr12339415wrq.27.1616742553594; 
 Fri, 26 Mar 2021 00:09:13 -0700 (PDT)
Received: from ?IPv6:2a01:cb1d:88b9:5c00:7b73:7901:965e:8523?
 ([2a01:cb1d:88b9:5c00:7b73:7901:965e:8523])
 by smtp.gmail.com with ESMTPSA id m15sm10327619wrp.96.2021.03.26.00.09.12
 for <bug-gnu-emacs@HIDDEN>
 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
 Fri, 26 Mar 2021 00:09:13 -0700 (PDT)
Subject: Emacs etags support for Mercury [v0.2]
References: <25b8baef-11f2-7079-69d8-3207a24658fc@HIDDEN>
To: bug-gnu-emacs@HIDDEN
From: fabrice nicol <fabrnicol@HIDDEN>
X-Forwarded-Message-Id: <25b8baef-11f2-7079-69d8-3207a24658fc@HIDDEN>
Message-ID: <ccb782a9-e9bf-67f8-ebef-a03bdd83f75d@HIDDEN>
Date: Fri, 26 Mar 2021 08:09:40 +0100
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
 Thunderbird/78.8.1
MIME-Version: 1.0
In-Reply-To: <25b8baef-11f2-7079-69d8-3207a24658fc@HIDDEN>
Content-Type: multipart/mixed; boundary="------------19B5DC828F28B24BA12F4B1F"
Content-Language: en-US
Received-SPF: pass client-ip=2a00:1450:4864:20::42d;
 envelope-from=fabrnicol@HIDDEN; helo=mail-wr1-x42d.google.com
X-Spam_score_int: -20
X-Spam_score: -2.1
X-Spam_bar: --
X-Spam_report: (-2.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,
 RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: -1.3 (-)
X-Debbugs-Envelope-To: submit
X-Mailman-Approved-At: Fri, 26 Mar 2021 04:27:06 -0400
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.3 (--)

This is a multi-part message in MIME format.
--------------19B5DC828F28B24BA12F4B1F
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit

Hi,

As a follow-up to my previous threads on the Emacs devel list (see 
below), I am now submitting a revised patch that takes into account 
suggestions from two devel-list members (and adds in support for 
declarations with variable quantifiers over predicates and functions).

I also consulted members from the Mercury devel list 
(reviews-request@HIDDEN). Although they did not go into 
the 'etags' code, as they mostly use Vim, the overall design does seem 
to meet approval there.

The patch proposes adding two options to 'etags', namely 
-M/--declarations and -m/--no-defines.
As explained in my prior threads, this is justified by the fact that 
Mercury is derived from Prolog. It is not unusual to have to port Prolog 
code into Mercury.
Yet Emacs 'etags' Prolog support is quite different, as Prolog has no 
types or declarations, so predicates appearing first in clauses are 
tagged as a workaround in Prolog 'etags' support.
Unlike Prolog, Mercury has declarations, which should be tagged in 
priority (this is the community consensus). But preserving some sort of 
backward compatibility with Prolog may be quite useful for porting 
purposes, notably.
There is no clean way to achieve this without adding at least one extra 
option to 'etags' (with an argument), or two options without argument, 
which I personally find clearer.

Regarding tests, the following link to source code from the Mercury 
compiler has (almost) all the possible use cases:
https://raw.githubusercontent.com/Mercury-Language/mercury/master/library/array.m

Thanks in advance for considering this submission.
Fabrice Nicol

Message-Id: <E1lOzjX-00GjV8-Hj@HIDDEN>

> You will note an unconventional move. I was daring enough to add two 
> options to 'etags' (-m and -M) to implement some kind of backward 
> compatibility with Prolog etags support (based on tagging definitions, 
> -M) while allowing a simpler, more idiomatic approach that focuses on 
> tagging Mercury declarations only (-m).  Backward compatibility is 
> legitimate and quite useful, but having it on board all the time may 
> be cumbersome for some use cases.  Hence the 'behavioral' options I added.

I fear this is too intrusive, but easy to amend.

Instead of -M, you should use --declarations

Instead of -m, you should use --no-defines

In both cases, the description of the options should be augmented with
their Mercury use.

-------------------------

In-Reply-To: <b9e2c35c-ba8f-5114-031f-36f580ae994e@HIDDEN>
Content-Type: multipart/mixed;
boundary="------------7AF01A37602B0D491A3765DF"
Content-Language: en-US

This is a multi-part message in MIME format.
--------------7AF01A37602B0D491A3765DF
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit

As a follow-up to my message of March 22, I would appreciate to get some
feedback on the attached patch implementing Mercury support for 'etags'
before considering a formal submission.

You will note an unconventional move.  I was daring enough to add two
options to 'etags' (-m and -M) to implement some kind of backward
compatibility with Prolog etags support (based on tagging definitions,
-M) while allowing a simpler, more idiomatic approach that focuses on
tagging  Mercury declarations only (-m).  Backward compatibility is
legitimate and quite useful, but having it on board all the time may be
cumbersome for some use cases.  Hence the 'behavioral' options I added.

Fabrice Nicol

------------------------

Date: Mon, 22 Mar 2021 19:23:33 +0200
Message-Id: <83y2ef9k6i.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
Cc: emacs-devel@HIDDEN
In-Reply-To: <b9e2c35c-ba8f-5114-031f-36f580ae994e@HIDDEN> (message from
fabrice nicol on Mon, 22 Mar 2021 03:02:03 +0100)
Subject: Re: etags support for the Mercury programming language
References: <b9e2c35c-ba8f-5114-031f-36f580ae994e@HIDDEN>

> Date: Mon, 22 Mar 2021 03:02:03 +0100
>
> I have been developing Emacs etags support for the Mercury 
> logic/functional programming language (https://mercurylang.org/), 
> based on the current code for Prolog support.
>
> Before proposing a patch for review, I would like to know if 
> (considering the limited audience) such a proposal stands a chance of 
> being accepted. All the changes are located in lib-src/etags.c (plus 
> two lines in lisp/speedbar.el).

Yes, I think support for additional languages in etags is always
welcome. But please also be sure to update the etags.1 man page with
the relevant information, and announce the addition in NEWS.

If the changes are substantial, we will need you to assign the
copyright for these changes to the FSF. Would you like to start the
legal paperwork rolling now? If so, I will send you the form to fill.

Thanks.





--------------19B5DC828F28B24BA12F4B1F
Content-Type: text/x-patch; charset=UTF-8;
 name="0001-Prepare-commit-for-submission-Mercury-etags-support.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0001-Prepare-commit-for-submission-Mercury-etags-support.pat";
 filename*1="ch"

From 03c7e5cfa23196b2e3a5564be87a8bbd01730f81 Mon Sep 17 00:00:00 2001
From: Fabrice Nicol <fabrnicol@HIDDEN>
Date: Fri, 26 Mar 2021 06:15:43 +0100
Subject: [PATCH] Prepare commit for submission [Mercury etags support]

---
 doc/man/etags.1  |  25 +++-
 etc/NEWS         |   9 ++
 lib-src/etags.c  | 371 +++++++++++++++++++++++++++++++++++++++++++++--
 lisp/speedbar.el |   2 +
 4 files changed, 394 insertions(+), 13 deletions(-)

diff --git a/doc/man/etags.1 b/doc/man/etags.1
index c5c15fb182..903e38a145 100644
--- a/doc/man/etags.1
+++ b/doc/man/etags.1
@@ -1,5 +1,5 @@
 .\" See section COPYING for copyright and redistribution information.
-.TH ETAGS 1 "2019-06-24" "GNU Tools" "GNU"
+.TH ETAGS 1 "2021-03-25" "GNU Tools" "GNU"
 .de BP
 .sp
 .ti -.2i
@@ -50,9 +50,9 @@ format understood by
 .BR vi ( 1 )\c
 \&.  Both forms of the program understand
 the syntax of C, Objective C, C++, Java, Fortran, Ada, Cobol, Erlang,
-Forth, Go, HTML, LaTeX, Emacs Lisp/Common Lisp, Lua, Makefile, Pascal, Perl,
-Ruby, PHP, PostScript, Python, Prolog, Scheme and
-most assembler\-like syntaxes.
+Forth, Go, HTML, LaTeX, Emacs Lisp/Common Lisp, Lua, Makefile, Mercury, Pascal,
+Perl, Ruby, PHP, PostScript, Python, Prolog, Scheme and most assembler\-like
+syntaxes.
 Both forms read the files specified on the command line, and write a tag
 table (defaults: \fBTAGS\fP for \fBetags\fP, \fBtags\fP for
 \fBctags\fP) in the current working directory.
@@ -270,6 +270,23 @@ prints detailed information about how tags are created for LANG.
 .B \-V, \-\-version
 Print the current version of the program (same as the version of the
 emacs \fBetags\fP is shipped with).
+.TP
+.B \-, \-\-version
+Print the current version of the program (same as the version of the
+emacs \fBetags\fP is shipped with).
+.TP
+.B \-M, \-\-no\-defines
+For the Mercury programming language, tag both declarations and
+definitions.  Declarations start a line with \fI:\-\fP optionally followed by a
+quantifier over a variable (\fIsome [T]\fP or \fIall [T]\fP), then by
+a builtin operator like \fIpred\fP or \fIfunc\fP.
+Definitions are first rules of clauses, as in Prolog.
+Implies \-\-language=mercury.
+.TP
+.B \-m, \-\-declarations
+For the Mercury programming language, tag declarations as with \fB\-M\fP, but do not
+tag definitions. Implies \-\-language=mercury.
+
 
 .SH "SEE ALSO"
 "\|\fBemacs\fP\|" entry in \fBinfo\fP; \fIGNU Emacs Manual\fP, Richard
diff --git a/etc/NEWS b/etc/NEWS
index 68812c64cc..f3455b341f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -93,6 +93,15 @@ useful on systems such as FreeBSD which ships only with "etc/termcap".
 
 * Changes in Emacs 28.1
 
+---
+** Etags support for the Mercury programming language (https://mercurylang.org).
+** New etags command line options '-M/-m' or --with-mercury-definitions/all'.
+Tags all Mercury declarations.  For compatibility with Prolog etags support,
+predicates and functions appearing first in clauses will be tagged if etags is
+run with the option '-M' or '--with-mercury-all'.  If run with '-m' or
+'--with-mercury-definitions', only declarations will be tagged.  Both options
+imply --language=mercury.
+
 +++
 ** New command 'font-lock-update', bound to 'C-x x f'.
 This command updates the syntax highlighting in this buffer.
diff --git a/lib-src/etags.c b/lib-src/etags.c
index b5c18e0e01..9019b619d4 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -359,6 +359,7 @@ #define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
 static void Lisp_functions (FILE *);
 static void Lua_functions (FILE *);
 static void Makefile_targets (FILE *);
+static void Mercury_functions (FILE *);
 static void Pascal_functions (FILE *);
 static void Perl_functions (FILE *);
 static void PHP_functions (FILE *);
@@ -502,6 +503,8 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
   { "ignore-case-regex",  required_argument, NULL,               'c'   },
   { "parse-stdin",        required_argument, NULL,               STDIN },
   { "version",            no_argument,       NULL,               'V'   },
+  { "with-mercury-all",   no_argument,       NULL,               'M'   },
+  { "with-mercury-definitions", no_argument, NULL,               'm'   },
 
 #if CTAGS /* Ctags options */
   { "backward-search",    no_argument,       NULL,               'B'   },
@@ -621,7 +624,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 "In Java code, all the tags constructs of C and C++ code are\n\
 tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
 
-
 static const char *Cobol_suffixes [] =
   { "COB", "cob", NULL };
 static char Cobol_help [] =
@@ -683,10 +685,21 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 "In makefiles, targets are tags; additionally, variables are tags\n\
 unless you specify '--no-globals'.";
 
+/* Mercury and Objective C share the same .m file extensions. */
+static const char *Mercury_suffixes [] =
+  {"m", /* Use option -l mercury to switch from Objective C to Mercury. */
+   NULL};
+static const char Mercury_help [] =
+  "In Mercury code, tags are all declarations beginning a line with :-\n\
+and optionally Prolog-like definitions (first rule for a predicate or \
+function).\n\
+To enable this behavior, run etags using --with-mercury-definitions.";
+static bool with_mercury_definitions = false;
+
 static const char *Objc_suffixes [] =
-  { "lm",			/* Objective lex file */
-    "m",			/* Objective C file */
-     NULL };
+  {"lm",
+   "m",  /* By default, Objective C will be assumed. */
+   NULL};
 static const char Objc_help [] =
 "In Objective C code, tags include Objective C definitions for classes,\n\
 class categories, methods and protocols.  Tags for variables and\n\
@@ -773,7 +786,6 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
 'TEXTAGS' to a colon-separated list like, for example,\n\
      TEXTAGS=\"mycommand:myothercommand\".";
 
-
 static const char *Texinfo_suffixes [] =
   { "texi", "texinfo", "txi", NULL };
 static const char Texinfo_help [] =
@@ -824,6 +836,7 @@ #define STDIN 0x1001		/* returned by getopt_long on --parse-stdin */
   { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
   { "lua",       Lua_help,Lua_functions,Lua_suffixes,NULL,Lua_interpreters},
   { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
+  { "mercury",   Mercury_help,   Mercury_functions, Mercury_suffixes   },
   { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
   { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
   { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
@@ -1061,6 +1074,17 @@ print_help (argument *argbuffer)
         which you like.");
     }
 
+  puts ("-m, --mercury-declarations\n\
+        For the Mercury programming language, only tag declarations.\n\
+	Declarations start a line with :- \n\
+        Implies --language=mercury.");
+
+  puts ("-M, --mercury-all\n\
+        For the Mercury programming language, include both declarations and\n\
+	definitions.  Declarations start a line with :- while definitions\n\
+	are first rules for a given item, as for Prolog.\n\
+        Implies --language=mercury.");
+
   puts ("-V, --version\n\
         Print the version of the program.\n\
 -h, --help\n\
@@ -1111,7 +1135,7 @@ main (int argc, char **argv)
 
   /* When the optstring begins with a '-' getopt_long does not rearrange the
      non-options arguments to be at the end, but leaves them alone. */
-  optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH",
+  optstring = concat ("-ac:Cf:Il:Mmo:Qr:RSVhHW",
 		      (CTAGS) ? "BxdtTuvw" : "Di:",
 		      "");
 
@@ -1202,6 +1226,17 @@ main (int argc, char **argv)
       case 'Q':
 	class_qualify = 1;
 	break;
+      case 'M':
+	with_mercury_definitions = true; FALLTHROUGH;
+      case 'm':
+	{
+	  language lang =
+	    { "mercury", Mercury_help, Mercury_functions, Mercury_suffixes };
+
+	  argbuffer[current_arg].lang = &lang;
+	  argbuffer[current_arg].arg_type = at_language;
+	}
+	break;
 
 	/* Etags options */
       case 'D': constantypedefs = false;			break;
@@ -1281,6 +1316,22 @@ main (int argc, char **argv)
 	pfatal (tagfile);
     }
 
+  /* /\* Settle the Mercury/Objective C file extension issue. *\/ */
+
+  /* if (parsing_mercury) */
+  /*   { */
+  /*     Objc_suffixes = */
+  /* 	{ "lm",			/\* Objective lex file *\/ */
+  /* 	  NULL };               /\* Remove .m from Obj_c identification. *\/ */
+  /*     Mercury_suffixes = {"m", NULL}; */
+  /*   } */
+  /* else */
+  /*   { */
+  /*     Objc_suffixes =           /\* Standard Objective C specification *\/ */
+  /* 	{"lm", "m", NULL}; */
+  /*     Mercury_suffixes = {NULL}; */
+  /*   } */
+
   /*
    * Loop through files finding functions.
    */
@@ -2297,7 +2348,7 @@ invalidate_nodes (fdesc *badfdp, node **npp)
     }
 }
 
-
+
 static ptrdiff_t total_size_of_entries (node *);
 static int number_len (intmax_t) ATTRIBUTE_CONST;
 
@@ -3222,7 +3273,7 @@ consider_token (char *str,	      /* IN: token pointer */
   return false;
 }
 
-
+
 /*
  * C_entries often keeps pointers to tokens or lines which are older than
  * the line currently read.  By keeping two line buffers, and switching
@@ -5890,7 +5941,8 @@ Prolog_functions (FILE *inf)
     {
       if (cp[0] == '\0')	/* Empty line */
 	continue;
-      else if (c_isspace (cp[0])) /* Not a predicate */
+      else if (c_isspace (cp[0]) || cp[0] == '%')
+	/* Not a predicate or comment */
 	continue;
       else if (cp[0] == '/' && cp[1] == '*')	/* comment. */
 	prolog_skip_comment (&lb, inf);
@@ -6019,6 +6071,307 @@ prolog_atom (char *s, size_t pos)
     return 0;
 }
 
+
+/*
+ * Support for Mercury
+ *
+ * Assumes that the declarationa starts at column 0.
+ * Original code by Sunichirou Sugou (1989) for Prolog.
+ * Rewritten by Anders Lindgren (1996) for Prolog.
+ * Adapted by Fabrice Nicol (2021) for Mercury.
+ * Note: Prolog-support behavior is preserved if
+ * --with-mercury-definitions is used, corresponding to
+ * with_mercury_definitions=true.
+ */
+
+static ptrdiff_t mercury_pr (char *, char *, ptrdiff_t);
+static void mercury_skip_comment (linebuffer *, FILE *);
+static bool is_mercury_type = false;
+static bool is_mercury_quantifier = false;
+static bool is_mercury_declaration = false;
+
+static void
+Mercury_functions (FILE *inf)
+{
+  char *cp, *last = NULL;
+  ptrdiff_t lastlen = 0, allocated = 0;
+
+  LOOP_ON_INPUT_LINES (inf, lb, cp)
+    {
+      if (cp[0] == '\0')   /* Empty line */
+	continue;
+      else if (c_isspace (cp[0]) || cp[0] == '%')
+	/*  a Prolog-type comment or anything other than a declaration */
+	continue;
+      else if (cp[0] == '/' && cp[1] == '*')  /* Mercury C-type comment. */
+        mercury_skip_comment (&lb, inf);
+      else
+	{
+	  is_mercury_declaration = (cp[0] == ':' && cp[1] == '-');
+
+          if (is_mercury_declaration
+	      || with_mercury_definitions)
+	    {
+	      ptrdiff_t len = mercury_pr (cp, last, lastlen);
+	      if (0 < len)
+		{
+		  /* Store the declaration to avoid generating duplicate
+		     tags later.  */
+		  if (allocated <= len)
+		    {
+		      xrnew (last, len + 1, 1);
+		      allocated = len + 1;
+		    }
+		  memcpyz (last, cp, len);
+		  lastlen = len;
+		}
+	    }
+	}
+    }
+  free (last);
+}
+
+static void
+mercury_skip_comment (linebuffer *plb, FILE *inf)
+{
+  char *cp;
+
+  do
+    {
+      for (cp = plb->buffer; *cp != '\0'; ++cp)
+	if (cp[0] == '*' && cp[1] == '/')
+	  return;
+      readline (plb, inf);
+    }
+  while (perhaps_more_input (inf));
+}
+
+/*
+ * A declaration is added if it matches:
+ *     <beginning of line>:-<whitespace><Mercury Term><whitespace>(
+ * If with_mercury_definitions == true, we also add:
+ *     <beginning of line><Mercury item><whitespace>(
+ * or  <beginning of line><Mercury item><whitespace>:-
+ * As for Prolog support, different arities and types are not taken into
+ * consideration.
+ * Item is added to the tags database if it doesn't match the
+ * name of the previous declaration.
+ *
+ * Consume a Mercury declaration.
+ * Return the number of bytes consumed, or 0 if there was an error.
+ *
+ * A Mercury declaration must be one of:
+ *  :- type
+ *  :- solver type
+ *  :- pred
+ *  :- func
+ *  :- inst
+ *  :- mode
+ *  :- typeclass
+ *  :- instance
+ *  :- pragma
+ *  :- promise
+ *  :- initialise
+ *  :- finalise
+ *  :- mutable
+ *  :- module
+ *  :- interface
+ *  :- implementation
+ *  :- import_module
+ *  :- use_module
+ *  :- include_module
+ *  :- end_module
+ * followed on the same line by an alphanumeric sequence, starting with a lower
+ * case letter or by a single-quoted arbitrary string.
+ * Single quotes can escape themselves.  Backslash quotes everything.
+ *
+ * Return the size of the name of the declaration or 0 if no header was found.
+ * As quantifiers may precede functions or predicates, we must list them too.
+ */
+
+static const char *Mercury_decl_tags[] = {"type", "solver type", "pred",
+  "func", "inst", "mode", "typeclass", "instance", "pragma", "promise",
+  "initialise", "finalise", "mutable", "module", "interface", "implementation",
+  "import_module", "use_module", "include_module", "end_module", "some", "all"};
+
+static size_t
+mercury_decl (char *s, size_t pos)
+{
+  if (s == NULL) return 0;
+
+  size_t origpos;
+  origpos = pos;
+
+  while (s + pos != NULL && (c_isalnum (s[pos]) || s[pos] == '_')) ++pos;
+
+  uint8_t decl_type_length = pos - origpos;
+  char buf[decl_type_length + 1];
+  memset(buf, 0, decl_type_length + 1);
+
+  /* Mercury declaration tags.  Consume them, then check the declaration item
+     following :- is legitimate, then go on as in the prolog case. */
+
+  memcpy(buf, &s[origpos], decl_type_length);
+
+  bool found_decl_tag = false;
+
+  if (is_mercury_quantifier)
+    {
+      if (strcmp(buf, "pred") != 0 && strcmp(buf, "func") != 0) /* Bad syntax */
+	return 0;
+      is_mercury_quantifier = false; /* Beset to base value. */
+      found_decl_tag = true;
+    }
+  else
+    {
+      for (int j = 0; j < sizeof(Mercury_decl_tags)/sizeof(char*); ++j)
+	{
+	  if (strcmp(buf, Mercury_decl_tags[j]) == 0)
+	    {
+	      found_decl_tag = true;
+	      if (strcmp(buf, "type") == 0)
+		is_mercury_type = true;
+
+	      if (strcmp(buf, "some") == 0
+		  || strcmp(buf, "all") == 0) {
+		is_mercury_quantifier = true;
+	      }
+
+	      break;  /* Found declaration tag of rank j. */
+	    }
+	  else
+	    /* 'solver type' has a blank in the middle,
+	       so this is the hard case */
+	    if (strcmp(buf, "solver") == 0)
+	      {
+		++pos;
+		while (s + pos != NULL && (c_isalnum (s[pos]) || s[pos] == '_'))
+		  ++pos;
+
+		decl_type_length = pos - origpos;
+		char buf2[decl_type_length + 1];
+		memset(buf2, 0, decl_type_length + 1);
+		memcpy(buf2, &s[origpos], decl_type_length);
+
+		if (strcmp(buf2, "solver type") == 0)
+		  {
+		    found_decl_tag = false;
+		    break;  /* Found declaration tag of rank j. */
+		  }
+	      }
+	}
+    }
+
+  /* If with_mercury_definitions == false
+   * this is a Mercury syntax error, ignoring... */
+
+  if (with_mercury_definitions)
+    {
+      if (found_decl_tag)
+	pos = skip_spaces (s + pos) - s; /* Skip len blanks again */
+      else
+	/* Prolog-like behavior
+	 * we have parsed the predicate once, yet inappropriately
+	 * so restarting again the parsing step */
+	pos = 0;
+    }
+  else
+    {
+      if (found_decl_tag)
+	pos = skip_spaces (s + pos) - s; /* Skip len blanks again */
+      else
+	return 0;
+    }
+
+  /* From now on it is the same as for Prolog except for module dots */
+
+  if (c_islower (s[pos]) || s[pos] == '_' )
+    {
+      /* The name is unquoted.
+         Do not confuse module dots with end-of-declaration dots. */
+
+      while (c_isalnum (s[pos])
+             || s[pos] == '_'
+             || (s[pos] == '.' /* A module dot */
+                 && s + pos + 1 != NULL
+                 && (c_isalnum (s[pos + 1]) || s[pos + 1] == '_')))
+	++pos;
+
+      return pos - origpos;
+    }
+  else if (s[pos] == '\'')
+    {
+      ++pos;
+      for (;;)
+	{
+	  if (s[pos] == '\'')
+	    {
+	      ++pos;
+	      if (s[pos] != '\'')
+		break;
+	      ++pos; /* A double quote */
+	    }
+	  else if (s[pos] == '\0')  /* Multiline quoted atoms are ignored. */
+	    return 0;
+	  else if (s[pos] == '\\')
+	    {
+	      if (s[pos+1] == '\0')
+		return 0;
+	      pos += 2;
+	    }
+	  else
+	    ++pos;
+	}
+      return pos - origpos;
+    }
+  else if (is_mercury_quantifier && s[pos] == '[')   /* :- some [T] pred/func */
+    {
+      for (++pos; s + pos != NULL && s[pos] != ']'; ++pos) {}
+      if (s + pos == NULL) return 0;
+      ++pos;
+      pos = skip_spaces (s + pos) - s;
+      return mercury_decl(s, pos) + pos - origpos;
+    }
+  else
+    return 0;
+}
+
+static ptrdiff_t
+mercury_pr (char *s, char *last, ptrdiff_t lastlen)
+{
+  size_t len0 = 0;
+  is_mercury_type = false;
+  is_mercury_quantifier = false;
+
+  if (is_mercury_declaration)
+    {
+      /* Skip len0 blanks only for declarations. */
+      len0 = skip_spaces (s + 2) - s;
+    }
+
+  size_t len = mercury_decl (s , len0);
+  if (len == 0) return 0;
+  len += len0;
+
+  if (( (s[len] == '.'  /* This is a statement dot, not a module dot. */
+	 || (s[len] == '(' && (len += 1))
+         || (s[len] == ':'  /* Stopping in case of a rule. */
+	     && s[len + 1] == '-'
+	     && (len += 2)))
+	&& (lastlen != len || memcmp (s, last, len) != 0)
+	)
+      /* Types are often declared on several lines so keeping just
+	 the first line */
+      || is_mercury_type
+      )
+    {
+      make_tag (s, 0, true, s, len, lineno, linecharno);
+      return len;
+    }
+
+  return 0;
+}
+
 
 /*
  * Support for Erlang
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index 12e57b1108..63f3cd6ca1 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -3534,6 +3534,8 @@ speedbar-fetch-etags-parse-list
      speedbar-parse-c-or-c++tag)
     ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" .
      "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?")
+      ("^\\.m$\\'" .
+     "\\(^:-\\)?\\s-*\\(\\(pred\\|func\\|type\\|instance\\|typeclass\\)+\\s+\\([a-z]+[a-zA-Z0-9_]*\\)+\\)\\s-*(?^?")
 ;    ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" .
 ;      speedbar-parse-fortran77-tag)
     ("\\.tex\\'" . speedbar-parse-tex-string)
-- 
2.26.3


--------------19B5DC828F28B24BA12F4B1F--




Acknowledgement sent to fabrice nicol <fabrnicol@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#47408; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sun, 28 Mar 2021 16:00:02 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.