1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00

cperl-mode.el: Support syntax of Perl version 5.42

* lisp/progmodes/cperl-mode.el (cperl--sub-name-generated-rx):
Simplify captures to account for the :writer attribute.  Parsing
is done later.
(cperl-imenu-sub-keywords): Remove attributes which generate subs
(cperl-imenu--create-perl-index): Analyze field declarations for
autogenerated methods
(cperl-init-faces): Add "all" and "any" to the list of functions
(cperl-short-docs): Add short docs for "all" and "any"

* test/lisp/progmodes/cperl-mode-tests.el
(cperl-test-autogenerated-reader-rx):
Adjust for modified rx form due to ":writer" support
(cperl-test-imenu-index): Add tests for autogenerated writer
accessors (in grammar.pl)

* test/lisp/progmodes/cperl-mode-resources/grammar.pl: Add code samples
for ":writer"

* etc/NEWS: Announce that CPerl mode supports Perl 5.42.
This commit is contained in:
Harald Jörg 2025-07-28 18:20:26 +02:00
parent 62fba3a723
commit cef4302d30
4 changed files with 67 additions and 29 deletions

View file

@ -2460,6 +2460,13 @@ The new commands 'newsticker-hide-old-feed-header' and
respectively, hide and show the headers of feeds whose items are all old
or obsolete.
** CPerl mode
*** Syntax of Perl up to version 5.42 is supported.
CPerl mode creates imenu entries for :writer-generated accessors and
recognizes the new functions "all" and "any".
* New Modes and Packages in Emacs 31.1

View file

