emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/swift-mode 9b8a92615b 4/5: Support regex literals


From: ELPA Syncer
Subject: [nongnu] elpa/swift-mode 9b8a92615b 4/5: Support regex literals
Date: Sat, 9 Jul 2022 02:59:17 -0400 (EDT)

branch: elpa/swift-mode
commit 9b8a92615b30e0a3074a6105b9fa9121da38e838
Author: taku0 <mxxouy6x3m_github@tatapa.org>
Commit: taku0 <mxxouy6x3m_github@tatapa.org>

    Support regex literals
    
    
https://github.com/apple/swift-evolution/blob/main/proposals/0354-regex-literals.md
---
 README.md                             |   9 ++
 swift-mode-indent.el                  |  12 +-
 swift-mode-lexer.el                   | 281 ++++++++++++++++++++++++++++++----
 test/swift-files/indent/strings.swift | 170 ++++++++++++++++++++
 4 files changed, 435 insertions(+), 37 deletions(-)

diff --git a/README.md b/README.md
index bf3f48cdb3..84657bc979 100644
--- a/README.md
+++ b/README.md
@@ -172,6 +172,15 @@ var x = foo
 
 Both are syntactically correct code. We cannot handle this case properly. This 
is also a future work.
 
+Other example is regex literals and custom operators.  The following example 
is valid Swift code with regex literals and custom operators.
+
+```swift
+let x = /^/ /^/ /^/
+```
+
+We parse them as regex literals rather than custom operators for now.
+
+
 ## Hacking
 
 To build the package locally, run `make package`.
