aboutsummaryrefslogtreecommitdiffstats
path: root/test/lisp
diff options
context:
space:
mode:
authorHarald Jörg2023-06-30 23:41:06 +0200
committerHarald Jörg2023-06-30 23:41:06 +0200
commita7ff8a76a52d316b27f05cd1267fe94cea9f35d1 (patch)
treed767d5ff79405a6fb4066c20592f4e88faef318e /test/lisp
parent361bf8a1132724516bf7e01d5f91510ffec83991 (diff)
downloademacs-a7ff8a76a52d316b27f05cd1267fe94cea9f35d1.tar.gz
emacs-a7ff8a76a52d316b27f05cd1267fe94cea9f35d1.zip
cperl-mode.el: Support subroutine signatures
Since Perl 5.20, subroutine signatures were available as an experimental feature. With Perl 5.38, they will be always enabled in the new object system. * test/lisp/progmodes/cperl-mode-resources/cperl-bug-64190.pl: * test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl: New test resources. * test/lisp/progmodes/cperl-mode-tests.el (cperl-test-fontify-attrs-and-signatures): Add tests for signatures. (cperl-test-attribute-rx, cperl-test-attribute-list-rx) (cperl-test-prototype-rx, cperl-test-signature-rx): Tests for the new rx sequences. (cperl-test-bug-64190): New test for multiline declarations. (cperl-test-bug-64364): New test for indentation of declarations. * lisp/progmodes/cperl-mode.el: (toplevel): New rx sequences to match Perl variables and attributes. (cperl-declaration-header-p): New function to identify declarations. (cperl-block-declaration-p): Use the new function. (cperl-mode): Use the rx sequences. (cperl-get-state): Use the new function. (cperl-sniff-for-indent): Use the new function. (cperl-find-sub-attrs): Improve fontification of subroutine prototypes and attributes while typing when jit-lock-mode is active. Detect signatures, and distinguish them from prototypes. (cperl-find-pods-heres): Use the rx sequences to detect subroutines. (cperl-init-faces): Use the rx sequences for fontification.
Diffstat (limited to 'test/lisp')
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-bug-64190.pl24
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl26
-rw-r--r--test/lisp/progmodes/cperl-mode-tests.el143
3 files changed, 190 insertions, 3 deletions
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64190.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64190.pl
new file mode 100644
index 00000000000..c7621e1c47b
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64190.pl
@@ -0,0 +1,24 @@
1# Example 1
2
3my ($var1,
4 $var2,
5 $var3);
6
7# Example 2
8
9package Foo
10 0.1;
11
12# Example 3 (intentionally incomplete, body is inserted by test)
13
14sub do_stuff
15
16# Example 4
17
18sub do_more_stuff ($param1,
19$param2)
20{
21 ...;
22}
23
24sub oops { ...; }
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl
new file mode 100644
index 00000000000..af188cbedac
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl
@@ -0,0 +1,26 @@
1# This resource file can be run with cperl--run-testcases from
2# cperl-tests.el and works with both perl-mode and cperl-mode.
3
4# -------- Bug#64364: input -------
5package P {
6sub way { ...; }
7#
8sub bus
9:lvalue
10($sig,$na,@ture)
11{
12...;
13}
14}
15# -------- Bug#64364: expected output -------
16package P {
17 sub way { ...; }
18 #
19 sub bus
20 :lvalue
21 ($sig,$na,@ture)
22 {
23 ...;
24 }
25}
26# -------- Bug#64364: end -------
diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el
index 9bd250a38b5..99d5a51b3ea 100644
--- a/test/lisp/progmodes/cperl-mode-tests.el
+++ b/test/lisp/progmodes/cperl-mode-tests.el
@@ -177,14 +177,18 @@ attributes, prototypes and signatures."
177 (should (equal (get-text-property (1+ (match-beginning 0)) 'face) 177 (should (equal (get-text-property (1+ (match-beginning 0)) 'face)
178 'font-lock-string-face))) 178 'font-lock-string-face)))
179 (goto-char start-of-sub) 179 (goto-char start-of-sub)
180 ;; Attributes with their optional parameters
180 (when (search-forward-regexp "\\(:[a-z]+\\)\\((.*?)\\)?" end-of-sub t) 181 (when (search-forward-regexp "\\(:[a-z]+\\)\\((.*?)\\)?" end-of-sub t)
181 (should (equal (get-text-property (match-beginning 1) 'face) 182 (should (equal (get-text-property (match-beginning 1) 'face)
182 'font-lock-constant-face)) 183 'font-lock-constant-face))
183 (when (match-beginning 2) 184 (when (match-beginning 2)
184 (should (equal (get-text-property (match-beginning 2) 'face) 185 (should (equal (get-text-property (match-beginning 2) 'face)
185 'font-lock-string-face)))) 186 'font-lock-string-face))))
186 (goto-char end-of-sub))) 187 (goto-char end-of-sub)
187 188 ;; Subroutine signatures
189 (when (search-forward "$bar" end-of-sub t)
190 (should (equal (get-text-property (match-beginning) 'face)
191 'font-lock-variable-name-face)))))
188 ;; Anonymous subroutines 192 ;; Anonymous subroutines
189 (while (search-forward-regexp "= sub" nil t) 193 (while (search-forward-regexp "= sub" nil t)
190 (let ((start-of-sub (match-beginning 0)) 194 (let ((start-of-sub (match-beginning 0))
@@ -201,7 +205,11 @@ attributes, prototypes and signatures."
201 (when (match-beginning 2) 205 (when (match-beginning 2)
202 (should (equal (get-text-property (match-beginning 2) 'face) 206 (should (equal (get-text-property (match-beginning 2) 'face)
203 'font-lock-string-face)))) 207 'font-lock-string-face))))
204 (goto-char end-of-sub)))))) 208 (goto-char end-of-sub)
209 ;; Subroutine signatures
210 (when (search-forward "$bar" end-of-sub t)
211 (should (equal (get-text-property (match-beginning) 'face)
212 'font-lock-variable-name-face))))))))
205 213
206(ert-deftest cperl-test-fontify-special-variables () 214(ert-deftest cperl-test-fontify-special-variables ()
207 "Test fontification of variables like $^T or ${^ENCODING}. 215 "Test fontification of variables like $^T or ${^ENCODING}.
@@ -428,6 +436,62 @@ Also includes valid cases with whitespace in strange places."
428 (cperl-test--validate-regexp (rx (eval cperl--basic-identifier-rx)) 436 (cperl-test--validate-regexp (rx (eval cperl--basic-identifier-rx))
429 valid invalid))) 437 valid invalid)))
430 438
439(ert-deftest cperl-test-attribute-rx ()
440 "Test attributes and attribute lists"
441 (skip-unless (eq cperl-test-mode #'cperl-mode))
442 (let ((valid
443 '("foo" "bar()" "baz(quux)"))
444 (invalid
445 '("+foo" ; not an identifier
446 "foo::bar" ; no package qualifiers allowed
447 "(no-identifier)" ; no attribute name
448 "baz (quux)"))) ; no space allowed before "("
449 (cperl-test--validate-regexp (rx (eval cperl--single-attribute-rx))
450 valid invalid)))
451
452(ert-deftest cperl-test-attribute-list-rx ()
453 "Test attributes and attribute lists"
454 (skip-unless (eq cperl-test-mode #'cperl-mode))
455 (let ((valid
456 '(":" ":foo" ": bar()" ":baz(quux):"
457 ":isa(Foo)does(Bar)" ":isa(Foo):does(Bar)" ":isa(Foo):does(Bar):"
458 ": isa(Foo::Bar) : does(Bar)"))
459 (invalid
460 '(":foo + bar" ; not an identifier
461 ": foo(bar : : baz" ; too many colons
462 ": baz (quux)"))) ; no space allowed before "("
463 (cperl-test--validate-regexp (rx (eval cperl--attribute-list-rx))
464 valid invalid)))
465
466(ert-deftest cperl-test-prototype-rx ()
467 "Test subroutine prototypes"
468 (skip-unless (eq cperl-test-mode #'cperl-mode))
469 (let ((valid
470 ;; Examples from perldoc perlsub
471 '("($$)" "($$$)" "($$;$)" "($$$;$)" "(@)" "($@)" "(\\@)" "(\\@$$@)"
472 "(\\[%@])" "(*;$)" "(**)" "(&@)" "(;$)" "()"))
473 (invalid
474 '("$" ; missing paren
475 "($self)" ; a variable, -> subroutine signature
476 "(!$)" ; not all punctuation is permitted
477 "{$$}"))) ; wrong type of paren
478 (cperl-test--validate-regexp (rx (eval cperl--prototype-rx))
479 valid invalid)))
480
481(ert-deftest cperl-test-signature-rx ()
482 "Test subroutine signatures."
483 (skip-unless (eq cperl-test-mode #'cperl-mode))
484 (let ((valid
485 '("()" "( )" "($self, %params)" "(@params)"))
486 (invalid
487 '("$self" ; missing paren
488 "($)" ; a subroutine signature
489 "($!)" ; globals not permitted in a signature
490 "(@par,%options)" ; two slurpy parameters
491 "{$self}"))) ; wrong type of paren
492 (cperl-test--validate-regexp (rx (eval cperl--signature-rx))
493 valid invalid)))
494
431;;; Test unicode identifier in various places 495;;; Test unicode identifier in various places
432 496
433(defun cperl--test-unicode-setup (code string) 497(defun cperl--test-unicode-setup (code string)
@@ -1145,6 +1209,79 @@ as a regex."
1145 (funcall cperl-test-mode) 1209 (funcall cperl-test-mode)
1146 (should-not (nth 3 (syntax-ppss 3))))) 1210 (should-not (nth 3 (syntax-ppss 3)))))
1147 1211
1212(ert-deftest cperl-test-bug-64190 ()
1213 "Verify correct fontification of multiline declarations"
1214 (skip-unless (eq cperl-test-mode #'cperl-mode))
1215 (let ((file (ert-resource-file "cperl-bug-64190.pl")))
1216 (with-temp-buffer
1217 (insert-file-contents file)
1218 (goto-char (point-min))
1219 (cperl-mode)
1220 (font-lock-ensure)
1221 ;; Example 1
1222 (while (search-forward "var" nil t)
1223 (should (equal (get-text-property (point) 'face)
1224 'font-lock-variable-name-face)))
1225 ;; Example 2
1226 (search-forward "package F")
1227 (should (equal (get-text-property (point) 'face)
1228 'font-lock-function-name-face))
1229
1230 ;; Example 3 and 4 can't be directly tested because jit-lock and
1231 ;; batch tests don't play together well. But we can approximate
1232 ;; the behavior by calling the the fontification for the same
1233 ;; region which would be used by jit-lock.
1234 ;; Example 3
1235 (search-forward "sub do_stuff")
1236 (let ((start-change (point)))
1237 (insert "\n{")
1238 (cperl-font-lock-fontify-region-function start-change
1239 (point-max)
1240 nil) ; silent
1241 (font-lock-ensure start-change (point-max))
1242 (goto-char (1- start-change)) ; between the "ff" in "stuff"
1243 (should (equal (get-text-property (point) 'face)
1244 'font-lock-function-name-face))
1245 (search-forward "{")
1246 (insert "}")) ; make it legal again
1247
1248 ;; Example 4
1249 (search-forward "$param2")
1250 (beginning-of-line)
1251 (let ((start-change (point)))
1252 (insert " ")
1253 (cperl-font-lock-fontify-region-function start-change
1254 (point-max)
1255 nil) ; silent
1256 (font-lock-ensure start-change (point-max))
1257 (goto-char (1+ start-change))
1258 (should (equal (get-text-property (point) 'face)
1259 'font-lock-variable-name-face))
1260 (re-search-forward (rx (group "sub") " " (group "oops")))
1261 (should (equal (get-text-property (match-beginning 1) 'face)
1262 'font-lock-keyword-face))
1263 (should (equal (get-text-property (match-beginning 2) 'face)
1264 'font-lock-function-name-face))))))
1265
1266(ert-deftest cperl-test-bug-64364 ()
1267 "Check that multi-line subroutine declarations indent correctly."
1268 (cperl-set-style "PBP") ; make cperl-mode use the same settings as perl-mode
1269 (cperl--run-test-cases
1270 (ert-resource-file "cperl-bug-64364.pl")
1271 (indent-region (point-min) (point-max)))
1272 (cperl--run-test-cases
1273 (ert-resource-file "cperl-bug-64364.pl")
1274 (let ((tab-function
1275 (if (equal cperl-test-mode 'perl-mode)
1276 #'indent-for-tab-command
1277 #'cperl-indent-command)))
1278 (goto-char (point-min))
1279 (while (null (eobp))
1280 (funcall tab-function)
1281 (forward-line 1))))
1282 (cperl-set-style-back))
1283
1284
1148(ert-deftest test-indentation () 1285(ert-deftest test-indentation ()
1149 (ert-test-erts-file (ert-resource-file "cperl-indents.erts"))) 1286 (ert-test-erts-file (ert-resource-file "cperl-indents.erts")))
1150 1287