diff options
| author | Harald Jörg | 2023-06-30 23:41:06 +0200 |
|---|---|---|
| committer | Harald Jörg | 2023-06-30 23:41:06 +0200 |
| commit | a7ff8a76a52d316b27f05cd1267fe94cea9f35d1 (patch) | |
| tree | d767d5ff79405a6fb4066c20592f4e88faef318e /test/lisp | |
| parent | 361bf8a1132724516bf7e01d5f91510ffec83991 (diff) | |
| download | emacs-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.pl | 24 | ||||
| -rw-r--r-- | test/lisp/progmodes/cperl-mode-resources/cperl-bug-64364.pl | 26 | ||||
| -rw-r--r-- | test/lisp/progmodes/cperl-mode-tests.el | 143 |
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 | |||
| 3 | my ($var1, | ||
| 4 | $var2, | ||
| 5 | $var3); | ||
| 6 | |||
| 7 | # Example 2 | ||
| 8 | |||
| 9 | package Foo | ||
| 10 | 0.1; | ||
| 11 | |||
| 12 | # Example 3 (intentionally incomplete, body is inserted by test) | ||
| 13 | |||
| 14 | sub do_stuff | ||
| 15 | |||
| 16 | # Example 4 | ||
| 17 | |||
| 18 | sub do_more_stuff ($param1, | ||
| 19 | $param2) | ||
| 20 | { | ||
| 21 | ...; | ||
| 22 | } | ||
| 23 | |||
| 24 | sub 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 ------- | ||
| 5 | package P { | ||
| 6 | sub way { ...; } | ||
| 7 | # | ||
| 8 | sub bus | ||
| 9 | :lvalue | ||
| 10 | ($sig,$na,@ture) | ||
| 11 | { | ||
| 12 | ...; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | # -------- Bug#64364: expected output ------- | ||
| 16 | package 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 | ||