emacs-elpa-diffs
[Top][All Lists]
Advanced

[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;")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]