@ -1465,28 +1465,17 @@ the subroutine name.")
`(sequence symbol-start
(optional (group-n 3 unmatchable))
;; autogenerated methods are not lexicals, so enforce the
;; first capture group to be nil
"field"
;; third capture group to be nil
(group-n 1 "field")
,cperl--ws+-rx
(or
(sequence (in "$%@")
(group-n 2 ,cperl--basic-identifier-rx)
(1+ (not (in ";={")))
":"
(group-n 1 "reader")
(not "("))
(sequence ,cperl--basic-variable-rx
(1+ (not (in ";={")))
":"
(group-n 1 "reader")
"("
(group-n 2 ,cperl--basic-identifier-rx)
")")))
,cperl--basic-variable-rx
,cperl--ws+-rx
(group-n 2 ,cperl--attribute-list-rx))
"A regular expression to capture autogenerated reader methods.
The name of the method is either the field name without its sigil, or
given in parentheses after the \":reader\" keyword.")
;; I don't dare to think about :writer where the generated name does
;; not even occur in the text.
given in parentheses after the \":reader\" or \":writer\" keyword. More
than one attribute can be present: The match will be parsed in an extra
step.")
(defconst cperl--block-declaration-rx
`(sequence
@ -6106,8 +6095,7 @@ use, it indicates a recursive call."
;; The following lists are used for categorizing the entries found by
;; `cperl-imenu--create-perl-index'.
(defvar cperl-imenu-package-keywords '("package" "class" "role"))
(defvar cperl-imenu-sub-keywords '("sub" "method" "function" "fun"
"reader")) ;; for autogenerated
(defvar cperl-imenu-sub-keywords '("sub" "method" "function" "fun"))
(defvar cperl-imenu-pod-keywords '("=head"))
(defun cperl-imenu--create-perl-index ()
@ -6175,6 +6163,38 @@ comment, or POD."
(push index index-alist)
(push index index-sub-alist)
(push index index-unsorted-alist))))
((string-equal entry-type "field")
(unless (nth 4 state) ; skip if in a comment
(let ((limit (match-end 0))
field-name)
(save-excursion
(goto-char (match-end 1))
(re-search-forward
(rx (in "$%@")
(group-n 1 (eval cperl--basic-identifier-rx)))
limit t)
(setq field-name (match-string-no-properties 1))
(when field-name
(while (re-search-forward
(rx (group-n 1 (eval cperl--basic-identifier-rx))
(optional
(sequence
"("
(group-n 2
(eval cperl--basic-identifier-rx))
")")))
limit t)
(when (member (match-string 1) '("reader" "writer"))
(let* ((name (or (match-string 2)
(if (string-equal
(match-string 1) "reader")
field-name)
(concat "set_" field-name)))
(qname (concat current-namespace "->" name))
(index (cons qname (match-beginning 1))))
(push index index-alist)
(push index index-sub-alist)
(push index index-unsorted-alist)))))))))
((member entry-type cperl-imenu-pod-keywords) ; POD heading
(when (get-text-property (match-beginning 2) 'in-pod)
(setq name (concat (make-string
@ -6461,7 +6481,9 @@ functions (which they are not). Inherits from `default'.")
"\\(^\\|[^$@%&\\]\\)\\<\\("
(regexp-opt
'("AUTOLOAD" "BEGIN" "CHECK" "DESTROY" "END" "INIT" "UNITCHECK"
"__END__" "__DATA__" "break" "catch" "chomp" "chop" "default"
"__END__" "__DATA__"
"all" "any"
"break" "catch" "chomp" "chop" "default"
"defined" "delete" "do" "each" "else" "elsif" "eval"
"evalbytes" "exists" "finally" "for" "foreach" "format" "given"
"goto" "grep" "if" "keys" "last" "local" "m" "map" "my" "next"
@ -8295,6 +8317,8 @@ DATA Input filehandle for what follows after __END__ or __DATA__.
abs [ EXPR ] absolute value function
accept(NEWSOCKET,GENERICSOCKET) accept an incoming socket connect
alarm(SECONDS) schedule a SIGALRM
all {BLOCK} LIST true if BLOCK is true for all elements in LIST
any {BLOCK} LIST true if BLOCK is true for any element in LIST
async(SUB NAME {}|SUB {}) Mark function as potentially asynchronous
atan2(X,Y) arctangent of Y/X in the range -PI to PI
await(ASYNCEXPR) Yield result of Future

View file

@ -1,4 +1,4 @@
use 5.024;
use 5.042;
use strict;
use warnings;
use utf8;
@ -204,9 +204,11 @@ method-generator for classes are available with Perl 5.40.
=cut
class With::Readers {
class With::Accessors {
field $simple;
field $auto_reader :reader;
field $named_reader :reader(named);
field $auto_writer :writer = 0;
field $auto_all :param :reader(read_all) :writer;
}
1;

View file

@ -637,14 +637,16 @@ Also includes valid cases with whitespace in strange places."
"field $name :param :reader;"
"field $field :param :reader(name);"
"field $field :reader(name) :param;"
"field $field :reader(name) = 'value';")))
"field $field :reader(name) = 'value';"
"field $field :writer = 'value';"
"field $field :writer(write_f)")))
(dolist (code code-examples)
(with-temp-buffer
(insert code)
(goto-char (point-min))
(search-forward-regexp (rx (eval cperl--sub-name-generated-rx)))
(should (string= (match-string 1) "reader"))
(should (string= (match-string 2) "name"))))))
(should (string= (match-string 1) "field"))
(should (string-match ":\\(reader\\|writer\\)" (match-string 2)))))))
;;; Test unicode identifier in various places
@ -973,8 +975,11 @@ created by CPerl mode, so skip it for Perl mode."
"Erdős::Number::erdős_number"
"Class::Class::init"
"Class::Inner::init_again"
"With::Readers::auto_reader"
"With::Readers::named")))
"With::Accessors->auto_reader"
"With::Accessors->named"
"With::Accessors->set_auto_writer"
"With::Accessors->read_all"
"With::Accessors->set_auto_all")))
(dolist (sub expected)
(should (assoc-string sub index))))
(should-not (assoc-string "_false" index)))))