(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)
(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 "||")
(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)
(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)
(defconst js2-keywords
'(break
- async await
case catch class const continue
debugger default delete do
else extends export
(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
(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 ()
(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))
(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)
(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)
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
(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
(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))
;; `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)
(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.")
((= 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)
(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
(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)