[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 84379dd 004/110: Treat async/await as contextual keywords;
From: |
Dmitry Gutov |
Subject: |
[elpa] master 84379dd 004/110: Treat async/await as contextual keywords; Refs #185 |
Date: |
Thu, 23 Jun 2016 01:12:52 +0000 (UTC) |
branch: master
commit 84379dd95ccb6b2b6ebdb403dbbd9163e1653e3a
Author: Masafumi Oyamada (mooz) <address@hidden>
Commit: Masafumi Oyamada (mooz) <address@hidden>
Treat async/await as contextual keywords; Refs #185
---
js2-mode.el | 120 ++++++++++++++++++++++++++++++++++++-------------------
tests/parser.el | 14 +++++++
2 files changed, 93 insertions(+), 41 deletions(-)
diff --git a/js2-mode.el b/js2-mode.el
index ce9a012..48e2005 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -655,10 +655,8 @@ which doesn't seem particularly useful, but Rhino permits
it."
(defvar js2-TEMPLATE_HEAD 167) ; part of template literal before
substitution
(defvar js2-NO_SUBS_TEMPLATE 168) ; template literal without substitutions
(defvar js2-TAGGED_TEMPLATE 169) ; tagged template literal
-(defvar js2-ASYNC 170)
-(defvar js2-AWAIT 171)
-(defconst js2-num-tokens (1+ js2-AWAIT))
+(defconst js2-num-tokens (1+ js2-TAGGED_TEMPLATE))
(defconst js2-debug-print-trees nil)
@@ -3490,7 +3488,6 @@ The type field inherited from `js2-node' holds the
operator."
(cons js2-TYPEOF "typeof")
(cons js2-INSTANCEOF "instanceof")
(cons js2-DELPROP "delete")
- (cons js2-AWAIT "await")
(cons js2-COMMA ",")
(cons js2-COLON ":")
(cons js2-OR "||")
@@ -3591,13 +3588,31 @@ property is added if the operator follows the operand."
(unless postfix
(insert op))
(if (or (= tt js2-TYPEOF)
- (= tt js2-DELPROP)
- (= tt js2-AWAIT))
+ (= tt js2-DELPROP))
(insert " "))
(js2-print-ast (js2-unary-node-operand n) 0)
(when postfix
(insert op))))
+(cl-defstruct (js2-await-node
+ (:include js2-node)
+ (:constructor nil)
+ (:constructor make-js2-await-node (&key (pos js2-ts-cursor)
+ len operand)))
+ "AST node type for await nodes."
+ operand) ; a `js2-node' expression
+
+(put 'cl-struct-js2-await-node 'js2-visitor 'js2-visit-await-node)
+(put 'cl-struct-js2-await-node 'js2-printer 'js2-print-await-node)
+
+(defun js2-visit-await-node (n v)
+ (js2-visit-ast (js2-await-node-operand n) v))
+
+(defun js2-print-await-node (n i)
+ (insert (js2-make-pad i))
+ (insert "await ")
+ (js2-print-ast (js2-await-node-operand n) 0))
+
(cl-defstruct (js2-let-node
(:include js2-scope)
(:constructor nil)
@@ -5133,8 +5148,8 @@ You should use `js2-print-tree' instead of this function."
(or (js2-node-has-side-effects expr)
(when (js2-string-node-p expr)
(member (js2-string-node-value expr) '("use strict" "use
asm"))))))
- ((= tt js2-AWAIT)
- (js2-node-has-side-effects (js2-unary-node-operand node)))
+ ((js2-await-node-p node)
+ (js2-node-has-side-effects (js2-await-node-operand node)))
((= tt js2-COMMA)
(js2-node-has-side-effects (js2-infix-node-right node)))
((or (= tt js2-AND)
@@ -5691,7 +5706,6 @@ into temp buffers."
(defconst js2-keywords
'(break
- async await
case catch class const continue
debugger default delete do
else extends export
@@ -5711,8 +5725,7 @@ into temp buffers."
(defconst js2-kwd-tokens
(let ((table (make-vector js2-num-tokens nil))
(tokens
- (list js2-ASYNC js2-AWAIT
- js2-BREAK
+ (list js2-BREAK
js2-CASE js2-CATCH js2-CLASS js2-CONST js2-CONTINUE
js2-DEBUGGER js2-DEFAULT js2-DELPROP js2-DO
js2-ELSE js2-EXPORT
@@ -7552,12 +7565,30 @@ Returns nil and consumes nothing if MATCH is not the
next token."
(defun js2-match-contextual-kwd (name)
"Consume and return t if next token is `js2-NAME', and its
string is NAME. Returns nil and keeps current token otherwise."
- (if (or (/= (js2-get-token) js2-NAME)
- (not (string= (js2-current-token-string) name)))
- (progn
- (js2-unget-token)
- nil)
- (js2-record-face 'font-lock-keyword-face)
+ (if (js2-contextual-kwd-p (progn (js2-get-token)
+ (js2-current-token))
+ name)
+ t
+ (js2-unget-token)
+ nil))
+
+(defun js2-contextual-kwd-p (token name &optional no-record-face)
+ "Return t if `token' is `js2-NAME', and its string is NAME."
+ (and (= (js2-token-type token) js2-NAME)
+ (string= (js2-token-string token) name)
+ (prog1 t (or no-record-face
+ (js2-record-face 'font-lock-keyword-face)))))
+
+(defun js2-match-async-function ()
+ (when (and (js2-contextual-kwd-p (js2-current-token) "async")
+ (= (js2-peek-token) js2-FUNCTION))
+ (js2-get-token)
+ t))
+
+(defun js2-match-async-arrow-function ()
+ (when (and (js2-contextual-kwd-p (js2-current-token) "async")
+ (/= (js2-peek-token) js2-FUNCTION))
+ (js2-get-token)
t))
(defun js2-get-prop-name-token ()
@@ -7919,16 +7950,8 @@ Last token scanned is the close-curly for the function
body."
(js2-name-node-name name) pos end)
(js2-add-strict-warning "msg.anon.no.return.value" nil pos end)))))
-(defsubst js2-determine-function-is-async ()
- (if (eq (js2-current-token-type) js2-ASYNC)
- ;; if `async` is specified, it's async
- (js2-must-match js2-FUNCTION "msg.syntax") ; consume `function`
- ;; otherwise, not async
- nil))
-
-(defun js2-parse-function-stmt ()
+(defun js2-parse-function-stmt (&optional async-p)
(let ((pos (js2-current-token-beg))
- (async-p (js2-determine-function-is-async))
(star-p (js2-match-token js2-MUL)))
(js2-must-match-name "msg.unnamed.function.stmt")
(let ((name (js2-create-name-node t))
@@ -7947,9 +7970,11 @@ Last token scanned is the close-curly for the function
body."
(js2-report-error "msg.no.paren.parms")
(make-js2-error-node))))))
-(defun js2-parse-function-expr ()
+(defun js2-parse-async-function-stmt ()
+ (js2-parse-function-stmt t))
+
+(defun js2-parse-function-expr (&optional async-p)
(let ((pos (js2-current-token-beg))
- (async-p (js2-determine-function-is-async))
(star-p (js2-match-token js2-MUL))
name)
(when (js2-match-token js2-NAME)
@@ -8065,7 +8090,6 @@ node are given relative start positions and correct
lengths."
(defconst js2-parsers
(let ((parsers (make-vector js2-num-tokens
#'js2-parse-expr-stmt)))
- (aset parsers js2-ASYNC #'js2-parse-function-stmt)
(aset parsers js2-BREAK #'js2-parse-break)
(aset parsers js2-CLASS #'js2-parse-class-stmt)
(aset parsers js2-CONST #'js2-parse-const-var)
@@ -8116,8 +8140,7 @@ node are given relative start positions and correct
lengths."
js2-ERROR
js2-SEMI
js2-CLASS
- js2-FUNCTION
- js2-ASYNC)
+ js2-FUNCTION)
"List of tokens that don't do automatic semicolon insertion.")
(defconst js2-autoinsert-semi-and-warn
@@ -8126,9 +8149,12 @@ node are given relative start positions and correct
lengths."
(defun js2-statement-helper ()
(let* ((tt (js2-get-token))
(first-tt tt)
+ (async-stmt (js2-match-async-function))
(parser (if (= tt js2-ERROR)
#'js2-parse-semi
- (aref js2-parsers tt)))
+ (if async-stmt
+ #'js2-parse-async-function-stmt
+ (aref js2-parsers tt))))
pn)
;; If the statement is set, then it's been told its label by now.
(and js2-labeled-stmt
@@ -8137,7 +8163,8 @@ node are given relative start positions and correct
lengths."
(setq pn (funcall parser))
;; Don't do auto semi insertion for certain statement types.
(unless (or (memq first-tt js2-no-semi-insertion)
- (js2-labeled-stmt-node-p pn))
+ (js2-labeled-stmt-node-p pn)
+ async-stmt)
(js2-auto-insert-semicolon pn))
pn))
@@ -9317,10 +9344,8 @@ If NODE is non-nil, it is the AST node associated with
the symbol."
;; `js2-parse-function-stmt' nor `js2-parse-function-expr' that
;; interpret `async` token, we trash `async` and just remember
;; we met `async` keyword to `async-p'.
- (when (and (= tt js2-ASYNC)
- (/= (js2-peek-token) js2-FUNCTION))
- (setq async-p t)
- (js2-get-token))
+ (when (js2-match-async-arrow-function)
+ (setq async-p t))
;; Save the tokenizer state in case we find an arrow function
;; and have to rewind.
(setq ts-state (make-js2-ts-state)
@@ -9541,6 +9566,18 @@ to parse the operand (for prefix operators)."
(js2-node-add-children pn expr)
pn))
+(defun js2-make-await ()
+ "Make an await node."
+ (let* ((pos (js2-current-token-beg))
+ (expr (js2-parse-unary-expr))
+ (end (js2-node-end expr))
+ pn)
+ (setq pn (make-js2-await-node :pos pos
+ :len (- end pos)
+ :operand expr))
+ (js2-node-add-children pn expr)
+ pn))
+
(defconst js2-incrementable-node-types
(list js2-NAME js2-GETPROP js2-GETELEM js2-GET_REF js2-CALL)
"Node types that can be the operand of a ++ or -- operator.")
@@ -9582,7 +9619,8 @@ to parse the operand (for prefix operators)."
((= tt js2-DELPROP)
(js2-get-token)
(js2-make-unary js2-DELPROP 'js2-parse-unary-expr))
- ((= tt js2-AWAIT)
+ ((and (= tt js2-NAME)
+ (js2-contextual-kwd-p (js2-current-token) "await"))
(setq beg (js2-current-token-beg)
end (js2-current-token-end))
(js2-get-token)
@@ -9590,7 +9628,7 @@ to parse the operand (for prefix operators)."
(js2-function-node-async js2-current-script-or-fn))
(js2-report-error "msg.bad.await" nil
beg (- end beg)))
- (js2-make-unary js2-AWAIT 'js2-parse-unary-expr))
+ (js2-make-await))
((= tt js2-ERROR)
(js2-get-token)
(make-js2-error-node)) ; try to continue
@@ -9981,8 +10019,8 @@ array-literals, array comprehensions and regular
expressions."
(js2-parse-class-expr))
((= tt js2-FUNCTION)
(js2-parse-function-expr))
- ((= tt js2-ASYNC)
- (js2-parse-function-expr))
+ ((js2-match-async-function)
+ (js2-parse-function-expr t))
((= tt js2-LB)
(js2-parse-array-comp-or-literal))
((= tt js2-LC)
diff --git a/tests/parser.el b/tests/parser.el
index b2d9642..3ac3c38 100644
--- a/tests/parser.el
+++ b/tests/parser.el
@@ -356,6 +356,20 @@ the test."
"a = () => { await bar();\n}"
:syntax-error "await")
+;;; 'async' and 'await' are contextual keywords
+
+(js2-deftest-parse async-can-be-var-name
+ "var async = 3;")
+
+(js2-deftest-parse async-can-be-function-name
+ "function async() {\n}")
+
+(js2-deftest-parse await-can-be-var-name
+ "var await = 3;")
+
+(js2-deftest-parse await-can-be-function-name
+ "function await() {\n}")
+
;;; Numbers
(js2-deftest-parse decimal-starting-with-zero "081;" :reference "81;")
- [elpa] master updated (7a2deff -> 04f3d4b), Dmitry Gutov, 2016/06/22
- [elpa] master f85abdd 005/110: Fix docstring to conform to the Elisp guideline, Dmitry Gutov, 2016/06/22
- [elpa] master b035bd0 006/110: Extract contextual keyword highlighting process from a predicate function, Dmitry Gutov, 2016/06/22
- [elpa] master cef7731 016/110: Handle open-curlies after newline, Dmitry Gutov, 2016/06/22
- [elpa] master 84379dd 004/110: Treat async/await as contextual keywords; Refs #185,
Dmitry Gutov <=
- [elpa] master a2be944 014/110: Add a test for the latest change, Dmitry Gutov, 2016/06/22
- [elpa] master 34245fe 008/110: Don't treat getter / setter pairs as duplicates, Dmitry Gutov, 2016/06/22
- [elpa] master fb3f5b6 010/110: Fix 'make all' on older emacsen, Dmitry Gutov, 2016/06/22
- [elpa] master 37867af 020/110: Add NEWS entry about rename to method-node, Dmitry Gutov, 2016/06/22
- [elpa] master b904d10 023/110: Merge pull request #279 from XeCycle/class-semicolon-elem, Dmitry Gutov, 2016/06/22
- [elpa] master 8abf087 025/110: Report error for binding initializer outside destructuring, Dmitry Gutov, 2016/06/22
- [elpa] master 4c0408b 032/110: Add NEWS entry for js2-jsx-mode, Dmitry Gutov, 2016/06/22
- [elpa] master bfb83dd 017/110: Refactor: unify computed property name handling, Dmitry Gutov, 2016/06/22
- [elpa] master c63c700 029/110: Update MELPA URL, Dmitry Gutov, 2016/06/22
- [elpa] master a28a648 007/110: Remove await-node for 'awayt' and use unary-node, Dmitry Gutov, 2016/06/22