unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Tom Tromey <tom@tromey.com>
To: Dmitry Gutov <dgutov@yandex.ru>
Cc: Tom Tromey <tom@tromey.com>,
	25529@debbugs.gnu.org, Stefan Monnier <monnier@IRO.UMontreal.CA>
Subject: bug#25529: diagnosis and one approach to a fix
Date: Fri, 10 Feb 2017 18:52:07 -0700	[thread overview]
Message-ID: <87vash5wag.fsf@tromey.com> (raw)
In-Reply-To: <fed5a1b0-fa9a-d170-f9e6-d973fb17797f@yandex.ru> (Dmitry Gutov's message of "Tue, 7 Feb 2017 04:20:40 +0200")

>> I think I understand combining the regexps.  But what does using a simple
>> regexp for the closer mean?

Dmitry> Simple handler (not regexp), for the group corresponding to the closer
Dmitry> (what's called a HIGHLIGHTn in syntax-propertize-rules docstring). The
Dmitry> string "\"/", probably.

Ok, I looked at this a bit.  My idea was to change js-syntax-propertize
to incorporate the new regexp I wrote.

However, after looking at this a bit, I think it's actually better the
way it is.  The reason is that the existing regexp in
js-syntax-propertize ends with "[^/*]" -- to prevent recognizing
"let x = /* comment */" as if it were using a regexp literal.

While it's possible to add this to the new regexp, it's kind of ugly,
since the regexp has to duplicate much of the body of the regexp just to
exclude "*" as the first character.

Conversely I don't think there's a drawback to the current approach.

Here's the latest version of my patch.  Let me know what you think.

Tom

commit 2518a9ca4ab59dbbfedc42a023267ae78476fc2e
Author: Tom Tromey <tom@tromey.com>
Date:   Sun Feb 5 11:40:18 2017 -0700

    Recognize JS regexp literals more correctly
    
    * lisp/progmodes/js.el (js--syntax-propertize-regexp-regexp): New
    constant.
    (js-syntax-propertize-regexp): Use it.  Remove "end" argument.
    (js--syntax-propertize-regexp-syntax-table): Remove.
    (js-syntax-propertize): Update.
    * test/lisp/progmodes/js-tests.el (js-mode-regexp-syntax-bug-25529):
    New test.

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index e42e014..3d9c1b4 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -1687,34 +1687,39 @@ js--font-lock-keywords
                                    js--font-lock-keywords-3)
   "Font lock keywords for `js-mode'.  See `font-lock-keywords'.")
 
-(defconst js--syntax-propertize-regexp-syntax-table
-  (let ((st (make-char-table 'syntax-table (string-to-syntax "."))))
-    (modify-syntax-entry ?\[ "(]" st)
-    (modify-syntax-entry ?\] ")[" st)
-    (modify-syntax-entry ?\\ "\\" st)
-    st))
-
-(defun js-syntax-propertize-regexp (end)
+(defconst js--syntax-propertize-regexp-regexp
+  (rx
+   ;; Start of regexp.
+   "/"
+   (0+ (or
+        ;; Match characters outside of a character class.
+        (not (any ?\[ ?/ ?\\))
+        ;; Match backslash quoted characters.
+        (and "\\" not-newline)
+        ;; Match character class.
+        (and
+         "["
+         (0+ (or
+              (not (any ?\] ?\\))
+              (and "\\" not-newline)))
+         "]")))
+   (group "/"))
+  "Regular expression matching a JavaScript regexp literal.")
+
+(defun js-syntax-propertize-regexp ()
   (let ((ppss (syntax-ppss)))
     (when (eq (nth 3 ppss) ?/)
       ;; A /.../ regexp.
-      (while
-          (when (re-search-forward "\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*/"
-                                   end 'move)
-            (if (nth 1 (with-syntax-table
-                           js--syntax-propertize-regexp-syntax-table
-                         (let ((parse-sexp-lookup-properties nil))
-                           (parse-partial-sexp (nth 8 ppss) (point)))))
-                ;; A / within a character class is not the end of a regexp.
-                t
-              (put-text-property (1- (point)) (point)
-                                 'syntax-table (string-to-syntax "\"/"))
-              nil))))))
+      (goto-char (nth 8 ppss))
+      (when (looking-at js--syntax-propertize-regexp-regexp)
+        (put-text-property (match-beginning 1) (match-end 1)
+                           'syntax-table (string-to-syntax "\"/"))
+        (goto-char (match-end 0))))))
 
 (defun js-syntax-propertize (start end)
   ;; JavaScript allows immediate regular expression objects, written /.../.
   (goto-char start)
-  (js-syntax-propertize-regexp end)
+  (js-syntax-propertize-regexp)
   (funcall
    (syntax-propertize-rules
     ;; Distinguish /-division from /-regexp chars (and from /-comment-starter).
@@ -1736,7 +1741,7 @@ js-syntax-propertize
                            (eval-when-compile (append "=({[,:;" '(nil))))))
            (put-text-property (match-beginning 1) (match-end 1)
                               'syntax-table (string-to-syntax "\"/"))
-           (js-syntax-propertize-regexp end)))))
+           (js-syntax-propertize-regexp)))))
     ("\\`\\(#\\)!" (1 "< b")))
    (point) end))
 
