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

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

[elpa] externals/js2-mode b3841a7 24/61: Merge pull request #533 from re


From: Dmitry Gutov
Subject: [elpa] externals/js2-mode b3841a7 24/61: Merge pull request #533 from redguardtoo/master
Date: Sun, 20 Dec 2020 12:20:02 -0500 (EST)

branch: externals/js2-mode
commit b3841a7a304d9d1328fdb0868fbbecf0c2f9831f
Merge: 999c0e7 8841175
Author: Dmitry Gutov <dgutov@yandex.ru>
Commit: GitHub <noreply@github.com>

    Merge pull request #533 from redguardtoo/master
    
    support optional chaining operator
---
 NEWS.md         |  1 +
 js2-mode.el     | 36 +++++++++++++++++++++++++++++++++---
 tests/parser.el | 21 +++++++++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index b3163a4..7fc9a6e 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -7,6 +7,7 @@
   `js-mode` with `js2-minor-mode` (see README), rather than
   `js2-jsx-mode`.
 * Using `js2-jsx-mode` will now trigger a warning in Emacs 27.
+* Support for optional-chaining operator `?.`
 
 ## 2019-02-19
 
diff --git a/js2-mode.el b/js2-mode.el
index 4686be8..c05be21 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -635,7 +635,8 @@ which doesn't seem particularly useful, but Rhino permits 
it."
 (defvar js2-AWAIT 169)  ; await (pseudo keyword)
 
 (defvar js2-HOOK 170)          ; conditional (?:)
-(defvar js2-EXPON 171)
+(defvar js2-OPTIONAL-CHAINING 171) ; optional chaining (?.prop obj?.[expr] 
func?.())
+(defvar js2-EXPON 172)
 
 (defconst js2-num-tokens (1+ js2-EXPON))
 
@@ -1656,6 +1657,9 @@ the correct number of ARGS must be provided."
 (js2-msg "msg.no.colon.cond"
          "missing : in conditional expression")
 
+(js2-msg "msg.bad.optional.chaining"
+         "missing property name or [ or ( after optional chaining operator")
+
 (js2-msg "msg.no.paren.arg"
          "missing ) after argument list")
 
@@ -6074,7 +6078,9 @@ its relevant fields and puts it into `js2-ti-tokens'."
                           (?,
                            (throw 'return js2-COMMA))
                           (??
-                           (throw 'return js2-HOOK))
+                           (if (js2-match-char ?.)
+                               (throw 'return js2-OPTIONAL-CHAINING)
+                             (throw 'return js2-HOOK)))
                           (?:
                            (if (js2-match-char ?:)
                                js2-COLONCOLON
@@ -10276,6 +10282,24 @@ Returns the list in reverse order.  Consumes the 
right-paren token."
         (setf (js2-node-len pn) (- end beg)))  ; end outer if
     (js2-parse-member-expr-tail allow-call-syntax pn)))
 
+(defun js2-parse-optional-chaining-operator (allow-call-syntax pn)
+  (let ((tt (js2-peek-token)))
+    (cond
+     ((eq tt js2-NAME)
+      (setq pn (js2-parse-property-access js2-DOT pn)))
+     ((eq tt js2-LB)
+      ;; skip left bracket token
+      (js2-get-token)
+      (setq pn (js2-parse-element-get pn)))
+     ((and (eq tt js2-LP) allow-call-syntax)
+      ;; unget optional chaining operator
+      ;; so current token is function name and could be highlighted
+      (js2-unget-token)
+      (setq pn (js2-parse-function-call pn t)))
+     (t
+      (js2-report-error "msg.bad.optional.chaining")))
+    pn))
+
 (defun js2-parse-member-expr-tail (allow-call-syntax pn)
   "Parse a chain of property/array accesses or function calls.
 Includes parsing for E4X operators like `..' and `.@'.
@@ -10288,6 +10312,9 @@ Returns an expression tree that includes PN, the parent 
node."
       (cond
        ((or (= tt js2-DOT) (= tt js2-DOTDOT))
         (setq pn (js2-parse-property-access tt pn)))
+       ((= tt js2-OPTIONAL-CHAINING)
+        (setq pn (js2-parse-optional-chaining-operator allow-call-syntax pn))
+        (unless pn (setq continue nil)))
        ((= tt js2-DOTQUERY)
         (setq pn (js2-parse-dot-query pn)))
        ((= tt js2-LB)
@@ -10365,11 +10392,14 @@ Last token parsed must be `js2-RB'."
   (when (eq (js2-token-type token) js2-NAME)
     (js2-record-face 'js2-function-call token)))
 
-(defun js2-parse-function-call (pn)
+(defun js2-parse-function-call (pn &optional use-optional-chaining-p)
   (js2-highlight-function-call (js2-current-token))
   (js2-get-token)
   (let (args
         (pos (js2-node-pos pn)))
+    (when use-optional-chaining-p
+      ;; skip optional chaining operator
+      (js2-get-token))
     (setq pn (make-js2-call-node :pos pos
                                  :target pn
                                  :lp (- (js2-current-token-beg) pos)))
diff --git a/tests/parser.el b/tests/parser.el
index 88d3dab..c87fa5f 100644
--- a/tests/parser.el
+++ b/tests/parser.el
@@ -990,6 +990,27 @@ the test."
 (js2-deftest-parse exponentiation-prohibits-unary-op
   "var a = -b ** c" :syntax-error "-b")
 
+(js2-deftest optional-chaining-operator-on-property-access
+  "var a = {}; a?.b;"
+  (js2-mode--and-parse)
+  (let ((node (js2-find-node js2-mode-ast 'js2-name-node-p)))
+    (should node)
+    (should (string= (js2-node-text node) "b"))))
+
+(js2-deftest optional-chaining-operator-on-get-element
+  "var a = []; a?.[99];"
+  (js2-mode--and-parse)
+  (let ((node (js2-find-node js2-mode-ast 'js2-number-node-p)))
+    (should node)
+    (should (string= (js2-node-text node) "99"))))
+
+(js2-deftest optional-chaining-operator-on-functioncall
+  "var a = function(b){}; a?.(99);"
+  (js2-mode--and-parse)
+  (let ((node (js2-find-node js2-mode-ast 'js2-number-node-p)))
+    (should node)
+    (should (string= (js2-node-text node) "99"))))
+
 (js2-deftest unary-void-node-start
   "var c = void 0"
   (js2-mode--and-parse)



reply via email to

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