]> code.delx.au - gnu-emacs-elpa/blobdiff - js2-mode.el
Remove js2-current-indent
[gnu-emacs-elpa] / js2-mode.el
index 14ec664aa12684360375f09bf8fda58b34784fc6..348b0d1e853e0f99c0b6cc434ff8f5d090fba118 100644 (file)
@@ -2465,12 +2465,11 @@ NAME can be a Lisp symbol or string.  SYMBOL is a `js2-symbol'."
                                                      len
                                                      buffer)))
   "The root node of a js2 AST."
-  buffer           ; the source buffer from which the code was parsed
-  comments         ; a Lisp list of comments, ordered by start position
-  errors           ; a Lisp list of errors found during parsing
-  warnings         ; a Lisp list of warnings found during parsing
-  node-count       ; number of nodes in the tree, including the root
-  in-strict-mode)  ; t if the script is running under strict mode
+  buffer         ; the source buffer from which the code was parsed
+  comments       ; a Lisp list of comments, ordered by start position
+  errors         ; a Lisp list of errors found during parsing
+  warnings       ; a Lisp list of warnings found during parsing
+  node-count)    ; number of nodes in the tree, including the root
 
 (put 'cl-struct-js2-ast-root 'js2-visitor 'js2-visit-ast-root)
 (put 'cl-struct-js2-ast-root 'js2-printer 'js2-print-script)
@@ -3347,8 +3346,7 @@ The `params' field is a Lisp list of nodes.  Each node is either a simple
   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, COMPREHENSION or nil
-  member-expr      ; nonstandard Ecma extension from Rhino
-  in-strict-mode)  ; t if the function is running under strict mode
+  member-expr)     ; nonstandard Ecma extension from Rhino
 
 (put 'cl-struct-js2-function-node 'js2-visitor 'js2-visit-function-node)
 (put 'cl-struct-js2-function-node 'js2-printer 'js2-print-function-node)
@@ -7959,7 +7957,7 @@ Scanner should be initialized."
         (end js2-ts-cursor)  ; in case file is empty
         root n tt
         (in-directive-prologue t)
-        (saved-strict-mode js2-in-use-strict-directive)
+        (js2-in-use-strict-directive js2-in-use-strict-directive)
         directive)
     ;; initialize buffer-local parsing vars
     (setf root (make-js2-ast-root :buffer (buffer-name) :pos pos)
@@ -7984,12 +7982,10 @@ Scanner should be initialized."
            ((null directive)
             (setq in-directive-prologue nil))
            ((string= directive "use strict")
-            (setq js2-in-use-strict-directive t)
-            (setf (js2-ast-root-in-strict-mode root) t)))))
+            (setq js2-in-use-strict-directive t)))))
       ;; add function or statement to script
       (setq end (js2-node-end n))
       (js2-block-node-push root n))
-    (setq js2-in-use-strict-directive saved-strict-mode)
     ;; add comments to root in lexical order
     (when js2-scanned-comments
       ;; if we find a comment beyond end of normal kids, use its end
@@ -8026,11 +8022,8 @@ Scanner should be initialized."
         tt
         end
         not-in-directive-prologue
-        (saved-strict-mode js2-in-use-strict-directive)
         node
         directive)
-    ;; Inherit strict mode.
-    (setf (js2-function-node-in-strict-mode fn-node) js2-in-use-strict-directive)
     (cl-incf js2-nesting-of-function)
     (unwind-protect
         (while (not (or (= (setq tt (js2-peek-token)) js2-ERROR)
@@ -8047,13 +8040,15 @@ Scanner should be initialized."
                   ((null directive)
                    (setq not-in-directive-prologue t))
                   ((string= directive "use strict")
-                   (setq js2-in-use-strict-directive t)
-                   (setf (js2-function-node-in-strict-mode fn-node) t)))
+                   ;; Back up and reparse the function, because new rules apply
+                   ;; to the function name and parameters.
+                   (when (not js2-in-use-strict-directive)
+                     (setq js2-in-use-strict-directive t)
+                     (throw 'reparse t))))
                  node)
              (js2-get-token)
              (js2-parse-function-stmt))))
-      (cl-decf js2-nesting-of-function)
-      (setq js2-in-use-strict-directive saved-strict-mode))
+      (cl-decf js2-nesting-of-function))
     (setq end (js2-current-token-end))  ; assume no curly and leave at current token
     (if (js2-must-match js2-RC "msg.no.brace.after.body" pos)
         (setq end (js2-current-token-end)))
