Skip to content

Commit

Permalink
Support async generators in method notation
Browse files Browse the repository at this point in the history
Resolves #598
  • Loading branch information
dgutov committed Dec 19, 2023
1 parent 79bc78d commit d3d8723
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Expand Up @@ -2,6 +2,8 @@

## Next

* Support for async generators in method notation
([#598](https://github.com/mooz/js2-mode/issues/598)).
* Support for static initialization blocks
([#594](https://github.com/mooz/js2-mode/issues/594)).

Expand Down
58 changes: 30 additions & 28 deletions js2-mode.el
Expand Up @@ -11095,7 +11095,8 @@ expression)."
(continue t)
tt elems elem
elem-key-string previous-elem-key-string
after-comma previous-token)
after-comma
prev-pos star-p type-string)
(while continue
;; Clear out any lookahead tokens (possibly wrong modifier).
;; FIXME: Deal with this problem in a more systematic fashion.
Expand All @@ -11108,38 +11109,49 @@ expression)."
(setq tt (js2-get-prop-name-token)
static nil
elem nil
previous-token nil)
prev-pos nil
star-p nil
type-string nil)
;; Handle 'static' keyword only if we're in a class
(when (and class-p (= js2-NAME tt)
(string= "static" (js2-current-token-string)))
(js2-record-face 'font-lock-keyword-face)
(setq static t
tt (js2-get-prop-name-token)))
;; Handle generator * before the property name for in-line functions
(when (and (>= js2-language-version 200)
(= js2-MUL tt))
(setq previous-token (js2-current-token)
tt (js2-get-prop-name-token)))
;; Handle getter, setter and async methods
(let ((prop (js2-current-token-string)))
(when (and (>= js2-language-version 200)
(= js2-NAME tt)
(member prop '("get" "set" "async"))
(memq (js2-peek-token 'KEYWORD_IS_NAME)
`(,js2-NAME ,js2-PRIVATE_NAME ,js2-STRING ,js2-NUMBER ,js2-LB)))
(setq previous-token (js2-current-token)
`( ,js2-NAME ,js2-PRIVATE_NAME ,js2-STRING ,js2-NUMBER
,js2-LB ,js2-MUL)))
(js2-set-face (js2-current-token-beg)
(js2-current-token-end)
'font-lock-keyword-face 'record)
(setq type-string prop
prev-pos (js2-current-token-beg)
tt (js2-get-prop-name-token))))
;; Handle generator * before the property name for in-line functions
(when (and (>= js2-language-version 200)
(= js2-MUL tt))
(js2-set-face (js2-current-token-beg)
(js2-current-token-end)
'font-lock-keyword-face 'record)
(setq star-p t
prev-pos (or prev-pos (js2-current-token-beg))
tt (js2-get-prop-name-token)))
(cond
;; Rest/spread (...expr)
((and (>= js2-language-version 200)
(not class-p) (not static) (not previous-token)
(not class-p) (not static) (not type-string)
(= js2-TRIPLEDOT tt))
(setq after-comma nil
elem (js2-make-unary nil js2-TRIPLEDOT 'js2-parse-assign-expr)))
;; Found a key/value property (of any sort)
((memq tt `(,js2-NAME ,js2-PRIVATE_NAME ,js2-STRING ,js2-NUMBER ,js2-LB))
(setq after-comma nil
elem (js2-parse-named-prop tt previous-token class-p))
elem (js2-parse-named-prop tt prev-pos type-string star-p class-p))
(if (and (null elem)
(not js2-recover-from-parse-errors))
(setq continue nil)))
Expand Down Expand Up @@ -11202,29 +11214,18 @@ expression)."
(js2-must-match js2-RC "msg.no.brace.prop")
(nreverse elems)))

(defun js2-parse-named-prop (tt previous-token &optional class-p)
(defun js2-parse-named-prop (tt pos type-string star-p &optional class-p)
"Parse a name, string, or getter/setter object property.
When `js2-is-in-destructuring' is t, forms like {a, b, c} will be permitted."
(let ((key (js2-parse-prop-name tt class-p))
(prop (and previous-token (js2-token-string previous-token)))
(property-type (when previous-token
(if (= (js2-token-type previous-token) js2-MUL)
"*"
(js2-token-string previous-token))))
pos)
(when (member prop '("get" "set" "async"))
(setq pos (js2-token-beg previous-token))
(js2-set-face (js2-token-beg previous-token)
(js2-token-end previous-token)
'font-lock-keyword-face 'record)) ; get/set/async
(let ((key (js2-parse-prop-name tt class-p)))
(cond
;; method definition: {f() {...}}
((and (= (js2-peek-token) js2-LP)
(>= js2-language-version 200))
(when (or (js2-name-node-p key) (js2-string-node-p key))
;; highlight function name properties
(js2-record-face 'font-lock-function-name-face))
(js2-parse-method-prop pos key property-type))
(js2-parse-method-prop pos key type-string star-p))
;; class field or binding element with initializer
((and (= (js2-peek-token) js2-ASSIGN)
(>= js2-language-version 200))
Expand Down Expand Up @@ -11326,7 +11327,7 @@ string or expression."
(js2-node-add-children result prop expr)
result))))

(defun js2-parse-method-prop (pos prop type-string)
(defun js2-parse-method-prop (pos prop type-string star-p)
"Parse method property in an object literal or a class body.
JavaScript syntax is:

Expand All @@ -11339,7 +11340,8 @@ and expression closure style is also supported

POS is the start position of the `get' or `set' keyword, if any.
PROP is the `js2-name-node' representing the property name.
TYPE-STRING is a string `get', `set', `*', or nil, indicating a found keyword."
TYPE-STRING is a string `get', `set', `async', or nil.
START-P is non-nil when name is preceded by the star character."
(let* ((type (or (cdr (assoc type-string '(("get" . GET)
("set" . SET)
("async" . ASYNC))))
Expand All @@ -11348,7 +11350,7 @@ TYPE-STRING is a string `get', `set', `*', or nil, indicating a found keyword."
(pos (or pos (js2-current-token-beg)))
(_ (js2-must-match js2-LP "msg.no.paren.parms"))
(fn (js2-parse-function 'FUNCTION_EXPRESSION pos
(string= type-string "*")
star-p
(eq type 'ASYNC)
nil)))
(js2-node-set-prop fn 'METHOD_TYPE type) ; for codegen
Expand Down
8 changes: 7 additions & 1 deletion tests/parser.el
@@ -1,6 +1,6 @@
;;; tests/parser.el --- Some tests for js2-mode. -*- lexical-binding: t; -*-

;; Copyright (C) 2009, 2011-2017 Free Software Foundation, Inc.
;; Copyright (C) 2009, 2011-2023 Free Software Foundation, Inc.

;; This file is part of GNU Emacs.

Expand Down Expand Up @@ -304,6 +304,9 @@ the test."
(js2-deftest-parse object-literal-computed-generator-key
"var x = {*[foo + bar]() { yield 42;\n}};")

(js2-deftest-parse object-literal-async-generator
"var x = {async *foo() { yield 42;\n}};")

;;; Function definition

(js2-deftest function-redeclaring-var "var gen = 3; function gen() {};"
Expand Down Expand Up @@ -562,6 +565,9 @@ the test."
(js2-deftest-parse async-method-allow-await
"({async f() { await x;\n}});")

(js2-deftest-parse async-method-generator
"class C {\n async *foo() {}\n}")

;;; Await

(js2-deftest-parse await-is-ok "async function foo() {\n await bar();\n}")
Expand Down

0 comments on commit d3d8723

Please sign in to comment.