[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] 14/46: Support ES6 generator comprehensions
From: |
Dmitry Gutov |
Subject: |
[elpa] 14/46: Support ES6 generator comprehensions |
Date: |
Sat, 15 Nov 2014 20:58:00 +0000 |
dgutov pushed a commit to branch master
in repository elpa.
commit 62bb757e14a220da24858b9ad40785dc892dea51
Author: Dmitry Gutov <address@hidden>
Date: Wed Jul 9 06:29:15 2014 +0300
Support ES6 generator comprehensions
Fixes #145
---
js2-mode.el | 71 +++++++++++++++++++++++++++++++++++++-----------------
tests/parser.el | 16 ++++++++++++
2 files changed, 64 insertions(+), 23 deletions(-)
diff --git a/js2-mode.el b/js2-mode.el
index 3418d9d..e7b37a5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2980,7 +2980,7 @@ The `params' field is a Lisp list of nodes. Each node is
either a simple
rp ; position of arg-list close-paren, or nil if omitted
ignore-dynamic ; ignore value of the dynamic-scope flag (interpreter only)
needs-activation ; t if we need an activation object for this frame
- generator-type ; STAR, LEGACY or nil
+ generator-type ; STAR, LEGACY, COMPREHENSION or nil
member-expr) ; nonstandard Ecma extension from Rhino
(put 'cl-struct-js2-function-node 'js2-visitor 'js2-visit-function-node)
@@ -3705,8 +3705,9 @@ as opposed to required parens such as those enclosing an
if-conditional."
(result (js2-comp-node-result n))
(loops (js2-comp-node-loops n))
(filters (js2-comp-node-filters n))
- (legacy-p (eq (js2-comp-node-form n) 'LEGACY_ARRAY)))
- (insert pad "[")
+ (legacy-p (eq (js2-comp-node-form n) 'LEGACY_ARRAY))
+ (gen-p (eq (js2-comp-node-form n) 'STAR_GENERATOR)))
+ (insert pad (if gen-p "(" "["))
(when legacy-p
(js2-print-ast result 0))
(dolist (l loops)
@@ -3725,7 +3726,7 @@ as opposed to required parens such as those enclosing an
if-conditional."
(insert " ")))
(unless legacy-p
(js2-print-ast result 0))
- (insert "]")))
+ (insert (if gen-p ")" "]"))))
(defstruct (js2-comp-loop-node
(:include js2-for-in-node)
@@ -8131,18 +8132,19 @@ but not BEFORE."
(= (logand after mask) mask)))
(defun js2-parse-return-or-yield (tt expr-context)
- (let ((pos (js2-current-token-beg))
- (end (js2-current-token-end))
- (before js2-end-flags)
- (inside-function (js2-inside-function))
- e ret name yield-star-p)
+ (let* ((pos (js2-current-token-beg))
+ (end (js2-current-token-end))
+ (before js2-end-flags)
+ (inside-function (js2-inside-function))
+ (gen-type (and inside-function (js2-function-node-generator-type
+ js2-current-script-or-fn)))
+ e ret name yield-star-p)
(unless inside-function
(js2-report-error (if (eq tt js2-RETURN)
"msg.bad.return"
"msg.bad.yield")))
(when (and inside-function
- (eq (js2-function-node-generator-type js2-current-script-or-fn)
- 'STAR)
+ (eq gen-type 'STAR)
(js2-match-token js2-MUL))
(setq yield-star-p t))
;; This is ugly, but we don't want to require a semicolon.
@@ -8170,6 +8172,10 @@ but not BEFORE."
(js2-now-all-set before js2-end-flags
(logior js2-end-returns
js2-end-returns-value)))
(js2-add-strict-warning "msg.return.inconsistent" nil pos end)))
+ ((eq gen-type 'COMPREHENSION)
+ ;; FIXME: We should probably switch to saving and using lastYieldOffset,
+ ;; like SpiderMonkey does.
+ (js2-report-error "msg.syntax" nil pos 5))
(t
(setq ret (make-js2-yield-node :pos pos
:len (- end pos)
@@ -8487,6 +8493,20 @@ If NODE is non-nil, it is the AST node associated with
the symbol."
(js2-define-new-symbol decl-type name node))
(t (js2-code-bug)))))
+(defun js2-parse-paren-expr-or-generator-comp ()
+ (let ((px-pos (js2-current-token-beg)))
+ (if (and (>= js2-language-version 200)
+ (js2-match-token js2-FOR))
+ (js2-parse-generator-comp px-pos)
+ (let* ((expr (js2-parse-expr))
+ (pn (make-js2-paren-node :pos px-pos
+ :expr expr
+ :len (- (js2-current-token-end)
+ px-pos))))
+ (js2-node-add-children pn (js2-paren-node-expr pn))
+ (js2-must-match js2-RP "msg.no.paren")
+ pn))))
+
(defun js2-parse-expr (&optional oneshot)
(let* ((pn (js2-parse-assign-expr))
(pos (js2-node-pos pn))
@@ -9163,14 +9183,7 @@ array-literals, array comprehensions and regular
expressions."
((= tt js2-LET)
(js2-parse-let (js2-current-token-beg)))
((= tt js2-LP)
- (setq px-pos (js2-current-token-beg)
- expr (js2-parse-expr))
- (js2-must-match js2-RP "msg.no.paren")
- (setq pn (make-js2-paren-node :pos px-pos
- :expr expr
- :len (- (js2-current-token-end) px-pos)))
- (js2-node-add-children pn (js2-paren-node-expr pn))
- pn)
+ (js2-parse-paren-expr-or-generator-comp))
((= tt js2-XMLATTR)
(js2-must-have-xml)
(js2-parse-attribute-access))
@@ -9338,7 +9351,7 @@ EXPR is the first expression after the opening
left-bracket.
POS is the beginning of the LB token preceding EXPR.
We should have just parsed the 'for' keyword before calling this function."
(let ((current-scope js2-current-scope)
- loops first filter if-pos result)
+ loops first filter result)
(unwind-protect
(progn
(while (js2-match-token js2-FOR)
@@ -9371,7 +9384,20 @@ We should have just parsed the 'for' keyword before
calling this function."
"Parse an ES6 array comprehension.
POS is the beginning of the LB token.
We should have just parsed the 'for' keyword before calling this function."
- (let (loops filters if-pos expr result)
+ (let ((pn (js2-parse-comprehension pos 'ARRAY)))
+ (js2-must-match js2-RB "msg.no.bracket.arg" pos)
+ pn))
+
+(defun js2-parse-generator-comp (pos)
+ (let* ((js2-nesting-of-function (1+ js2-nesting-of-function))
+ (js2-current-script-or-fn
+ (make-js2-function-node :generator-type 'COMPREHENSION))
+ (pn (js2-parse-comprehension pos 'STAR_GENERATOR)))
+ (js2-must-match js2-RP "msg.no.paren" pos)
+ pn))
+
+(defun js2-parse-comprehension (pos form)
+ (let (loops filters expr result)
(unwind-protect
(progn
(js2-unget-token)
@@ -9385,13 +9411,12 @@ We should have just parsed the 'for' keyword before
calling this function."
(setq expr (js2-parse-assign-expr)))
(dolist (_ loops)
(js2-pop-scope)))
- (js2-must-match js2-RB "msg.no.bracket.arg" pos)
(setq result (make-js2-comp-node :pos pos
:len (- js2-ts-cursor pos)
:result expr
:loops (nreverse loops)
:filters (nreverse filters)
- :form 'ARRAY))
+ :form form))
(apply #'js2-node-add-children result (js2-comp-node-loops result))
(apply #'js2-node-add-children result expr (js2-comp-node-filters result))
result))
diff --git a/tests/parser.el b/tests/parser.el
index 9500e1c..d30e1dd 100644
--- a/tests/parser.el
+++ b/tests/parser.el
@@ -112,6 +112,9 @@ the test."
(js2-deftest-parse named-function-expression
"a = function b() {};")
+(js2-deftest-parse parenthesized-expression
+ "(1 + 2);")
+
;;; Callers of `js2-valid-prop-name-token'
(js2-deftest-parse parse-property-access-when-not-keyword
@@ -261,6 +264,19 @@ the test."
(js2-deftest-parse parse-array-comp-loop-with-filters
"[for (a in b) if (a == 2) if (b != 10) a];")
+(js2-deftest-parse parse-generator-comp-loop-with-filters
+ "(for (x of y) if (x != 4) x);")
+
+(js2-deftest-parse parse-array-comp-with-yield-is-ok
+ "(function() { return [for (x of []) yield x];\n});")
+
+(js2-deftest-parse parse-generator-comp-with-yield-is-not-ok
+ "(function() { return (for (x of []) yield x);\n});"
+ :syntax-error "yield")
+
+(js2-deftest-parse parse-generator-comp-with-yield-inside-function-is-ok
+ "(for (x of []) function*() { yield x;\n});")
+
;;; Scopes
(js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
- [elpa] 05/46: Fix electric-indent-mode, (continued)
- [elpa] 05/46: Fix electric-indent-mode, Dmitry Gutov, 2014/11/15
- [elpa] 08/46: Fix parsing of function statements in blocks, Dmitry Gutov, 2014/11/15
- [elpa] 04/46: Try to improve formatting, Dmitry Gutov, 2014/11/15
- [elpa] 09/46: Rename mention of espresso-mode to js-mode, Dmitry Gutov, 2014/11/15
- [elpa] 10/46: js2-parse-array-literal: improve trailing comma warning, Dmitry Gutov, 2014/11/15
- [elpa] 07/46: Cut down on reserved words; improve error reporting, Dmitry Gutov, 2014/11/15
- [elpa] 11/46: Support yield*, Dmitry Gutov, 2014/11/15
- [elpa] 16/46: Support Unicode Identifiers, Dmitry Gutov, 2014/11/15
- [elpa] 17/46: Check if buffer is alive before reparsing., Dmitry Gutov, 2014/11/15
- [elpa] 19/46: Better docstrings, Dmitry Gutov, 2014/11/15
- [elpa] 14/46: Support ES6 generator comprehensions,
Dmitry Gutov <=
- [elpa] 13/46: Support ES6 array comprehensions, Dmitry Gutov, 2014/11/15
- [elpa] 12/46: Add `.' to electric-indent-chars for method continuations, Dmitry Gutov, 2014/11/15
- [elpa] 15/46: Add Contributing section, Dmitry Gutov, 2014/11/15
- [elpa] 24/46: Small tweak, Dmitry Gutov, 2014/11/15
- [elpa] 23/46: Add js2-language-version checks, Dmitry Gutov, 2014/11/15
- [elpa] 25/46: Ignore integer overflow, Dmitry Gutov, 2014/11/15
- [elpa] 26/46: Allow 'in' operator inside 'for' init when unambiguous, Dmitry Gutov, 2014/11/15
- [elpa] 27/46: Fix parsing of let expressions, Dmitry Gutov, 2014/11/15
- [elpa] 18/46: Merge pull request #149 from lewang/dont-parse-killed-buffer, Dmitry Gutov, 2014/11/15
- [elpa] 28/46: js2-parse-let: Simplify, Dmitry Gutov, 2014/11/15