]> git.eshelyaron.com Git - emacs.git/commitdiff
; cperl-mode.el: Detect prototypes in anonymous subroutines
authorHarald Jörg <haj@posteo.de>
Wed, 2 Feb 2022 21:30:09 +0000 (22:30 +0100)
committerHarald Jörg <haj@posteo.de>
Wed, 2 Feb 2022 21:42:05 +0000 (22:42 +0100)
My commit 3d49ad73e5a from 2021-09-143 had a flaw causing bad
fontification and indentation after anonymous subroutines with
a prototype.
* lisp/progmodes/cperl-mode.el (cperl-find-pods-heres): Correctly
process prototypes in anonymous subroutines
* test/lisp/progmodes/cperl-mode-tests.el
(cperl-test-fontify-attrs-and-signatures): new tests for various
combinations of attributes, prototypes, and signatures
* test/lisp/progmodes/cperl-mode-resources/proto-and-attrs.pl: new
test source

lisp/progmodes/cperl-mode.el
test/lisp/progmodes/cperl-mode-resources/proto-and-attrs.pl [new file with mode: 0644]
test/lisp/progmodes/cperl-mode-tests.el

index 8f33b3e3b73fa7fa6ea34b29930ec8185f797e3c..94ecc45b15fb777f1fbd87b26de849a48a1b971b 100644 (file)
@@ -3834,7 +3834,7 @@ recursive calls in starting lines of here-documents."
                "\\<" cperl-sub-regexp "\\>" ;  sub with proto/attr
                "\\("
                   cperl-white-and-comment-rex
-                   (rx (group (eval cperl--normal-identifier-rx)))
+                   (rx (opt (group (eval cperl--normal-identifier-rx))))
                 "\\)"
                "\\("
                   cperl-maybe-white-and-comment-rex
diff --git a/test/lisp/progmodes/cperl-mode-resources/proto-and-attrs.pl b/test/lisp/progmodes/cperl-mode-resources/proto-and-attrs.pl
new file mode 100644 (file)
index 0000000..7138bf6
--- /dev/null
@@ -0,0 +1,50 @@
+# The next two lines are required as of 2022, but obsolescent
+# as soon as signatures leave their "experimental" state
+use feature 'signatures';
+no warnings 'experimental::signatures';
+
+# Tests for subroutine prototypes, signatures and the like
+
+# Prototypes have syntactical properties different from "normal" Perl:
+# Perl has a variable $), so ($)) is not an unbalanced parenthesis.
+# On the other hand, in a prototype ($) is _not_ an open paren
+# followed by the variable $), so the parens are balanced.  Prototypes
+# are somewhat frowned upon most of the times, but they are required
+# for some Perl magic
+
+# FIXME: 2022-02-02 CPerl mode does not handle subroutine signatures.
+# In simple cases it mistakes them as prototypes, when attributes are
+# present, it doesn't handle them at all.  Variables in signatures
+# SHOULD be fontified like variable declarations.
+
+# Part 1: Named subroutines
+# A prototype and a trivial subroutine attribute
+{
+    no feature 'signatures'; # that's a prototype, not a signature
+    sub sub_1 ($) :lvalue { local $); }
+}
+
+# A prototype as an attribute (how it should be written these days)
+sub sub_2 :prototype($) { ...; }
+
+# A signature (these will soon-ish leave the experimental state)
+sub sub_3 ($foo,$bar) { ...; }
+
+# Attribute plus signature FIXME: Not yet supported
+sub bad_sub_4 :prototype($$$) ($foo,$bar,$baz) { ...; }
+
+# Part 2: Same constructs for anonymous subs
+# A prototype and a trivial subroutine attribute
+{
+    no feature 'signatures'; # that's a prototype, not a signature
+    my $subref_1 = sub ($) :lvalue { local $); };
+}
+
+# A prototype as an attribute (how it should be written these days)
+my $subref_2 = sub :prototype($) { ...; };
+
+# A signature (these will soon-ish leave the experimental state)
+my $subref_3 = sub ($foo,$bar) { ...; };
+
+# Attribute plus signature
+my $subref_4 = sub :prototype($$$) ($foo,$bar,$baz) { ...; };
index 0124dad6f17cf0bebf679dd37e564c9732359083..b8a3bd97d8d766b5e34759e4bca39ea0f53b7dc8 100644 (file)
@@ -154,6 +154,55 @@ point in the distant past, and is still broken in perl-mode. "
     (should (equal (get-text-property (match-beginning 0) 'face)
                    'font-lock-keyword-face))))
 
+(ert-deftest cperl-test-fontify-attrs-and-signatures ()
+  "Test fontification of the various combinations of subroutine
+attributes, prototypes and signatures."
+  (skip-unless (eq cperl-test-mode #'cperl-mode))
+  (let ((file (ert-resource-file "proto-and-attrs.pl")))
+    (with-temp-buffer
+      (insert-file-contents file)
+      (goto-char (point-min))
+      (funcall cperl-test-mode)
+      (font-lock-ensure)
+
+      ;; Named subroutines
+      (while (search-forward-regexp "\\_<sub_[[:digit:]]+" nil t)
+        (should (equal (get-text-property (match-beginning 0) 'face)
+                       'font-lock-function-name-face))
+        (let ((start-of-sub (match-beginning 0))
+              (end-of-sub (save-excursion (search-forward "}") (point))))
+
+          ;; Prototypes are shown as strings
+          (when (search-forward-regexp " ([$%@*]*) " end-of-sub t)
+            (should (equal (get-text-property (1+ (match-beginning 0)) 'face)
+                           'font-lock-string-face)))
+          (goto-char start-of-sub)
+          (when (search-forward-regexp "\\(:[a-z]+\\)\\((.*?)\\)?" end-of-sub t)
+            (should (equal (get-text-property (match-beginning 1) 'face)
+                           'font-lock-constant-face))
+            (when (match-beginning 2)
+              (should (equal (get-text-property (match-beginning 2) 'face)
+                             'font-lock-string-face))))
+          (goto-char end-of-sub)))
+
+      ;; Anonymous subroutines
+      (while (search-forward-regexp "= sub" nil t)
+        (let ((start-of-sub (match-beginning 0))
+              (end-of-sub (save-excursion (search-forward "}") (point))))
+
+          ;; Prototypes are shown as strings
+          (when (search-forward-regexp " ([$%@*]*) " end-of-sub t)
+            (should (equal (get-text-property (1+ (match-beginning 0)) 'face)
+                           'font-lock-string-face)))
+          (goto-char start-of-sub)
+          (when (search-forward-regexp "\\(:[a-z]+\\)\\((.*?)\\)?" end-of-sub t)
+            (should (equal (get-text-property (match-beginning 1) 'face)
+                           'font-lock-constant-face))
+            (when (match-beginning 2)
+              (should (equal (get-text-property (match-beginning 2) 'face)
+                             'font-lock-string-face))))
+          (goto-char end-of-sub))))))
+
 (ert-deftest cperl-test-fontify-special-variables ()
   "Test fontification of variables like $^T or ${^ENCODING}.
 These can occur as \"local\" aliases."