From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: fabrice nicol Newsgroups: gmane.emacs.bugs Subject: bug#47408: Emacs etags support for Mercury [v0.2] Date: Fri, 26 Mar 2021 08:09:40 +0100 Message-ID: References: <25b8baef-11f2-7079-69d8-3207a24658fc@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------19B5DC828F28B24BA12F4B1F" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19567"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 To: 47408@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Mar 26 09:28:11 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lPhpC-0004v8-Vc for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 26 Mar 2021 09:28:11 +0100 Original-Received: from localhost ([::1]:57046 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lPhpB-000689-Qr for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 26 Mar 2021 04:28:09 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:33538) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lPhp4-00067z-Vj for bug-gnu-emacs@gnu.org; Fri, 26 Mar 2021 04:28:03 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:57008) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lPhp4-0000ve-OJ for bug-gnu-emacs@gnu.org; Fri, 26 Mar 2021 04:28:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1lPhp4-0004jD-KK for bug-gnu-emacs@gnu.org; Fri, 26 Mar 2021 04:28:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: fabrice nicol Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 26 Mar 2021 08:28:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 47408 X-GNU-PR-Package: emacs X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.161674723018112 (code B ref -1); Fri, 26 Mar 2021 08:28:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 26 Mar 2021 08:27:10 +0000 Original-Received: from localhost ([127.0.0.1]:40321 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lPhoC-0004i2-L7 for submit@debbugs.gnu.org; Fri, 26 Mar 2021 04:27:10 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:51940) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lPgat-0000hV-NO for submit@debbugs.gnu.org; Fri, 26 Mar 2021 03:09:21 -0400 Original-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 ) id 1lPgat-0000qV-IQ for bug-gnu-emacs@gnu.org; Fri, 26 Mar 2021 03:09:19 -0400 Original-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 ) id 1lPgap-00034r-Ui for bug-gnu-emacs@gnu.org; Fri, 26 Mar 2021 03:09:19 -0400 Original-Received: by mail-wr1-x42d.google.com with SMTP id x13so4577288wrs.9 for ; 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) Original-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 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 26 Mar 2021 00:09:13 -0700 (PDT) X-Forwarded-Message-Id: <25b8baef-11f2-7079-69d8-3207a24658fc@gmail.com> In-Reply-To: <25b8baef-11f2-7079-69d8-3207a24658fc@gmail.com> Content-Language: en-US Received-SPF: pass client-ip=2a00:1450:4864:20::42d; envelope-from=fabrnicol@gmail.com; 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-Mailman-Approved-At: Fri, 26 Mar 2021 04:27:06 -0400 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:203037 Archived-At: 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@lists.mercurylang.org). 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: > 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: 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@gnu.org> From: Eli Zaretskii Cc: emacs-devel@gnu.org In-Reply-To: (message from fabrice nicol on Mon, 22 Mar 2021 03:02:03 +0100) Subject: Re: etags support for the Mercury programming language References: > 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 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 = ⟨ + 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: + * :-( + * If with_mercury_definitions == true, we also add: + * ( + * or :- + * 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--