; perl-mode, cperl-mode: Fix $\" in strings (Bug#69604)

* lisp/progmodes/perl-mode.el (perl-syntax-propertize-function):
Add to syntax-propertize-rules that $ is punctuation in strings.

* lisp/progmodes/cperl-mode.el (cperl-find-pods-heres): capture $\
to catch the edge case of "$\"".  Make $ a punctuation char in
strings and comments.

* test/lisp/progmodes/cperl-mode-tests.el (cperl-test-bug-69604):
New testcases with various combinations of $ " \
This commit is contained in:
Harald Jörg 2024-03-08 00:37:36 +01:00
parent e42f14f0e0
commit 00f86833ac
3 changed files with 39 additions and 3 deletions

View file

@ -4014,7 +4014,10 @@ recursive calls in starting lines of here-documents."
;; 1+6+2+1+1+6+1+1+1=20 extra () before this:
"\\|"
;; -------- backslash-escaped stuff, don't interpret it
"\\\\\\(['`\"($]\\)") ; BACKWACKED something-hairy
"\\\\\\(['`\"($]\\)" ; BACKWACKED something-hairy
"\\|"
;; -------- $\ is a variable in code, but not in a string
"\\(\\$\\\\\\)")
"")))
warning-message)
(unwind-protect
@ -4068,7 +4071,12 @@ recursive calls in starting lines of here-documents."
(cperl-modify-syntax-type bb cperl-st-punct)))
;; No processing in strings/comments beyond this point:
((or (nth 3 state) (nth 4 state))
t) ; Do nothing in comment/string
;; Edge case: In a double-quoted string, $\ is not the
;; punctuation variable, $ must not quote \ here. We
;; generally make $ a punctuation character in strings
;; and comments (Bug#69604).
(when (match-beginning 22)
(cperl-modify-syntax-type (match-beginning 22) cperl-st-punct)))
((match-beginning 1) ; POD section
;; "\\(\\`\n?\\|^\n\\)="
(setq b (match-beginning 0)

View file

@ -251,7 +251,16 @@
;; correctly the \() construct (Bug#11996) as well as references
;; to string values.
("\\(\\\\\\)['`\"($]" (1 (unless (nth 3 (syntax-ppss))
(string-to-syntax "."))))
(string-to-syntax "."))))
;; A "$" in Perl code must escape the next char to protect against
;; misinterpreting Perl's punctuation variables as unbalanced
;; quotes or parens. This is not needed in strings and broken in
;; the special case of "$\"" (Bug#69604). Make "$" a punctuation
;; char in strings.
("\\$" (0 (if (save-excursion
(nth 3 (syntax-ppss (match-beginning 0))))
(string-to-syntax ".")
(string-to-syntax "/"))))
;; Handle funny names like $DB'stop.
("\\$ ?{?\\^?[_[:alpha:]][_[:alnum:]]*\\('\\)[_[:alpha:]]" (1 "_"))
;; format statements

View file

@ -1431,6 +1431,25 @@ cperl-mode fontifies text after the delimiter as Perl code."
(should (equal (get-text-property (point) 'face)
font-lock-comment-face))))
(ert-deftest cperl-test-bug-69604 ()
"Verify that $\" in a double-quoted string does not end the string.
Both `perl-mode' and `cperl-mode' treat ?$ as a quoting/escaping char to
avoid issues with punctuation variables. In a string, however, this is
not appropriate."
(let ((strings
'("\"$\\\" in string ---\"; # \"" ; $ must not quote \
"$\" . \" in string ---\"; # \"" ; $ must quote \
"\"\\$\" . \" in string ---\"; # \""))) ; \$ must not quote
(dolist (string strings)
(with-temp-buffer
(insert string)
(funcall cperl-test-mode)
(font-lock-ensure)
(goto-char (point-min))
(search-forward "in string")
(should (equal (get-text-property (point) 'face)
font-lock-string-face))))))
(ert-deftest test-indentation ()
(ert-test-erts-file (ert-resource-file "cperl-indents.erts")))