diff --git a/swift-mode-indent.el b/swift-mode-indent.el
index 1b8550c366..82c9128a93 100644
--- a/swift-mode-indent.el
+++ b/swift-mode-indent.el
@@ -225,11 +225,15 @@ declaration and its offset is `swift-mode:basic-offset'."
       (swift-mode:indentation (point) 0)))))
 
 (defun swift-mode:calculate-indent-of-multiline-string ()
-  "Return the indentation of the current line inside a multiline string."
+  "Return the indentation of the current line inside a multiline string.
+
+Also used for regexes."
   (back-to-indentation)
   (let ((string-beginning-position
          (save-excursion (swift-mode:beginning-of-string))))
-    (if (looking-at "\"\"\"")
+    (if (and (looking-at "\\(\"\"\"\\|/\\)#*")
+             (equal (get-text-property (1- (match-end 0)) 'syntax-table)
+                    (string-to-syntax "|")))
         ;; The last line.
         (progn
           (goto-char string-beginning-position)
@@ -240,13 +244,13 @@ declaration and its offset is `swift-mode:basic-offset'."
       (swift-mode:goto-non-interpolated-expression-bol)
       (back-to-indentation)
       (if (<= (point) string-beginning-position)
-          ;; The cursor was on the 2nd line of the comment, so aligns with
+          ;; The cursor was on the 2nd line of the string, so aligns with
           ;; that line with offset.
           (progn
             (goto-char string-beginning-position)
             (swift-mode:calculate-indent-of-expression
              swift-mode:multiline-statement-offset))
-        ;; The cursor was on the 3rd or following lines of the comment, so
+        ;; The cursor was on the 3rd or following lines of the string, so
         ;; aligns with a non-empty preceding line.
         (if (and (bolp) (eolp))
             ;; The cursor is on an empty line, so seeks a non-empty-line.
diff --git a/swift-mode-lexer.el b/swift-mode-lexer.el
index 2caf5eb608..f5a4989e1c 100644
--- a/swift-mode-lexer.el
+++ b/swift-mode-lexer.el
@@ -75,7 +75,7 @@
 (defun swift-mode:token (type text start end)
   "Construct and return a token.
 
-TYPE is the type of the token such as `infix-operator' or {.
+TYPE is the type of the token such as `binary-operator' or {.
 TEXT is the text of the token.
 START is the start position of the token.
 END is the point after the token."
@@ -122,7 +122,7 @@ END is the point after the token."
 ;; - : (part of conditional operator, key-value separator, label-statement
 ;;   separator)
 ;; - anonymous-function-parameter-in ("in" after anonymous function parameter)
-;; - string-chunk-after-interpolated-expression (part of a string ending with
+;; - string-chunk-after-interpolated-expression (part of a string starting with
 ;;   ")")
 ;; - string-chunk-before-interpolated-expression (part of a string ending with
 ;;   "\\(")
@@ -220,8 +220,8 @@ Intended for `syntax-propertize-extend-region-functions'."
 
 (defun swift-mode:syntax-propertize (start end)
   "Update text properties for strings.
-Mark the beginning of and the end of single-line/multiline strings between
-the position START and END as general string delimiters.
+Mark the beginning of and the end of single-line/multiline strings and regexes
+between the position START and END as general string delimiters.
 Intended for `syntax-propertize-function'."
   (remove-text-properties start end
                           '(syntax-table
@@ -229,8 +229,11 @@ Intended for `syntax-propertize-function'."
                             syntax-multiline
                             nil
                             swift-mode:matching-parenthesis
+                            nil
+                            swift-mode:comment
                             nil))
-  (let* ((chunk (swift-mode:chunk-after (syntax-ppss start))))
+  (let* ((chunk (swift-mode:chunk-after (syntax-ppss start)))
+         comment-start)
     (cond
      ((swift-mode:chunk:multiline-string-p chunk)
       (swift-mode:syntax-propertize:end-of-string
@@ -240,21 +243,27 @@ Intended for `syntax-propertize-function'."
       (swift-mode:syntax-propertize:end-of-string
        end "\"" (swift-mode:chunk:pound-count chunk)))
 
+     ((swift-mode:chunk:regex-p chunk)
+      (swift-mode:syntax-propertize:end-of-regex
+       (swift-mode:chunk:start chunk)))
+
      ((swift-mode:chunk:comment-p chunk)
       (goto-char (swift-mode:chunk:start chunk))
-      (forward-comment (point-max)))))
+      (setq comment-start (point))
+      (forward-comment 1)
+      (put-text-property comment-start (point) 'swift-mode:comment t))))
   (swift-mode:syntax-propertize:scan end 0))
 
 (defun swift-mode:syntax-propertize:scan (end nesting-level)
   "Update text properties for strings.
-Mark the beginning of and the end of single-line/multiline strings between
-the current position and END as general string delimiters.
-Assuming the cursor is not on strings nor comments.
+Mark the beginning of and the end of single-line/multiline strings and regexes
+between the current position and END as general string delimiters.
+Assuming the cursor is not on strings, regexes, nor comments.
 If NESTING-LEVEL is non-zero, nesting of parentheses are tracked and the scan
 stops where the level becomes zero."
   (let ((found-matching-parenthesis nil)
         (pattern (mapconcat #'regexp-quote
-                            '("\"\"\"" "\"" "//" "/*" "(" ")")
+                            '("\"\"\"" "\"" "/" "(" ")")
                             "\\|")))
     (while (and (not found-matching-parenthesis)
                 (< (point) end)
@@ -262,8 +271,8 @@ stops where the level becomes zero."
       (cond
        ((member (match-string-no-properties 0) '("\"\"\"" "\""))
         (let ((start (match-beginning 0))
-              (pound-count 0)
-              (quotation (match-string-no-properties 0)))
+              (quotation (match-string-no-properties 0))
+              pound-count)
           (save-excursion
             (goto-char start)
             (skip-chars-backward "#")
@@ -274,15 +283,31 @@ stops where the level becomes zero."
                              (string-to-syntax "|"))
           (swift-mode:syntax-propertize:end-of-string
            end quotation pound-count)
-          (put-text-property start (point) 'syntax-multiline t)))
+          (swift-mode:put-syntax-multiline-property start (point))))
+
+       ((equal "/" (match-string-no-properties 0))
+        (let ((start (match-beginning 0))
+              regex-start)
+          (save-excursion
+            (goto-char start)
+            (skip-chars-backward "#")
+            (setq regex-start (point)))
+          (cond
+           ;; Regexes
+           ((swift-mode:syntax-propertize:end-of-regex regex-start)
+            (put-text-property regex-start (1+ regex-start)
+                               'syntax-table
+                               (string-to-syntax "|"))
+            (swift-mode:put-syntax-multiline-property regex-start (point)))
 
-       ((equal "//" (match-string-no-properties 0))
-        (goto-char (match-beginning 0))
-        (forward-comment (point-max)))
+           ;; Comments
+           ((memq (char-after) '(?/ ?*))
+            (goto-char start)
+            (forward-comment 1)
+            (put-text-property start (point) 'swift-mode:comment t))
 
-       ((equal "/*" (match-string-no-properties 0))
-        (goto-char (match-beginning 0))
-        (forward-comment (point-max)))
+           ;; Operators
+           (t nil))))
 
        ((and (equal "(" (match-string-no-properties 0))
              (/= nesting-level 0))
@@ -297,6 +322,17 @@ stops where the level becomes zero."
       (goto-char end))
     found-matching-parenthesis))
 
+(defun swift-mode:put-syntax-multiline-property (start end)
+  "Put `syntax-multiline` text propery from START to END.
+
+Also call `font-lock-flush' with START and END."
+  (put-text-property start end 'syntax-multiline t)
+  (if (fboundp 'font-lock-flush)
+      (font-lock-flush start end)
+    (if (eq font-lock-fontify-buffer-function #'jit-lock-refontify)
+        (jit-lock-refontify start end)
+      (font-lock-after-change-function start end (- end start)))))
+
 (defun swift-mode:syntax-propertize:end-of-string (end quotation pound-count)
   "Move point to the end of single-line/multiline string.
 
@@ -378,6 +414,143 @@ Return nil otherwise."
          (setq p (1- p)))
        (= (mod backslash-count 2) 1)))))
 
+(defun swift-mode:syntax-propertize:end-of-regex (start)
+  "Move point to the end of regex if any.
+
+START is the position of the open delimiter, including pounds if any.
+
+If START is not a start of a regex, keep the point and return nil.  Otherwise,
+return non-nil.
+
+This function doesn't take end parameter since if the closing delimiter is
+missing, this function must return nil."
+  (let* ((pound-count (save-excursion
+                        (goto-char start)
+                        (skip-chars-forward "#")
+                        (- (point) start)))
+         end-of-regex)
+    (setq end-of-regex
+          (if (zerop pound-count)
+              (swift-mode:syntax-propertize:end-of-basic-regex start)
+            (swift-mode:syntax-propertize:end-of-extended-regex
+             start
+             pound-count)))
+    (when end-of-regex
+      (put-text-property (1- end-of-regex) end-of-regex
+                         'syntax-table
+                         (string-to-syntax "|")))
+    end-of-regex))
+
+(defun swift-mode:syntax-propertize:end-of-basic-regex (start)
+  "Move point to the end of regex if any.
+
+START is the position of the open delimiter.
+
+If START is not a start of a regex, keep the point and return nil.  Otherwise,
+return non-nil."
+  (let* ((pos (point))
+         (start-of-contents (1+ start))
+         after-last-dot
+         (square-brackets-count 0)
+         (parentheses-count 0)
+         (limit (line-end-position))
+         (end-of-regex nil))
+    (if (or
+         ;; Cannot starts with spaces, tabs, slashes, or asterisks.
+         (memq (char-after start-of-contents) '(?\s ?\t ?/ ?*))
+         ;; Cannot be a comment closer: /**/+++/.
+         (get-text-property start 'swift-mode:comment)
+         ;; Cannot be preceded with infix operators while it can be preceded
+         ;; with prefix operators.
+         (save-excursion
+           (goto-char start)
+           ;; TODO Unicode operators
+           (skip-chars-backward "-/=+!*%<>&|^~?")
+           (when (eq (char-before) ?.)
+             (setq after-last-dot (point))
+             (skip-chars-backward "-/=+!*%<>&|^~?.")
+             (unless (eq (char-after) ?.)
+               (goto-char (1- after-last-dot))))
+           (and
+            ;; preceded with an operator
+            (/= start (point))
+            ;; it is not a prefix operator
+            (not (memq (char-before)
+                       '(nil ?\s ?\t ?\[ ?\( ?{ ?, ?\; ?:)))
+            ;; it does't contain comments: a/**/+/**//b /
+            (not (text-property-any (point) start 'swift-mode:comment t)))))
+        nil
+      (goto-char start-of-contents)
+      (while (and (null end-of-regex)
+                  (search-forward-regexp "[][()\\/]" limit t))
+        (cond
+         ((eq (char-before) ?\\)
+          (forward-char))
+         ((eq (char-before) ?\[)
+          (setq square-brackets-count (1+ square-brackets-count)))
+         ((eq (char-before) ?\])
+          (when (< 0 square-brackets-count)
+            (setq square-brackets-count (1- square-brackets-count))))
+         ((eq (char-before) ?\()
+          (when (zerop square-brackets-count)
+            (setq parentheses-count (1+ parentheses-count))))
+         ((eq (char-before) ?\))
+          (cond
+           ((< 0 square-brackets-count)
+            nil)
+           ((zerop parentheses-count)
+            ;; Found an unmatching close parenthesis.  This is not a regex
+            ;; literal.
+            (goto-char limit))
+           (t
+            (setq parentheses-count (1- parentheses-count)))))
+         ((eq (char-before) ?/)
+          (if (memq (char-after) '(?/ ?*))
+              (goto-char limit)
+            (setq end-of-regex (point)))))))
+    (unless end-of-regex
+      (goto-char pos))
+    end-of-regex))
+
+(defun swift-mode:syntax-propertize:end-of-extended-regex (start pound-count)
+  "Move point to the end of extended regex if any.
+
+START is the position of the open delimiter, including pounds of POUND-COUNT.
+
+If START is not a start of a regex, keep the point and return nil.  Otherwise,
+return non-nil."
+  (let* ((pos (point))
+         (start-of-contents (1+ (+ start pound-count)))
+         (starts-with-line-break (save-excursion
+                                   (goto-char start-of-contents)
+                                   (skip-chars-forward "\s\t")
+                                   (eolp)))
+         (end-of-regex nil))
+    (goto-char start-of-contents)
+    (if starts-with-line-break
+        (while (and (null end-of-regex)
+                    (zerop (forward-line)))
+          (skip-chars-forward "\s\t")
+          (when (and (eq (char-after) ?/)
+                     (progn
+                       (forward-char)
+                       (eq (skip-chars-forward "#" (+ (point) pound-count))
+                           pound-count)))
+            (setq end-of-regex (point))))
+      (while (and (null end-of-regex)
+                  (search-forward-regexp "/#" (line-end-position) t))
+        (backward-char)
+        (when (and (eq (skip-chars-forward "#" (+ (point) pound-count))
+                       pound-count)
+                   ;; Inside regex literal, backslashes without pounds are
+                   ;; still special.
+                   (not (swift-mode:escaped-p (match-beginning 0) 0)))
+          (setq end-of-regex (point)))))
+    (unless end-of-regex
+      (swift-mode:put-syntax-multiline-property start (point))
+      (goto-char pos))
+    end-of-regex))
+
 ;;; Lexers
 
 (defun swift-mode:implicit-semi-p ()
@@ -785,11 +958,13 @@ Other properties are the same as the TOKEN."
        (has-preceding-space (or
                              (= start (point-min))
                              (memq (char-syntax (char-before start)) '(?  ?>))
+                             (memq (char-before start) '(?\( ?\[ ?{ ?, ?\; ?:))
                              (nth 4 (save-excursion
                                       (syntax-ppss (1- start))))))
        (has-following-space (or
                              (= end (point-max))
                              (memq (char-syntax (char-after end)) '(?  ?<))
+                             (memq (char-after end) '(?\) ?\] ?} ?, ?\; ?:))
                              (save-excursion (goto-char end)
                                              (looking-at "/\\*\\|//"))
                              (= (char-after end) ?\C-j)))
@@ -953,23 +1128,40 @@ This function does not return `implicit-;' or `type-:'."
     (forward-char)
     (swift-mode:token '> ">" (1- (point)) (point)))
 
+   ;; Regex
+   ((and (looking-at "#*/")
+         (equal (get-text-property (match-beginning 0) 'syntax-table)
+                (string-to-syntax "|")))
+    (let ((pos-after-comment (point)))
+      (swift-mode:forward-string-chunk)
+      (swift-mode:token
+       'identifier
+       (buffer-substring-no-properties pos-after-comment (point))
+       pos-after-comment
+       (point))))
+
    ;; Operator (other than as, try, is, or await)
    ;;
    ;; Operators starts with a dot can contains dots. Other operators cannot
    ;; contain dots.
    ;;
    ;; 
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/dot-operator-head
+   ;; TODO Unicode operators
    ((looking-at "[-/=+!*%<>&|^~?]+\\|[.][-./=+!*%<>&|^~?]*")
-    (let*
-        ((text (match-string-no-properties 0))
-         (start (match-beginning 0))
-         (end (match-end 0)))
-      (when (string-match ".*/\\*\\|.*//" text)
+    (let* ((text (match-string-no-properties 0))
+           (start (match-beginning 0))
+           (end (match-end 0)))
+      (when (string-match "^.*?/\\*\\|^.*?//" text)
         ;; e.g. +++/* */ or +++//
-        (setq end
-              (- end
-                 (- (length text) (- (match-end 0) 2))))
+        (setq end (- end (- (length text) (- (match-end 0) 2))))
         (setq text (substring text 0 (- (match-end 0) 2))))
+      (when (and (string-match "^.*?/" text)
+                 (equal (get-text-property (+ start (1- (match-end 0)))
+                                           'syntax-table)
+                        (string-to-syntax "|")))
+        ;; Regex after prefix operator, e.g. +++/<>/
+        (setq end (- end (- (length text) (- (match-end 0) 1))))
+        (setq text (substring text 0 (- (match-end 0) 1))))
       (goto-char end)
       (swift-mode:fix-operator-type
        (swift-mode:token nil text start end))))
@@ -1206,12 +1398,27 @@ This function does not return `implicit-;' or `type-:'."
     (backward-char)
     (swift-mode:token '> ">" (point) (1+ (point))))
 
+   ;; Regex
+   ((and (save-excursion
+           (skip-chars-backward "#")
+           (eq (char-before) ?/))
+         (equal (get-text-property (1- (point)) 'syntax-table)
+                (string-to-syntax "|")))
+    (let ((pos-before-comment (point)))
+      (swift-mode:backward-string-chunk)
+      (swift-mode:token
+       'identifier
+       (buffer-substring-no-properties (point) pos-before-comment)
+       (point)
+       pos-before-comment)))
+
    ;; Operator (other than as, try, is, or await)
    ;;
    ;; Operators which starts with a dot can contain other dots. Other
    ;; operators cannot contain dots.
    ;;
    ;; 
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/dot-operator-head
+   ;; TODO Unicode operators
    ((memq (char-before) '(?. ?- ?/ ?= ?+ ?! ?* ?% ?< ?> ?& ?| ?^ ?~ ??))
     (let ((point-before-comments (point)))
       (skip-chars-backward "-./=+!*%<>&|^~?")
@@ -1385,7 +1592,7 @@ If this line ends with a single-line comment, goto just 
before the comment."
 
 ;;; Comment or string chunks
 
-;; A chunk is either a string-chunk or a comment.
+;; A chunk is either a string-chunk, regex, or a comment.
 ;; It have the type and the start position.
 
 (defun swift-mode:chunk (type start)
@@ -1433,12 +1640,16 @@ If this line ends with a single-line comment, goto just 
before the comment."
   "Return non-nil if the CHUNK is a multiline string."
   (eq (swift-mode:chunk:type chunk) 'multiline-string))
 
+(defun swift-mode:chunk:regex-p (chunk)
+  "Return non-nil if the CHUNK is a regex."
+  (eq (swift-mode:chunk:type chunk) 'regex))
+
 (defun swift-mode:chunk:pound-count (chunk)
   "Return the number of pound signs before the start position of the CHUNK."
   (save-excursion
     (goto-char (swift-mode:chunk:start chunk))
     (swift-mode:beginning-of-string)
-    (skip-chars-backward "#")
+    (skip-chars-forward "#")
     (- (swift-mode:chunk:start chunk) (point))))
 
 (defun swift-mode:chunk-after (&optional parser-state)
@@ -1457,10 +1668,14 @@ If PARSER-STATE is given, it is used instead of 
(syntax-ppss)."
       ;; Syntax category "|" is attached to both single-line and multiline
       ;; string delimiters.  So (nth 3 parser-state) may be t even for
       ;; single-line string delimiters.
-      (if (save-excursion (goto-char (nth 8 parser-state))
-                          (looking-at "#*\"\"\""))
-          (swift-mode:chunk 'multiline-string (nth 8 parser-state))
-        (swift-mode:chunk 'single-line-string (nth 8 parser-state))))
+      (cond
+       ((save-excursion (goto-char (nth 8 parser-state))
+                        (looking-at "#*\"\"\""))
+        (swift-mode:chunk 'multiline-string (nth 8 parser-state)))
+       ((save-excursion (goto-char (nth 8 parser-state))
+                        (looking-at "#*/"))
+        (swift-mode:chunk 'regex (nth 8 parser-state)))
+       (t (swift-mode:chunk 'single-line-string (nth 8 parser-state)))))
 
      ((eq (nth 4 parser-state) t)
       (swift-mode:chunk 'single-line-comment (nth 8 parser-state)))
diff --git a/test/swift-files/indent/strings.swift 
b/test/swift-files/indent/strings.swift
index 862dde71ec..044bd52208 100644
--- a/test/swift-files/indent/strings.swift
+++ b/test/swift-files/indent/strings.swift
@@ -161,4 +161,174 @@ func f() {
     let x = #"abc\( 1 + (2 + 3) ) \#( 1 + (2 + 3) ) \" \#"# " a \"#
     let x = ##"abc\( 1 + (2 + 3) ) \#( 1 + (2 + 3) ) \" \#"# " a \"##
     let x = 1
+
+
+    // Regexes
+
+    // Simple case.
+    let x = /a/
+
+    // Slashes can be escaped.
+    let x = /\/ /
+
+    // Slashes must be escaped in character classes.
+    let x = /[/ + "]/ + // "
+    let x = /[\/ + "]/ + // "
+      a()
+
+    // Regexes can contain quotes.
+    let x = /"/
+    let x = /"""/
+
+    // Regex with extended delimiters can contain slashes.
+    let x = #// /* /#
+
+    // Backslashes are still special in regexes with extended delimiters.
+    let x = #/\/# /* /#
+    a()
+
+    // Multiline regex.
+    let x = #/
+      let x = #/
+      /#
+
+    // Closing extended delimiter can be escaped.
+    let x = #/
+      \/#
+      let x = #/
+      /#
+
+    // Extended delimiters with more than one pound.
+    let x = ##/
+      /#
+      let x = #/
+      /##
+
+    // Comments are ignored in exended regexes.
+    let x = #/
+      let x = "a" # /#
+      /#
+
+    // Multiline comment cannot contain regexes with */.
+    /*
+     let regex = /[0-9]*/
+    let x = "*/ // "
+
+
+    // Regexes without extended delimiters cannot be preceded by infix
+    // operators without whitespaces.
+    // `a`, infix operator `+/`, `b`, and infix operator `/`
+    let x = a+/b /
+      c()
+
+    // Regexes without extended delimiters can be preceded by infix operators
+    // with whitespaces.
+    // `a`, infix operator `+`, and regex /b /
+    let x = a + /b /
+    c()
+
+    // Comments are whitespaces.
+    let x = a/**/+/**//b /
+    c()
+
+    // Regexes with extended delimiters can be preceded by infix operators
+    // without whitespaces.
+    // `a`, infix operator `+`, and regex #/b /#
+    let x = a+#/b /#
+    c()
+
+    // Regexes without extended delimiters cannot start with spaces.
+    let regex = Regex {
+        digit
+          / [+-] /
+          digit
+    }
+    let regex = Regex {
+        digit
+        /[+-]/
+        digit
+    }
+
+    // Initial space must be escaped.
+    let regex = Regex {
+        digit
+        /\ [+-] /
+        digit
+    }
+
+    // Regexes with extended delimiters can start with spaces.
+    let regex = Regex {
+        digit
+        #/ [+-] /#
+        digit
+    }
+
+    foo {
+        // This must be infix operator /^/.
+        let a = b() /^/
+          c() // swift-mode:test:known-bug
+    }
+
+    foo {
+        // Regex /^/, infix operator /^/, and b().
+        let a = /^/ /^/
+          b() // swift-mode:test:known-bug
+    }
+
+    foo {
+        // Regex /^/, infix operator /^/, regex /^/, and b()
+        let a = /^/ /^/ /^/
+        b()
+    }
+
+    // Regex without extended delimiters cannot be multiline.
+    // Also, it cannot end with // or /*
+    let a = /0 + // /
+      b()
+    let a = /0 + /* /
+                    b()
+                  */
+      c()
+
+    // Regexes can be preceded with prefix operators wihtout spaces.
+    // prefix operator `+` and regex /a /.
+    let x = +/a /
+    b()
+
+    // Regexes without extended delimiters cannot contain unmatching close
+    // parentheses.
+    array.reduce(1, /) { otherArray.reduce(1, /)
+                         array.reduce(1, /) }; otherArray.reduce(1, /)
+
+    // Regexes without extended delimiters can contain matching close
+    // parentheses.
+    array.reduce(1, /(a) { otherArray.reduce(1, /)
+    array.reduce(1, /(a) }; otherArray.reduce(1, /)
+
+    // Regexes without extended delimiters can contain escaped close
+    // parentheses.
+    array.reduce(1, /\) { otherArray.reduce(1, /)
+    array.reduce(1, /\) }; otherArray.reduce(1, /)
+
+    // Character classes can contain closing parentheses.
+    array.reduce(1, /[)] { otherArray.reduce(1, /)
+    array.reduce(1, /[)] }; otherArray.reduce(1, /)
+
+    // Regexes with extended delimiters can contain unmatching close
+    // parentheses.
+    array.reduce(1, #/) { otherArray.reduce(1, /#)
+    array.reduce(1, #/) }; otherArray.reduce(1, /#)
+
+
+    // Regexes can contain unmatching close square brackets.
+    let d = a[/] /
+    ]
+    let d = a[(/)] /
+      b()
+
+    // Comments have higher precedence.
+    let x = a() /**/+++/
+      b()
+    let x = a() //+++/
+    b()
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]