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)
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)
(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)
((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
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)
((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)))
(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)
(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)))))
(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-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
- error-checking-arguments
default-found rest-param-at)
(when paren-free-arrow
(js2-unget-token))
(js2-report-error "msg.no.default.after.default.param"))
(setq param (js2-parse-destruct-primary-expr)
new-param-name-nodes (js2-define-destruct-symbols
- param js2-LP 'js2-function-param)
- error-checking-arguments (append
- error-checking-arguments
- (list
- (list
- param-name-nodes
- new-param-name-nodes)))
- param-name-nodes (append param-name-nodes new-param-name-nodes))
+ param js2-LP 'js2-function-param))
+ (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
(t
(js2-record-face 'js2-function-param)
(setq param (js2-create-name-node))
(js2-define-symbol js2-LP (js2-current-token-string) param)
- (setq error-checking-arguments (append
- error-checking-arguments
- (list
- (list param-name-nodes
- (list param))))
- param-name-nodes (append 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
(not rest-param-at)
(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)))
- 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.
(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)))
(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.
(js2-end-flags 0)
js2-label-set
js2-loop-set
- js2-loop-and-switch-set
- (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 error-checking-arguments)
- (apply #'js2-check-strict-function-params arguments))))
(js2-check-inconsistent-return-warning fn-node name)
(when name
(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.
;; 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
(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
(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
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