]> code.delx.au - gnu-emacs-elpa/commitdiff
Support initializer in destructuring
authorCarl Lei <xecycle@gmail.com>
Fri, 16 Oct 2015 03:31:22 +0000 (11:31 +0800)
committerCarl Lei <xecycle@gmail.com>
Fri, 30 Oct 2015 03:26:14 +0000 (11:26 +0800)
Also known as default arguments.

NEWS.md
js2-mode.el
tests/parser.el

diff --git a/NEWS.md b/NEWS.md
index aa04a4227fe593f6c148c6e2b710e1524ce5db35..30500e04493d1f26faf4798ec1bc0c3683704686 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,6 +8,8 @@
   with its related functions.  It already handles generator methods,
   and will in the future add support for async methods, so the old
   name will get more confusing.
+* Support for default parameters in destructuring.  It should work for both
+  objects and arrays, in both literals and function arguments.
 
 ## 20150909
 
index 865f287596df5776c14e0161b37369d38ad5e371..249f4ca8b03ec2c751b18fb5c23b2f5c0479a551 100644 (file)
@@ -8003,16 +8003,18 @@ declared; probably to check them for errors."
         (list node)))
      ((js2-object-node-p node)
       (dolist (elem (js2-object-node-elems node))
-        (when (js2-object-prop-node-p elem)
+        ;; js2-infix-node-p catches both object prop node and initialized
+        ;; binding element (which is directly an infix node).
+        (when (js2-infix-node-p elem)
           (push (js2-define-destruct-symbols
-                 ;; In abbreviated destructuring {a, b}, right == left.
-                 (js2-object-prop-node-right elem)
+                 (js2-infix-node-left elem)
                  decl-type face ignore-not-in-block)
                 name-nodes)))
       (apply #'append (nreverse name-nodes)))
      ((js2-array-node-p node)
       (dolist (elem (js2-array-node-elems node))
         (when elem
+          (if (js2-infix-node-p elem) (setq elem (js2-infix-node-left elem)))
           (push (js2-define-destruct-symbols
                  elem decl-type face ignore-not-in-block)
                 name-nodes)))
@@ -9632,7 +9634,7 @@ If NODE is non-nil, it is the AST node associated with the symbol."
       (js2-node-add-children pn test-expr if-true if-false))
     pn))
 
-(defun js2-make-binary (type left parser)
+(defun js2-make-binary (type left parser &optional no-get)
   "Helper for constructing a binary-operator AST node.
 LEFT is the left-side-expression, already parsed, and the
 binary operator should have just been matched.
@@ -9643,7 +9645,7 @@ FIXME: The latter option is unused?"
          (op-pos (- (js2-current-token-beg) pos))
          (right (if (js2-node-p parser)
                     parser
-                  (js2-get-token)
+                  (unless no-get (js2-get-token))
                   (funcall parser)))
          (pn (make-js2-infix-node :type type
                                   :pos pos
@@ -10364,14 +10366,20 @@ array-literals, array comprehensions and regular expressions."
         (apply #'js2-node-add-children pn (js2-array-node-elems pn)))
        ;; destructuring binding
        (js2-is-in-destructuring
-        (push (if (or (= tt js2-LC)
-                      (= tt js2-LB)
-                      (= tt js2-NAME))
-                  ;; [a, b, c] | {a, b, c} | {a:x, b:y, c:z} | a
-                  (js2-parse-destruct-primary-expr)
-                ;; invalid pattern
+        (push (cond
+               ((and (= tt js2-NAME)
+                     (= js2-ASSIGN (js2-peek-token)))
+                ;; a=defaultValue
+                (js2-parse-initialized-binding (js2-parse-name js2-NAME)))
+               ((or (= tt js2-LC)
+                    (= tt js2-LB)
+                    (= tt js2-NAME))
+                ;; [a, b, c] | {a, b, c} | {a:x, b:y, c:z} | a
+                (js2-parse-destruct-primary-expr))
+               ;; invalid pattern
+               (t
                 (js2-report-error "msg.bad.var")
-                (make-js2-error-node))
+                (make-js2-error-node)))
               elems)
         (setq after-lb-or-comma nil
               after-comma nil))
@@ -10714,6 +10722,10 @@ When `js2-is-in-destructuring' is t, forms like {a, b, c} will be permitted."
       (when (js2-name-node-p key)  ; highlight function name properties
         (js2-record-face 'font-lock-function-name-face))
       (js2-parse-method-prop pos key property-type))
+     ;; binding element with initializer
+     ((and (= (js2-peek-token) js2-ASSIGN)
+           (>= js2-language-version 200))
+      (js2-parse-initialized-binding key))
      ;; regular prop
      (t
       (let ((beg (js2-current-token-beg))
@@ -10732,6 +10744,13 @@ When `js2-is-in-destructuring' is t, forms like {a, b, c} will be permitted."
                       'record)
         expr)))))
 
+(defun js2-parse-initialized-binding (name)
+  "Parse a `SingleNameBinding' with initializer.
+
+`name' is the `BindingIdentifier'."
+  (when (js2-match-token js2-ASSIGN)
+    (js2-make-binary js2-ASSIGN name 'js2-parse-assign-expr t)))
+
 (defun js2-parse-prop-name (tt)
   (cond
    ;; Literal string keys: {'foo': 'bar'}
index c65be2c3bdfa1046a3f15c380e64fcc8771418bf..51b03eb56690b8a39914f15134a26fa34f7e8b78 100644 (file)
@@ -178,6 +178,26 @@ the test."
 (js2-deftest-parse destruct-in-catch-clause
   "try {\n} catch ({a, b}) {\n  a + b;\n}")
 
+(js2-deftest-parse destruct-with-initializer-in-object
+  "var {a, b = 2, c} = {};")
+
+(js2-deftest-parse destruct-with-initializer-in-array
+  "var [a, b = 2, c] = [];")
+
+(js2-deftest-parse destruct-non-name-target-is-error
+  "var {1=1} = {};" :syntax-error "1" :errors-count 1)
+
+(js2-deftest-parse destruct-with-initializer-in-function-arguments
+  "function f({a, b = 1, c}, [d, e = 1, f]) {\n}")
+
+(js2-deftest-parse destruct-name-conflict-is-error-in-object
+  "\"use strict\";\nvar {a=1,a=2} = {};" :syntax-error "a" :errors-count 1)
+
+(js2-deftest destruct-name-conflict-is-warning-in-array "\"use strict\";\nvar [a=1,a=2] = [];"
+  (js2-mode)
+  (should (equal '("msg.var.redecl" "a")
+                 (caar js2-parsed-warnings))))
+
 ;;; Object literals
 
 (js2-deftest-parse object-literal-shorthand