diff --git a/test/lisp/progmodes/js-tests.el b/test/lisp/progmodes/js-tests.el
index 7cb737c..d61f084 100644
--- a/test/lisp/progmodes/js-tests.el
+++ b/test/lisp/progmodes/js-tests.el
@@ -23,6 +23,7 @@
 
 (require 'ert)
 (require 'js)
+(require 'syntax)
 
 (ert-deftest js-mode-fill-bug-19399 ()
   (with-temp-buffer
@@ -99,6 +100,22 @@
     (forward-line)
     (should (looking-at " \\* test"))))
 
+(ert-deftest js-mode-regexp-syntax-bug-25529 ()
+  (dolist (regexp-contents '("[^[]"
+                             "[/]"
+                             ;; A comment with the regexp on the next
+                             ;; line.
+                             "*comment*/\n/regexp"))
+    (with-temp-buffer
+      (js-mode)
+      (insert "let x = /" regexp-contents "/;\n")
+      (save-excursion (insert "something();\n"))
+      ;; The failure mode was that the regexp literal was not
+      ;; recognized, causing the next line to be given string syntax;
+      ;; but check for comment syntax as well to prevent an
+      ;; implementation not recognizing the comment example.
+      (should-not (syntax-ppss-context (syntax-ppss))))))
+
 (provide 'js-tests)
 
 ;;; js-tests.el ends here





  parent reply	other threads:[~2017-02-11  1:52 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-25  7:22 bug#25529: 25.1.90; js-mode: Regexp literal with unbalanced brackets breaks font-lock Mikhail Gusarov
2017-02-05  5:37 ` bug#25529: diagnosis and one approach to a fix Tom Tromey
2017-02-05  6:01   ` Tom Tromey
2017-02-05 18:05     ` Tom Tromey
2017-02-05 18:43       ` Tom Tromey
2017-02-06  1:12         ` Dmitry Gutov
2017-02-06 17:27           ` Tom Tromey
2017-02-07  2:20             ` Dmitry Gutov
2017-02-07 13:07               ` Tom Tromey
2017-02-07 13:11                 ` Dmitry Gutov
2017-02-07 14:56               ` Stefan Monnier
2017-02-11  1:52               ` Tom Tromey [this message]
2017-02-11  3:45                 ` Stefan Monnier
2017-02-11  4:06                   ` Tom Tromey
2017-02-11  4:22                     ` Stefan Monnier
2017-02-11 15:27                       ` Tom Tromey
2017-02-11 15:41                         ` Stefan Monnier
2017-02-11 17:13                           ` Tom Tromey
2017-02-11 19:11                             ` Dmitry Gutov
2017-02-11 19:37 ` bug#25529: done Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87vash5wag.fsf@tromey.com \
    --to=tom@tromey.com \
    --cc=25529@debbugs.gnu.org \
    --cc=dgutov@yandex.ru \
    --cc=monnier@IRO.UMontreal.CA \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).