@@ -8063,13 +8058,10 @@ Scanner should be initialized."
     (js2-node-add-children fn-node pn)
     pn))
 
-(defun js2-define-destruct-symbols
+(defun js2-define-destruct-symbols-internal
     (node decl-type face &optional ignore-not-in-block name-nodes)
-  "Declare and fontify destructuring parameters inside NODE.
-NODE is either `js2-array-node', `js2-object-node', or `js2-name-node'.
-
-Return a list of `js2-name-node' nodes representing the symbols
-declared; probably to check them for errors."
+  "Internal version of `js2-define-destruct-symbols'.  The only
+difference is that NAME-NODES is passed down recursively."
   (cond
    ((js2-name-node-p node)
     (let (leftpos)
@@ -8084,7 +8076,7 @@ declared; probably to check them for errors."
     (dolist (elem (js2-object-node-elems node))
       (setq name-nodes
             (append name-nodes
-                    (js2-define-destruct-symbols
+                    (js2-define-destruct-symbols-internal
                      ;; In abbreviated destructuring {a, b}, right == left.
                      (js2-object-prop-node-right elem)
                      decl-type face ignore-not-in-block name-nodes)))))
@@ -8093,18 +8085,29 @@ declared; probably to check them for errors."
       (when elem
         (setq name-nodes
               (append name-nodes
-                      (js2-define-destruct-symbols
+                      (js2-define-destruct-symbols-internal
                        elem decl-type face ignore-not-in-block name-nodes))))))
    (t (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
                         (js2-node-len node))))
   name-nodes)
 
+(defun js2-define-destruct-symbols (node decl-type face &optional ignore-not-in-block)
+  "Declare and fontify destructuring parameters inside NODE.
+NODE is either `js2-array-node', `js2-object-node', or `js2-name-node'.
+
+Return a list of `js2-name-node' nodes representing the symbols
+declared; probably to check them for errors."
+  (js2-define-destruct-symbols-internal node decl-type face ignore-not-in-block))
+
+(defvar js2-illegal-strict-identifiers
+  '("eval" "arguments")
+  "Identifiers not allowed as variables in strict mode.")
+
 (defun js2-check-strict-identifier (name-node)
   "Check that NAME-NODE makes a legal strict mode identifier."
   (when js2-in-use-strict-directive
     (let ((param-name (js2-name-node-name name-node)))
-      (when (or (string= param-name "eval")
-                (string= param-name "arguments"))
+      (when (member param-name js2-illegal-strict-identifiers)
         (js2-report-error "msg.bad.id.strict" param-name
                           (js2-node-abs-pos name-node) (js2-node-len name-node))))))
 
@@ -8116,31 +8119,20 @@ for strict mode errors caused by PARAMS."
       (let ((param-name (js2-name-node-name param)))
         (js2-check-strict-identifier param)
         (when (cl-some (lambda (param)
-                         (string= (js2-name-node-name param)
-                                  param-name))
+                         (string= (js2-name-node-name param) param-name))
                        preceding-params)
           (js2-report-error "msg.dup.param.strict" param-name
                             (js2-node-abs-pos param) (js2-node-len param)))))))
 
 (defun js2-parse-function-params (function-type fn-node pos)
   "Parse the parameters of a function of FUNCTION-TYPE
-represented by FN-NODE at POS.
-
-Return a list of lists of arguments to apply many times to
-`js2-check-strict-function-params' to retroactively check for
-strict mode errors that occurred.  Because the function body is
-parsed after its parameters, and the body might activate strict
-mode for that function, the check has to occur after the body is
-parsed."
+represented by FN-NODE at POS."
   (if (js2-match-token js2-RP)
-      (progn (setf (js2-function-node-rp fn-node) (- (js2-current-token-beg) pos))
-             ;; Return an empty list for consistency.
-             '())
+      (setf (js2-function-node-rp fn-node) (- (js2-current-token-beg) pos))
     (let ((paren-free-arrow (and (eq function-type 'FUNCTION_ARROW)
                                  (eq (js2-current-token-type) js2-NAME)))
           params param
           param-name-nodes new-param-name-nodes
-          deferred-error-checking-arguments
           default-found rest-param-at)
       (when paren-free-arrow
         (js2-unget-token))
@@ -8153,13 +8145,10 @@ parsed."
                  (js2-get-token)
                  (when default-found
                    (js2-report-error "msg.no.default.after.default.param"))
-                 (setq param (js2-parse-destruct-primary-expr))
-                 (setq new-param-name-nodes (js2-define-destruct-symbols
+                 (setq param (js2-parse-destruct-primary-expr)
+                       new-param-name-nodes (js2-define-destruct-symbols
                                              param js2-LP 'js2-function-param))
-                 (setq deferred-error-checking-arguments
-                       (append deferred-error-checking-arguments
-                               (list (list param-name-nodes
-                                           new-param-name-nodes))))
+                 (js2-check-strict-function-params param-name-nodes new-param-name-nodes)
                  (setq param-name-nodes (append param-name-nodes new-param-name-nodes))
                  (push param params))
                 ;; variable name
@@ -8174,10 +8163,7 @@ parsed."
                  (js2-record-face 'js2-function-param)
                  (setq param (js2-create-name-node))
                  (js2-define-symbol js2-LP (js2-current-token-string) param)
-                 (setq deferred-error-checking-arguments
-                       (append deferred-error-checking-arguments
-                               (list (list param-name-nodes
-                                           (list param)))))
+                 (js2-check-strict-function-params param-name-nodes (list param))
                  (setq param-name-nodes (append param-name-nodes (list param)))
                  ;; default parameter value
                  (when (or (and default-found
@@ -8213,8 +8199,7 @@ parsed."
         (setf (js2-function-node-rest-p fn-node) t))
       (dolist (p params)
         (js2-node-add-children fn-node p)
-        (push p (js2-function-node-params fn-node)))
-      deferred-error-checking-arguments)))
+        (push p (js2-function-node-params fn-node))))))
 
 (defun js2-check-inconsistent-return-warning (fn-node name)
   "Possibly show inconsistent-return warning.
@@ -8263,10 +8248,7 @@ Last token scanned is the close-curly for the function body."
     (js2-must-match js2-LP "msg.no.paren.parms")
     (js2-parse-function 'FUNCTION_EXPRESSION pos star-p name)))
 
-(defun js2-parse-function (function-type pos star-p &optional name)
-  "Function parser.  FUNCTION-TYPE is a symbol, POS is the
-beginning of the first token (function keyword, unless it's an
-arrow function), NAME is js2-name-node."
+(defun js2-parse-function-internal (function-type pos star-p &optional name)
   (let (fn-node lp)
     (if (= (js2-current-token-type) js2-LP) ; eventually matched LP?
         (setq lp (js2-current-token-beg)))
@@ -8281,7 +8263,9 @@ arrow function), NAME is js2-name-node."
       (when (and (eq function-type 'FUNCTION_STATEMENT)
                  (cl-plusp (js2-name-node-length name)))
         ;; Function statements define a symbol in the enclosing scope
-        (js2-define-symbol js2-FUNCTION (js2-name-node-name name) fn-node)))
+        (js2-define-symbol js2-FUNCTION (js2-name-node-name name) fn-node))
+      (when js2-in-use-strict-directive
+        (js2-check-strict-identifier name)))
     (if (or (js2-inside-function) (cl-plusp js2-nesting-of-with))
         ;; 1. Nested functions are not affected by the dynamic scope flag
         ;;    as dynamic scope is already a parent of their scope.
@@ -8296,24 +8280,14 @@ arrow function), NAME is js2-name-node."
           (js2-end-flags 0)
           js2-label-set
           js2-loop-set
-          js2-loop-and-switch-set
-          deferred-error-checking-arguments)
-      (setq deferred-error-checking-arguments
-            (js2-parse-function-params function-type fn-node pos))
+          js2-loop-and-switch-set)
+      (js2-parse-function-params function-type fn-node pos)
       (when (eq function-type 'FUNCTION_ARROW)
         (js2-must-match js2-ARROW "msg.bad.arrow.args"))
       (if (and (>= js2-language-version 180)
                (/= (js2-peek-token) js2-LC))
           (js2-parse-function-closure-body fn-node)
         (js2-parse-function-body fn-node))
-      (when (js2-function-node-in-strict-mode fn-node)
-        ;; Pretend that we're inside the function again.  It cleans up its
-        ;; `js2-in-use-strict-directive' binding.
-        (let ((js2-in-use-strict-directive t))
-          (when name
-            (js2-check-strict-identifier name))
-          (dolist (arguments deferred-error-checking-arguments)
-            (apply #'js2-check-strict-function-params arguments))))
       (js2-check-inconsistent-return-warning fn-node name)
 
       (when name
@@ -8337,6 +8311,29 @@ arrow function), NAME is js2-name-node."
     (setf (js2-scope-parent-scope fn-node) js2-current-scope)
     fn-node))
 
+(defun js2-parse-function (function-type pos star-p &optional name)
+  "Function parser.  FUNCTION-TYPE is a symbol, POS is the
+beginning of the first token (function keyword, unless it's an
+arrow function), NAME is js2-name-node."
+  (let ((continue t)
+        ts-state
+        fn-node
+        ;; Preserve strict state outside this function.
+        (js2-in-use-strict-directive js2-in-use-strict-directive))
+    ;; Parse multiple times if a new strict mode directive is discovered in the
+    ;; function body, as new rules will be retroactively applied to the legality
+    ;; of function names and parameters.
+    (while continue
+      (setq ts-state (make-js2-ts-state))
+      (setq continue (catch 'reparse
+                       (setq fn-node (js2-parse-function-internal
+                                      function-type pos star-p name))
+                       ;; Don't continue.
+                       nil))
+      (when continue
+        (js2-ts-seek ts-state)))
+    fn-node))
+
 (defun js2-parse-statements (&optional parent)
   "Parse a statement list.  Last token consumed must be js2-LC.
 
@@ -9555,8 +9552,12 @@ If NODE is non-nil, it is the AST node associated with the symbol."
          (len (if node (js2-node-len node))))
     (cond
      ((and symbol ; already defined
-           (or (= sdt js2-CONST) ; old version is const
-               (= decl-type js2-CONST) ; new version is const
+           (or (if js2-in-use-strict-directive
+                   ;; two const-bound vars in this block have same name
+                   (and (= sdt js2-CONST)
+                        (eq defining-scope js2-current-scope))
+                 (or (= sdt js2-CONST)          ; old version is const
+                     (= decl-type js2-CONST)))  ; new version is const
                ;; two let-bound vars in this block have same name
                (and (= sdt js2-LET)
                     (eq defining-scope js2-current-scope))))
@@ -9667,7 +9668,10 @@ If NODE is non-nil, it is the AST node associated with the symbol."
         ;; tt express assignment (=, |=, ^=, ..., %=)
         (setq op-pos (- (js2-current-token-beg) pos)  ; relative
               left pn)
-        (js2-check-strict-identifier left)
+        ;; The assigned node could be a js2-prop-get-node (foo.bar = 0), we only
+        ;; care about assignment to strict variable names.
+        (when (js2-name-node-p left)
+          (js2-check-strict-identifier left))
         (setq right (js2-parse-assign-expr)
               pn (make-js2-assign-node :type tt
                                        :pos pos
@@ -10321,7 +10325,7 @@ array-literals, array comprehensions and regular expressions."
       (setq node (make-js2-number-node))
       (when (and js2-in-use-strict-directive
                  (= (js2-number-node-num-base node) 8))
-        (js2-report-error "msg.no.octal.literal"))
+        (js2-report-error "msg.no.octal.strict"))
       node)
      ((or (= tt js2-STRING) (= tt js2-NO_SUBS_TEMPLATE))
       (make-js2-string-node :type tt))
@@ -10747,9 +10751,8 @@ expression)."
           (js2-unget-token)
           (unless class-p (setq continue nil))))
       (when elem
-        (setq elem-key-string (js2-property-key-string elem))
         (when (and js2-in-use-strict-directive
-                   elem-key-string
+                   (setq elem-key-string (js2-property-key-string elem))
                    (cl-some
                     (lambda (previous-elem)
                       (and (setq previous-elem-key-string
@@ -11302,15 +11305,6 @@ indentation is aligned to that column."
   (interactive)
   (while (forward-comment 1)))
 
-(defun js2-current-indent (&optional pos)
-  "Return column of indentation on current line.
-If POS is non-nil, go to that point and return indentation for that line."
-  (save-excursion
-    (if pos
-        (goto-char pos))
-    (back-to-indentation)
-    (current-column)))
-
 (defun js2-arglist-close ()
   "Return non-nil if we're on a line beginning with a close-paren/brace."
   (save-excursion
@@ -11365,7 +11359,7 @@ of the buffer to the current point.  NORMAL-COL is the indentation
 column computed by the heuristic guesser based on current paren,
 bracket, brace and statement nesting.  If BACKWARDS, cycle positions
 in reverse."
-  (let ((cur-indent (js2-current-indent))
+  (let ((cur-indent (current-indentation))
         (old-buffer-undo-list buffer-undo-list)
         ;; Emacs 21 only has `count-lines', not `line-number-at-pos'
         (current-line (save-excursion