[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master ff072bf 49/49: Merge commit '03c679eb9914d58d7d9b7afc2036c
From: |
Dmitry Gutov |
Subject: |
[elpa] master ff072bf 49/49: Merge commit '03c679eb9914d58d7d9b7afc2036c482a9a01236' from js2-mode |
Date: |
Mon, 16 Jan 2017 15:35:50 +0000 (UTC) |
branch: master
commit ff072bfbc7b433df5a643a01d694070f3e19e8ec
Merge: 218fd5a 03c679e
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>
Merge commit '03c679eb9914d58d7d9b7afc2036c482a9a01236' from js2-mode
---
packages/js2-mode/Makefile | 6 +-
packages/js2-mode/NEWS.md | 7 +
packages/js2-mode/js2-mode.el | 488 ++++++++++++++++++++---------------
packages/js2-mode/js2-old-indent.el | 4 +
packages/js2-mode/tests/consume.el | 59 +++++
packages/js2-mode/tests/externs.el | 7 +
packages/js2-mode/tests/indent.el | 4 +
packages/js2-mode/tests/parser.el | 35 ++-
8 files changed, 400 insertions(+), 210 deletions(-)
diff --git a/packages/js2-mode/Makefile b/packages/js2-mode/Makefile
index 7777a67..bad22c9 100644
--- a/packages/js2-mode/Makefile
+++ b/packages/js2-mode/Makefile
@@ -3,7 +3,7 @@
EMACS = emacs
# Compile with noninteractive and relatively clean environment.
-BATCHFLAGS = -batch -q --no-site-file
+BATCHFLAGS = -batch -Q
SRCS = js2-mode.el js2-imenu-extras.el
@@ -18,6 +18,6 @@ clean:
-rm -f $(OBJS)
test:
- ${EMACS} $(BATCHFLAGS) -L . -l js2-mode.el -l js2-old-indent.el -l
tests/parser.el\
- -l tests/indent.el -l tests/externs.el -l tests/json-path.el \
+ ${EMACS} $(BATCHFLAGS) -L . -l js2-mode.el -l js2-old-indent.el -l
tests/parser.el \
+ -l tests/indent.el -l tests/externs.el -l tests/json-path.el -l
tests/consume.el \
-l tests/navigation.el -f ert-run-tests-batch-and-exit
diff --git a/packages/js2-mode/NEWS.md b/packages/js2-mode/NEWS.md
index 87e9d72..714bab8 100644
--- a/packages/js2-mode/NEWS.md
+++ b/packages/js2-mode/NEWS.md
@@ -1,5 +1,12 @@
# History of user-visible changes
+## 2017-01-16
+
+* `js2-include-*-externs` are now evaluated on demand. As a result,
+ they can now be effectively used as file- or directory-local
+ variables.
+* Support for ES7 exponentiation operator.
+
## 2016-06-23
* New variable `js2-mode-assume-strict`, for use with ES6 modules.
diff --git a/packages/js2-mode/js2-mode.el b/packages/js2-mode/js2-mode.el
index 5ccfbcc..140b6c0 100644
--- a/packages/js2-mode/js2-mode.el
+++ b/packages/js2-mode/js2-mode.el
@@ -7,7 +7,7 @@
;; Dmitry Gutov <address@hidden>
;; URL: https://github.com/mooz/js2-mode/
;; http://code.google.com/p/js2-mode/
-;; Version: 20160623
+;; Version: 20170116
;; Keywords: languages, javascript
;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
@@ -115,7 +115,7 @@
decodeURI decodeURIComponent encodeURI
encodeURIComponent escape eval isFinite isNaN
parseFloat parseInt undefined unescape))
-"Ecma-262 externs. Included in `js2-externs' by default.")
+"Ecma-262 externs. Never highlighted as undeclared variables.")
(defvar js2-browser-externs
(mapcar 'symbol-name
@@ -539,11 +539,11 @@ which doesn't seem particularly useful, but Rhino permits
it."
(defvar js2-ASSIGN_MUL 98) ; *=
(defvar js2-ASSIGN_DIV 99) ; /=
(defvar js2-ASSIGN_MOD 100) ; %=
+(defvar js2-ASSIGN_EXPON 101)
(defvar js2-first-assign js2-ASSIGN)
-(defvar js2-last-assign js2-ASSIGN_MOD)
+(defvar js2-last-assign js2-ASSIGN_EXPON)
-(defvar js2-HOOK 101) ; conditional (?:)
(defvar js2-COLON 102)
(defvar js2-OR 103) ; logical or (||)
(defvar js2-AND 104) ; logical and (&&)
@@ -624,7 +624,10 @@ which doesn't seem particularly useful, but Rhino permits
it."
(defvar js2-AWAIT 169) ; await (pseudo keyword)
-(defconst js2-num-tokens (1+ js2-AWAIT))
+(defvar js2-HOOK 170) ; conditional (?:)
+(defvar js2-EXPON 171)
+
+(defconst js2-num-tokens (1+ js2-EXPON))
(defconst js2-debug-print-trees nil)
@@ -786,28 +789,10 @@ Will only be used when we finish implementing the
interpreter.")
(defcustom js2-global-externs nil
"A list of any extern names you'd like to consider always declared.
This list is global and is used by all `js2-mode' files.
-You can create buffer-local externs list using `js2-additional-externs'.
-
-There is also a buffer-local variable `js2-default-externs',
-which is initialized by default to include the Ecma-262 externs
-and the standard browser externs. The three lists are all
-checked during highlighting."
+You can create buffer-local externs list using `js2-additional-externs'."
:type 'list
:group 'js2-mode)
-(js2-deflocal js2-default-externs nil
- "Default external declarations.
-
-These are currently only used for highlighting undeclared variables,
-which only worries about top-level (unqualified) references.
-As js2-mode's processing improves, we will flesh out this list.
-
-The initial value is set to `js2-ecma-262-externs', unless some
-of the `js2-include-?-externs' variables are set to t, in which
-case the browser, Rhino and/or Node.js externs are also included.
-
-See `js2-additional-externs' for more information.")
-
(defcustom js2-include-browser-externs t
"Non-nil to include browser externs in the master externs list.
If you work on JavaScript files that are not intended for browsers,
@@ -831,7 +816,7 @@ See `js2-additional-externs' for more information about
externs."
(js2-deflocal js2-additional-externs nil
"A buffer-local list of additional external declarations.
It is used to decide whether variables are considered undeclared
-for purposes of highlighting.
+for purposes of highlighting. See `js2-highlight-undeclared-vars'.
Each entry is a Lisp string. The string should be the fully qualified
name of an external entity. All externs should be added to this list,
@@ -1119,7 +1104,7 @@ another file, or you've got a potential bug."
(defcustom js2-include-jslint-globals t
"Non-nil to include the identifiers from JSLint global
-declaration (see http://www.jslint.com/lint.html#global) in the
+declaration (see http://www.jslint.com/help.html#global) in the
buffer-local externs list. See `js2-additional-externs' for more
information."
:type 'boolean
@@ -1127,7 +1112,6 @@ information."
(defvar js2-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map [mouse-1] #'js2-mode-show-node)
(define-key map (kbd "M-j") #'js2-line-break)
(define-key map (kbd "C-c C-e") #'js2-mode-hide-element)
(define-key map (kbd "C-c C-s") #'js2-mode-show-element)
@@ -2110,13 +2094,13 @@ Returns nil if element is not found in the list."
"Signal a syntax error or record a parse error."
(if js2-recover-from-parse-errors
(js2-record-parse-error msg msg-arg pos len)
- (signal 'js2-syntax-error
- (list msg
- js2-ts-lineno
- (save-excursion
- (goto-char js2-ts-cursor)
- (current-column))
- js2-ts-hit-eof))))
+ (signal 'js2-syntax-error
+ (list msg
+ js2-ts-lineno
+ (save-excursion
+ (goto-char js2-ts-cursor)
+ (current-column))
+ js2-ts-hit-eof))))
(defun js2-report-warning (msg &optional msg-arg pos len face)
(if js2-compiler-report-warning-as-error
@@ -3030,7 +3014,7 @@ modules metadata itself."
(insert pad "}\n")))
(cl-defstruct (js2-switch-node
- (:include js2-node)
+ (:include js2-scope)
(:constructor nil)
(:constructor make-js2-switch-node (&key (type js2-SWITCH)
(pos js2-ts-cursor)
@@ -3507,6 +3491,7 @@ The type field inherited from `js2-node' holds the
operator."
(cons js2-ADD "+") ; infix plus
(cons js2-SUB "-") ; infix minus
(cons js2-MUL "*")
+ (cons js2-EXPON "**")
(cons js2-DIV "/")
(cons js2-MOD "%")
(cons js2-NOT "!")
@@ -3526,6 +3511,7 @@ The type field inherited from `js2-node' holds the
operator."
(cons js2-ASSIGN_ADD "+=")
(cons js2-ASSIGN_SUB "-=")
(cons js2-ASSIGN_MUL "*=")
+ (cons js2-ASSIGN_EXPON "**=")
(cons js2-ASSIGN_DIV "/=")
(cons js2-ASSIGN_MOD "%="))))
(cl-loop for (k . v) in tokens do
@@ -3787,7 +3773,7 @@ You can tell the quote type by looking at the first
character."
(:include js2-node)
(:constructor nil)
(:constructor make-js2-template-node (&key (type
js2-TEMPLATE_HEAD)
- beg len kids)))
+ pos len kids)))
"Template literal."
kids) ; `js2-string-node' is used for string segments, other nodes
; for substitutions inside.
@@ -3810,7 +3796,7 @@ You can tell the quote type by looking at the first
character."
(:include js2-node)
(:constructor nil)
(:constructor make-js2-tagged-template-node (&key (type
js2-TAGGED_TEMPLATE)
- beg len tag
template)))
+ pos len tag
template)))
"Tagged template literal."
tag ; `js2-node' with the tag expression.
template) ; `js2-template-node' with the template.
@@ -4976,7 +4962,20 @@ Function returns nil if POS was not in any comment node."
end (+ beg (js2-node-len comment)))
(if (and (>= x beg)
(<= x end))
- (throw 'done comment))))))
+ (throw 'done comment))))))
+
+(defun js2-comments-between (start end comments-list)
+ "Return comment nodes between START and END, nil if not found.
+START and END are absolute positions in current buffer.
+COMMENTS-LIST is the comments list to check."
+ (let (comments c-start c-end)
+ (nreverse
+ (dolist (comment comments-list comments)
+ (setq c-start (js2-node-abs-pos comment)
+ c-end (1- (+ c-start (js2-node-len comment))))
+ (unless (or (< c-end start)
+ (> c-start end))
+ (push comment comments))))))
(defun js2-mode-find-parent-fn (node)
"Find function enclosing NODE.
@@ -5083,6 +5082,7 @@ You should use `js2-print-tree' instead of this function."
js2-ASSIGN_RSH
js2-ASSIGN_SUB
js2-ASSIGN_URSH
+ js2-ASSIGN_EXPON
js2-BLOCK
js2-BREAK
js2-CALL
@@ -6194,7 +6194,11 @@ its relevant fields and puts it into `js2-ti-tokens'."
(?*
(if (js2-match-char ?=)
js2-ASSIGN_MUL
- (throw 'return js2-MUL)))
+ (if (js2-match-char ?*)
+ (if (js2-match-char ?=)
+ js2-ASSIGN_EXPON
+ js2-EXPON)
+ (throw 'return js2-MUL))))
(?/
;; is it a // comment?
(when (js2-match-char ?/)
@@ -6386,13 +6390,15 @@ its relevant fields and puts it into `js2-ti-tokens'."
js2-TEMPLATE_HEAD
js2-NO_SUBS_TEMPLATE))))
-(defun js2-read-regexp (start-tt)
+(defun js2-read-regexp (start-tt start-pos)
"Called by parser when it gets / or /= in literal context."
(let (c err
in-class ; inside a '[' .. ']' character-class
flags
(continue t)
(token (js2-new-token 0)))
+ (js2-record-text-property start-pos (1+ start-pos)
+ 'syntax-table (string-to-syntax "\"/"))
(setq js2-ts-string-buffer nil)
(if (eq start-tt js2-ASSIGN_DIV)
;; mis-scanned /=
@@ -6419,6 +6425,8 @@ its relevant fields and puts it into `js2-ti-tokens'."
(setq in-class nil)))
(js2-add-to-string c))))
(unless err
+ (js2-record-text-property (1- js2-ts-cursor) js2-ts-cursor
+ 'syntax-table (string-to-syntax "\"/"))
(while continue
(cond
((js2-match-char ?g)
@@ -6924,6 +6932,7 @@ of a simple name. Called before EXPR has a parent node."
"member"
"memberOf"
"method"
+ "module"
"name"
"namespace"
"since"
@@ -7076,16 +7085,37 @@ later. NODE must be a name node."
(defun js2-highlight-undeclared-vars ()
"After entire parse is finished, look for undeclared variable references.
We have to wait until entire buffer is parsed, since JavaScript permits var
-decls to occur after they're used.
-
-If any undeclared var name is in `js2-externs' or `js2-additional-externs',
-it is considered declared."
- (let (name)
+declarations to occur after they're used.
+
+Some identifiers may be assumed to be externally defined.
+These externs are not highlighted, even if there is no declaration
+for them in the source code (in the current file).
+
+The list of externs consists of the following:
+
+ - `js2-ecma262-externs' for basic names from the ECMAScript language
standard.
+ - Depending on the buffer-local variables `js2-include-*-externs'
+ the corresponding `js2-*-externs' to add names for certain environments
+ like the browser, Node or Rhino.
+ - Two customizable lists `js2-global-externs' and `js2-additional-externs',
+ the latter of which should be set per-buffer.
+
+See especially `js2-additional-externs' for further details about externs."
+ (let ((default-externs
+ (append js2-ecma-262-externs
+ (if (and js2-include-browser-externs
+ (>= js2-language-version 200)) js2-harmony-externs)
+ (if js2-include-rhino-externs js2-rhino-externs)
+ (if js2-include-node-externs js2-node-externs)
+ (if (or js2-include-browser-externs js2-include-node-externs)
+ js2-typed-array-externs)
+ (if js2-include-browser-externs js2-browser-externs)))
+ name)
(dolist (entry js2-recorded-identifiers)
(cl-destructuring-bind (name-node scope pos end) entry
(setq name (js2-name-node-name name-node))
(unless (or (member name js2-global-externs)
- (member name js2-default-externs)
+ (member name default-externs)
(member name js2-additional-externs)
(js2-get-defining-scope scope name pos))
(js2-report-warning "msg.undeclared.variable" name pos (- end pos)
@@ -7112,13 +7142,157 @@ in the cdr of the entry.
(progn
(when (and inition (not (equal (car var) ?P)))
(setcar var inition))
- (when used
+ (when (and used (not (memq symbol (cdr var))))
(push symbol (cdr var))))
;; do not consider the declaration of catch parameter as an usage
(when (and err-var-p used)
(setq used nil))
(puthash sym (cons inition (if used (list symbol))) vars))))))
+(defun js2--collect-target-symbols (node strict)
+ "Collect the `js-name-node' symbols declared in NODE and return a list of
them.
+NODE is either `js2-array-node', `js2-object-node', or `js2-name-node'.
+When STRICT, signal an error if NODE is not one of the expected types."
+ (let (targets)
+ (cond
+ ((js2-name-node-p node)
+ (push node targets))
+ ((js2-array-node-p node)
+ (dolist (elt (js2-array-node-elems node))
+ (when elt
+ (setq elt (cond ((js2-infix-node-p elt) ;; default (=)
+ (js2-infix-node-left elt))
+ ((js2-unary-node-p elt) ;; rest (...)
+ (js2-unary-node-operand elt))
+ (t elt)))
+ (setq targets (append (js2--collect-target-symbols elt strict)
+ targets)))))
+ ((js2-object-node-p node)
+ (dolist (elt (js2-object-node-elems node))
+ (let ((subexpr (cond
+ ((and (js2-infix-node-p elt)
+ (= js2-ASSIGN (js2-infix-node-type elt)))
+ ;; Destructuring with default argument.
+ (js2-infix-node-left elt))
+ ((and (js2-infix-node-p elt)
+ (= js2-COLON (js2-infix-node-type elt)))
+ ;; In regular destructuring {a: aa, b: bb},
+ ;; the var is on the right. In abbreviated
+ ;; destructuring {a, b}, right == left.
+ (js2-infix-node-right elt))
+ ((and (js2-unary-node-p elt)
+ (= js2-TRIPLEDOT (js2-unary-node-type elt)))
+ ;; Destructuring with spread.
+ (js2-unary-node-operand elt)))))
+ (when subexpr
+ (setq targets (append
+ (js2--collect-target-symbols subexpr strict)
+ targets))))))
+ (strict
+ (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
+ (js2-node-len node))
+ nil))
+ targets))
+
+(defun js2--examine-variable (parent node var-init-node)
+ "Examine the usage of the variable NODE, a js2-name-node.
+PARENT is its direct ancestor and VAR-INIT-NODE is the node to be
+examined: return a list of three values, respectively if the
+variable is declared and/or assigned or whether it is simply a
+key of a literal object."
+ (let ((target (js2-var-init-node-target var-init-node))
+ declared assigned object-key)
+ (setq declared (memq node (js2--collect-target-symbols target nil)))
+ ;; Is there an initializer for the declared variable?
+ (when (js2-var-init-node-initializer var-init-node)
+ (setq assigned declared)
+ ;; Determine if the name is actually a literal object key that we shall
+ ;; ignore later
+ (when (and (not declared)
+ (js2-object-prop-node-p parent)
+ (eq node (js2-object-prop-node-left parent)))
+ (setq object-key t)))
+ ;; Maybe this is a for loop and the variable is one of its iterators?
+ (unless assigned
+ (let* ((gp (js2-node-parent parent))
+ (ggp (if gp (js2-node-parent gp))))
+ (when (and ggp (js2-for-in-node-p ggp))
+ (setq assigned (memq node
+ (cl-loop
+ for kid in (js2-var-decl-node-kids
+ (js2-for-in-node-iterator ggp))
+ with syms = '()
+ do
+ (setq syms (append syms
+ (js2--collect-target-symbols
+ (js2-var-init-node-target
kid)
+ nil)))
+ finally return syms))))))
+ (list declared assigned object-key)))
+
+(defun js2--classify-variable (parent node)
+ "Classify the single variable NODE, a js2-name-node."
+ (let ((function-param (and (js2-function-node-p parent)
+ (memq node (js2-function-node-params parent)))))
+ (if (js2-prop-get-node-p parent)
+ ;; If we are within a prop-get, e.g. the "bar" in "foo.bar",
+ ;; just mark "foo" as used
+ (let ((left (js2-prop-get-node-left parent)))
+ (when (js2-name-node-p left)
+ (js2--add-or-update-symbol left nil t vars)))
+ (let ((granparent parent)
+ var-init-node
+ assign-node
+ object-key ; is name actually an object prop key?
+ declared ; is it declared in narrowest scope?
+ assigned ; does it get assigned or initialized?
+ (used (null function-param)))
+ ;; Determine the closest var-init-node and assign-node: this
+ ;; is needed because the name may be within a "destructured"
+ ;; declaration/assignment, so we cannot just take its parent
+ (while (and granparent (not (js2-scope-p granparent)))
+ (cond
+ ((js2-var-init-node-p granparent)
+ (when (null var-init-node)
+ (setq var-init-node granparent)))
+ ((js2-assign-node-p granparent)
+ (when (null assign-node)
+ (setq assign-node granparent))))
+ (setq granparent (js2-node-parent granparent)))
+
+ ;; If we are within a var-init-node, determine if the name is
+ ;; declared and initialized
+ (when var-init-node
+ (let ((result (js2--examine-variable parent node var-init-node)))
+ (setq declared (car result)
+ assigned (cadr result)
+ object-key (car (cddr result)))))
+
+ ;; Ignore literal object keys, which are not really variables
+ (unless object-key
+ (when function-param
+ (setq assigned ?P))
+
+ (when (null assigned)
+ (cond
+ ((js2-for-in-node-p parent)
+ (setq assigned (eq node (js2-for-in-node-iterator parent))
+ used (not assigned)))
+ ((js2-function-node-p parent)
+ (setq assigned t
+ used (js2-wrapper-function-p parent)))
+ (assign-node
+ (setq assigned (memq node
+ (js2--collect-target-symbols
+ (js2-assign-node-left assign-node)
+ nil))
+ used (not assigned)))))
+
+ (when declared
+ (setq used nil))
+
+ (js2--add-or-update-symbol node assigned used vars))))))
+
(defun js2--classify-variables ()
"Collect and classify variables declared or used within js2-mode-ast.
Traverse the whole ast tree returning a summary of the variables
@@ -7133,67 +7307,10 @@ are ignored."
(js2-visit-ast
js2-mode-ast
(lambda (node end-p)
- (when (null end-p)
- (cond
- ((js2-var-init-node-p node)
- ;; take note about possibly initialized declarations
- (let ((target (js2-var-init-node-target node))
- (initializer (js2-var-init-node-initializer node)))
- (when target
- (let* ((parent (js2-node-parent node))
- (grandparent (if parent (js2-node-parent parent)))
- (inited (not (null initializer))))
- (unless inited
- (setq inited
- (and grandparent
- (js2-for-in-node-p grandparent)
- (memq target
- (mapcar #'js2-var-init-node-target
- (js2-var-decl-node-kids
- (js2-for-in-node-iterator
grandparent)))))))
- (js2--add-or-update-symbol target inited nil vars)))))
-
- ((js2-assign-node-p node)
- ;; take note about assignments
- (let ((left (js2-assign-node-left node)))
- (when (js2-name-node-p left)
- (js2--add-or-update-symbol left t nil vars))))
-
- ((js2-prop-get-node-p node)
- ;; handle x.y.z nodes, considering only x
- (let ((left (js2-prop-get-node-left node)))
- (when (js2-name-node-p left)
- (js2--add-or-update-symbol left nil t vars))))
-
- ((js2-name-node-p node)
- ;; take note about used variables
- (let ((parent (js2-node-parent node)))
- (when parent
- (unless (or (and (js2-var-init-node-p parent) ; handled above
- (eq node (js2-var-init-node-target parent)))
- (and (js2-assign-node-p parent)
- (eq node (js2-assign-node-left parent)))
- (js2-prop-get-node-p parent))
- (let ((used t) inited)
- (cond
- ((and (js2-function-node-p parent)
- (js2-wrapper-function-p parent))
- (setq inited (if (memq node (js2-function-node-params
parent)) ?P t)))
-
- ((js2-for-in-node-p parent)
- (if (eq node (js2-for-in-node-iterator parent))
- (setq inited t used nil)))
-
- ((js2-function-node-p parent)
- (setq inited (if (memq node (js2-function-node-params
parent)) ?P t)
- used nil)))
-
- (unless used
- (let ((grandparent (js2-node-parent parent)))
- (when grandparent
- (setq used (js2-return-node-p grandparent)))))
-
- (js2--add-or-update-symbol node inited used vars))))))))
+ (when (and (null end-p) (js2-name-node-p node))
+ (let ((parent (js2-node-parent node)))
+ (when parent
+ (js2--classify-variable parent node))))
t))
vars))
@@ -7245,19 +7362,6 @@ are ignored."
(remove-hook 'js2-post-parse-callbacks
#'js2-highlight-unused-variables t)))
-(defun js2-set-default-externs ()
- "Set the value of `js2-default-externs' based on the various
-`js2-include-?-externs' variables."
- (setq js2-default-externs
- (append js2-ecma-262-externs
- (if js2-include-browser-externs js2-browser-externs)
- (if (and js2-include-browser-externs
- (>= js2-language-version 200)) js2-harmony-externs)
- (if js2-include-rhino-externs js2-rhino-externs)
- (if js2-include-node-externs js2-node-externs)
- (if (or js2-include-browser-externs js2-include-node-externs)
- js2-typed-array-externs))))
-
(defun js2-apply-jslint-globals ()
(setq js2-additional-externs
(nconc (js2-get-jslint-globals)
@@ -7269,7 +7373,7 @@ are ignored."
when (and (eq 'block (js2-comment-node-format node))
(save-excursion
(goto-char (js2-node-abs-pos node))
- (looking-at "/\\* *global ")))
+ (looking-at "/\\* *global\\(?: \\|$\\)")))
append (js2-get-jslint-globals-in
(match-end 0)
(js2-node-abs-end node))))
@@ -7720,14 +7824,14 @@ is only true until the node is added to its parent;
i.e., while parsing."
;; Tell cc-engine the bounds of the comment.
(js2-record-text-property beg (1- end) 'c-in-sws t)))))
-(defun js2-peek-token ()
+(defun js2-peek-token (&optional modifier)
"Return the next token type without consuming it.
If `js2-ti-lookahead' is positive, return the type of next token
from `js2-ti-tokens'. Otherwise, call `js2-get-token'."
(if (not (zerop js2-ti-lookahead))
(js2-token-type
(aref js2-ti-tokens (mod (1+ js2-ti-tokens-cursor) js2-ti-ntokens)))
- (let ((tt (js2-get-token-internal nil)))
+ (let ((tt (js2-get-token-internal modifier)))
(js2-unget-token)
tt)))
@@ -7907,9 +8011,11 @@ Returns t on match, nil if no match."
(js2-pop-scope))
(defsubst js2-enter-switch (switch-node)
+ (js2-push-scope switch-node)
(push switch-node js2-loop-and-switch-set))
(defsubst js2-exit-switch ()
+ (js2-pop-scope)
(pop js2-loop-and-switch-set))
(defsubst js2-get-directive (node)
@@ -8091,54 +8197,16 @@ 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."
- (let (name-nodes)
- (cond
- ((js2-name-node-p node)
+ (let ((name-nodes (js2--collect-target-symbols node t)))
+ (dolist (node name-nodes)
(let (leftpos)
(js2-define-symbol decl-type (js2-name-node-name node)
node ignore-not-in-block)
(when face
(js2-set-face (setq leftpos (js2-node-abs-pos node))
(+ leftpos (js2-node-len node))
- face 'record))
- (list node)))
- ((js2-object-node-p node)
- (dolist (elem (js2-object-node-elems node))
- (let ((subexpr (cond
- ((and (js2-infix-node-p elem)
- (= js2-ASSIGN (js2-infix-node-type elem)))
- ;; Destructuring with default argument.
- (js2-infix-node-left elem))
- ((and (js2-infix-node-p elem)
- (= js2-COLON (js2-infix-node-type elem)))
- ;; In regular destructuring {a: aa, b: bb},
- ;; the var is on the right. In abbreviated
- ;; destructuring {a, b}, right == left.
- (js2-infix-node-right elem))
- ((and (js2-unary-node-p elem)
- (= js2-TRIPLEDOT (js2-unary-node-type elem)))
- ;; Destructuring with spread.
- (js2-unary-node-operand elem)))))
- (when subexpr
- (push (js2-define-destruct-symbols
- subexpr decl-type face ignore-not-in-block)
- name-nodes))))
- (apply #'append (nreverse name-nodes)))
- ((js2-array-node-p node)
- (dolist (elem (js2-array-node-elems node))
- (when elem
- (setq elem (cond ((js2-infix-node-p elem) ;; default (=)
- (js2-infix-node-left elem))
- ((js2-unary-node-p elem) ;; rest (...)
- (js2-unary-node-operand elem))
- (t elem)))
- (push (js2-define-destruct-symbols
- elem decl-type face ignore-not-in-block)
- name-nodes)))
- (apply #'append (nreverse name-nodes)))
- (t (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
- (js2-node-len node))
- nil))))
+ face 'record))))
+ name-nodes))
(defvar js2-illegal-strict-identifiers
'("eval" "arguments")
@@ -8339,7 +8407,7 @@ Last token scanned is the close-curly for the function
body."
(when (eq function-type 'FUNCTION_STATEMENT)
(js2-record-imenu-functions fn-node))))
- (setf (js2-node-len fn-node) (- js2-ts-cursor pos))
+ (setf (js2-node-len fn-node) (- (js2-current-token-end) pos))
;; Rhino doesn't do this, but we need it for finding undeclared vars.
;; We wait until after parsing the function to set its parent scope,
;; since `js2-define-symbol' needs the defining-scope check to stop
@@ -8650,19 +8718,22 @@ imports or a namespace import that follows it.
"Parse a namespace import expression such as `* as bar'.
The current token must be js2-MUL."
(let ((beg (js2-current-token-beg)))
- (if (js2-match-contextual-kwd "as")
- (when (js2-must-match-prop-name "msg.syntax")
- (let ((node (make-js2-namespace-import-node
- :pos beg
- :len (- (js2-current-token-end) beg)
- :name (make-js2-name-node
- :pos (js2-current-token-beg)
- :len (js2-current-token-end)
- :name (js2-current-token-string)))))
- (js2-node-add-children node (js2-namespace-import-node-name node))
- node))
- (js2-unget-token)
- (js2-report-error "msg.syntax"))))
+ (cond
+ ((js2-match-contextual-kwd "as")
+ (when (js2-must-match-prop-name "msg.syntax")
+ (let ((node (make-js2-namespace-import-node
+ :pos beg
+ :len (- (js2-current-token-end) beg)
+ :name (make-js2-name-node
+ :pos (js2-current-token-beg)
+ :len (- (js2-current-token-end)
+ (js2-current-token-beg))
+ :name (js2-current-token-string)))))
+ (js2-node-add-children node (js2-namespace-import-node-name node))
+ node)))
+ (t
+ (js2-unget-token)
+ (js2-report-error "msg.syntax")))))
(defun js2-parse-from-clause ()
@@ -9908,17 +9979,29 @@ FIXME: The latter option is unused?"
(list js2-MUL js2-DIV js2-MOD))
(defun js2-parse-mul-expr ()
- (let ((pn (js2-parse-unary-expr))
+ (let ((pn (js2-parse-expon-expr))
tt
(continue t))
(while continue
(setq tt (js2-get-token))
(if (memq tt js2-parse-mul-ops)
- (setq pn (js2-make-binary tt pn 'js2-parse-unary-expr))
+ (setq pn (js2-make-binary tt pn 'js2-parse-expon-expr))
(js2-unget-token)
(setq continue nil)))
pn))
+(defun js2-parse-expon-expr ()
+ (let ((pn (js2-parse-unary-expr)))
+ (when (>= js2-language-version 200)
+ (while (js2-match-token js2-EXPON)
+ (when (and (js2-unary-node-p pn)
+ (not (memq (js2-node-type pn) '(js2-INC js2-DEC))))
+ (js2-report-error "msg.syntax" nil
+ (js2-node-abs-pos pn) (js2-node-len pn)))
+ ;; Make it right-associative.
+ (setq pn (js2-make-binary js2-EXPON pn 'js2-parse-expon-expr))))
+ pn))
+
(defun js2-make-unary (type parser &rest args)
"Make a unary node of type TYPE.
PARSER is either a node (for postfix operators) or a function to call
@@ -10142,9 +10225,9 @@ Returns an expression tree that includes PN, the parent
node."
(defun js2-parse-tagged-template (tag-node tpl-node)
"Parse tagged template expression."
- (let* ((beg (js2-node-pos tag-node))
- (pn (make-js2-tagged-template-node :beg beg
- :len (- (js2-current-token-end)
beg)
+ (let* ((pos (js2-node-pos tag-node))
+ (pn (make-js2-tagged-template-node :pos pos
+ :len (- (js2-current-token-end)
pos)
:tag tag-node
:template tpl-node)))
(js2-node-add-children pn tag-node tpl-node)
@@ -10400,16 +10483,15 @@ array-literals, array comprehensions and regular
expressions."
(js2-parse-template-literal))
((or (= tt js2-DIV) (= tt js2-ASSIGN_DIV))
;; Got / or /= which in this context means a regexp literal
- (let ((px-pos (js2-current-token-beg))
- (flags (js2-read-regexp tt))
- (end (js2-current-token-end)))
+ (let* ((px-pos (js2-current-token-beg))
+ (flags (js2-read-regexp tt px-pos))
+ (end (js2-current-token-end)))
(prog1
(make-js2-regexp-node :pos px-pos
:len (- end px-pos)
:value (js2-current-token-string)
:flags flags)
- (js2-set-face px-pos end 'font-lock-string-face 'record)
- (js2-record-text-property px-pos end 'syntax-table '(2)))))
+ (js2-set-face px-pos end 'font-lock-string-face 'record))))
((or (= tt js2-NULL)
(= tt js2-THIS)
(= tt js2-SUPER)
@@ -10452,7 +10534,7 @@ array-literals, array comprehensions and regular
expressions."
(setq tt (js2-get-token 'TEMPLATE_TAIL))
(push (make-js2-string-node :type tt) kids))
(setq kids (nreverse kids))
- (let ((tpl (make-js2-template-node :beg beg
+ (let ((tpl (make-js2-template-node :pos beg
:len (- (js2-current-token-end) beg)
:kids kids)))
(apply #'js2-node-add-children tpl kids)
@@ -10721,7 +10803,8 @@ If ONLY-OF-P is non-nil, only the `for (foo of bar)'
form is allowed."
:name name
:extends extends
:elems elems))
- (apply #'js2-node-add-children pn (js2-class-node-elems pn))
+ (apply #'js2-node-add-children
+ pn name extends (js2-class-node-elems pn))
pn))
(defun js2-parse-object-literal ()
@@ -10780,7 +10863,7 @@ expression)."
(when (and (>= js2-language-version 200)
(= js2-NAME tt)
(member prop '("get" "set" "async"))
- (member (js2-peek-token)
+ (member (js2-peek-token 'KEYWORD_IS_NAME)
(list js2-NAME js2-STRING js2-NUMBER js2-LB)))
(setq previous-token (js2-current-token)
tt (js2-get-prop-name-token))))
@@ -10872,7 +10955,8 @@ When `js2-is-in-destructuring' is t, forms like {a, b,
c} will be permitted."
;; method definition: {f() {...}}
((and (= (js2-peek-token) js2-LP)
(>= js2-language-version 200))
- (when (js2-name-node-p key) ; highlight function name properties
+ (when (or (js2-name-node-p key) (js2-string-node-p key))
+ ;; highlight function name properties
(js2-record-face 'font-lock-function-name-face))
(js2-parse-method-prop pos key property-type))
;; binding element with initializer
@@ -11373,7 +11457,6 @@ If so, we don't ever want to use bounce-indent."
(defvar js2-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-`") #'js2-next-error)
- (define-key map [mouse-1] #'js2-mode-show-node)
map)
"Keymap used when `js2-minor-mode' is active.")
@@ -11396,7 +11479,6 @@ highlighting features of `js2-mode'."
(set (make-local-variable 'max-lisp-eval-depth)
(max max-lisp-eval-depth 3000))
(setq next-error-function #'js2-next-error)
- (js2-set-default-externs)
;; Experiment: make reparse-delay longer for longer files.
(if (cl-plusp js2-dynamic-idle-timer-adjust)
(setq js2-idle-timer-delay
@@ -11570,8 +11652,6 @@ Selecting an error will jump it to the corresponding
source-buffer error.
js2-mode-buffer-dirty-p t
js2-mode-parsing nil)
- (js2-set-default-externs)
-
(when js2-include-jslint-globals
(add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
@@ -11700,11 +11780,15 @@ buffer will only rebuild its `js2-mode-ast' if the
buffer is dirty."
(unless interrupted-p
(setq js2-mode-parse-timer nil))))))
-(defun js2-mode-show-node (event)
+;; We bound it to [mouse-1] previously. But the signature of
+;; mouse-set-point changed around 24.4, so it's kind of hard to keep
+;; it working in 24.1-24.3. Since the command is not hugely
+;; important, we removed the binding (#356). Maybe we'll bring it
+;; back when supporting <24.4 is not a goal anymore.
+(defun js2-mode-show-node (event &optional promote-to-region)
"Debugging aid: highlight selected AST node on mouse click."
- (interactive "e")
- (mouse-set-point event)
- (setq deactivate-mark t)
+ (interactive "e\np")
+ (mouse-set-point event promote-to-region)
(when js2-mode-show-overlay
(let ((node (js2-node-at-point))
beg end)
diff --git a/packages/js2-mode/js2-old-indent.el
b/packages/js2-mode/js2-old-indent.el
index 0b0ed3a..0016861 100644
--- a/packages/js2-mode/js2-old-indent.el
+++ b/packages/js2-mode/js2-old-indent.el
@@ -224,6 +224,10 @@ and comments have been removed."
(and (js2-re-search-backward "[?:{]\\|\\_<case\\_>" nil t)
(eq (char-after) ??))))
(not (and
+ (eq (char-after) ?/)
+ (save-excursion
+ (eq (nth 3 (syntax-ppss)) ?/))))
+ (not (and
(eq (char-after) ?*)
;; Generator method (possibly using computed property).
(looking-at (concat "\\* *\\(?:\\[\\|"
diff --git a/packages/js2-mode/tests/consume.el
b/packages/js2-mode/tests/consume.el
new file mode 100644
index 0000000..935cdeb
--- /dev/null
+++ b/packages/js2-mode/tests/consume.el
@@ -0,0 +1,59 @@
+;;; tests/consume.el --- Some tests for js2-mode.
+
+;; Copyright (C) 2016 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'js2-mode)
+
+(defun js2-mode--and-parse ()
+ (js2-mode)
+ (js2-reparse))
+
+;;; Comments
+
+(ert-deftest js2-comments-between ()
+ (with-temp-buffer
+ (insert "0\n//\n[0,/* */1]")
+ (js2-mode--and-parse)
+ (let ((comments-list (js2-ast-root-comments js2-mode-ast))
+ comments)
+ (setq comments (js2-comments-between 1 2 comments-list))
+ (should (null comments))
+ ;; comment head between region
+ (setq comments (js2-comments-between 1 3 comments-list))
+ (should (= (length comments) 1))
+ ;; comment body between region
+ (setq comments (js2-comments-between 4 5 comments-list))
+ (should (= (length comments) 1))
+ ;; comment tail between region
+ (setq comments (js2-comments-between 5 6 comments-list))
+ (should (= (length comments) 1))
+ (setq comments (js2-comments-between 6 6 comments-list))
+ (should (null comments))
+ (setq comments (js2-comments-between 10 12 comments-list))
+ (should (= (length comments) 1))
+ ;; multiple comments between
+ (setq comments (js2-comments-between 5 15 comments-list))
+ (should (= (length comments) 2))
+ ;; pass comments-list when no AST available
+ (setq js2-mode-ast nil)
+ (setq comments (js2-comments-between 8 9 comments))
+ (should (= (length comments) 1))
+ )))
diff --git a/packages/js2-mode/tests/externs.el
b/packages/js2-mode/tests/externs.el
index 75b93cd..3540f3c 100644
--- a/packages/js2-mode/tests/externs.el
+++ b/packages/js2-mode/tests/externs.el
@@ -49,6 +49,13 @@
(should (equal (js2-get-jslint-globals)
'("foo" "bar" "baz")))))
+(ert-deftest js2-finds-jslint-globals-with-newline ()
+ (with-temp-buffer
+ (insert "/* global\nfoo, bar")
+ (js2-mode)
+ (should (equal (js2-get-jslint-globals)
+ '("foo" "bar")))))
+
;;;TODO
;; ensure that any symbols bound with the import syntax are added to the
extern list
;; ensure that any symbols bound with the export syntax exist in the file scope
diff --git a/packages/js2-mode/tests/indent.el
b/packages/js2-mode/tests/indent.el
index 0fabe95..0924691 100644
--- a/packages/js2-mode/tests/indent.el
+++ b/packages/js2-mode/tests/indent.el
@@ -194,6 +194,10 @@
| 5
|]")
+(js2-deftest-indent no-continued-expression-after-regexp
+ "var re = /some value/
+ |str.match(re)")
+
(js2-deftest-indent jsx-one-line
"var foo = <div></div>;")
diff --git a/packages/js2-mode/tests/parser.el
b/packages/js2-mode/tests/parser.el
index b4aa683..de97343 100644
--- a/packages/js2-mode/tests/parser.el
+++ b/packages/js2-mode/tests/parser.el
@@ -497,6 +497,9 @@ the test."
(js2-deftest-parse async-method-in-object-literal
"({async f() {}});")
+(js2-deftest-parse async-method-kwname-in-object-literal
+ "({async delete() {}});")
+
(js2-deftest-parse async-method-in-class-body
"class C {\n async foo() {}\n}")
@@ -934,6 +937,12 @@ the test."
(js2-deftest-parse parse-harmony-class-allow-semicolon-element
"class Foo {;}" :reference "class Foo {\n}")
+(js2-deftest-parse exponentiation
+ "a **= b ** c ** d * e ** f;")
+
+(js2-deftest-parse exponentiation-prohibits-unary-op
+ "var a = -b ** c" :syntax-error "b")
+
;;; Scopes
(js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
@@ -1148,7 +1157,7 @@ the test."
(js2-deftest-classify-variables prop-get-function-assignment
"(function(w) { w.f = function() { var a=42, m; return a; }; })(window);"
- '("address@hidden:P" 11 16 "address@hidden:I" 55 "address@hidden:U"))
+ '("address@hidden:P" 16 "address@hidden:I" 55 "address@hidden:U"))
(js2-deftest-classify-variables let-declaration
"function foo () { let x,y=1; return x; }"
@@ -1175,8 +1184,8 @@ the test."
'("address@hidden:U" "address@hidden:I" 64))
(js2-deftest-classify-variables prop-get-assignment
- "function foo () { var x={y:{z:{}}}; x.y.z=42; }"
- '("address@hidden:U" "address@hidden:I" 37))
+ "function foo () { var y,x={y:{z:{}}}; x.y.z=42; }"
+ '("address@hidden:U" "address@hidden:U" "address@hidden:I" 39))
(js2-deftest-classify-variables unused-function-argument
"function foo (a) { return 42; }"
@@ -1203,9 +1212,25 @@ the test."
'("address@hidden:U" "address@hidden:N" 30 "address@hidden:U"
"address@hidden:I" 28))
(js2-deftest-classify-variables return-named-function
- "function foo() { var a=42; return function bar() { return a; } }"
- '("address@hidden:U" "address@hidden:I" 59 "address@hidden:I" 44))
+ "function foo() { var a=42; return function bar() { return a; }; }"
+ '("address@hidden:U" "address@hidden:I" 59 "address@hidden:U"))
(js2-deftest-classify-variables named-wrapper-function
"function foo() { var a; (function bar() { a=42; })(); return a; }"
'("address@hidden:U" "address@hidden:I" 62 "address@hidden:I" 35))
+
+(js2-deftest-classify-variables destructure-array
+ "function foo(x,y) { let [u,v] = [x,y]; }"
+ '("address@hidden:U" "address@hidden:P" 34 "address@hidden:P" 36
"address@hidden:U" "address@hidden:U"))
+
+(js2-deftest-classify-variables destructure-object
+ "function foo(x,y) { var {p: [, w], q: z} = {p: [x, 2, 3], q: y}; }"
+ '("address@hidden:U" "address@hidden:P" 49 "address@hidden:P" 62
"address@hidden:U" "address@hidden:U"))
+
+(js2-deftest-classify-variables destructure-object-shorthand
+ "function foo(x,y) { var {p, q} = {p: x, q: y}; }"
+ '("address@hidden:U" "address@hidden:P" 38 "address@hidden:P" 44
"address@hidden:U" "address@hidden:U"))
+
+(js2-deftest-classify-variables destructure-object-mixed
+ "function foo() { let {a, b, c = 3} = {a: 1, b: 2}; }"
+ '("address@hidden:U" "address@hidden:U" "address@hidden:U"
"address@hidden:U"))
- [elpa] master 672e2da 07/49: js2-parse-mul-expr: Parse the right operand as exponentiation too, (continued)
- [elpa] master 672e2da 07/49: js2-parse-mul-expr: Parse the right operand as exponentiation too, Dmitry Gutov, 2017/01/16
- [elpa] master a91e357 40/49: Create a separate scope for switch statements, Dmitry Gutov, 2017/01/16
- [elpa] master 4d35da5 30/49: Fix the fix (error detection), Dmitry Gutov, 2017/01/16
- [elpa] master 31a2399 44/49: Mostly cosmetic, split js2--classify-variables in three simpler functions, Dmitry Gutov, 2017/01/16
- [elpa] master 3725fcf 35/49: Handle other cases of destructuring assignments/initializations, Dmitry Gutov, 2017/01/16
- [elpa] master dad7d09 32/49: feat: add js2-comments-between func, Dmitry Gutov, 2017/01/16
- [elpa] master 523b3cb 38/49: Add a STRICT parameter to js2--collect-declared-symbols, Dmitry Gutov, 2017/01/16
- [elpa] master 1f12517 10/49: Merge pull request #353 from kaushalmodi/js2-jsx-mode-docstring-fix, Dmitry Gutov, 2017/01/16
- [elpa] master 454b242 20/49: Update NEWS.md, Dmitry Gutov, 2017/01/16
- [elpa] master 2d0dc5e 43/49: Cosmetic, reformat to stay within the preferred 80 columns limit, Dmitry Gutov, 2017/01/16
- [elpa] master ff072bf 49/49: Merge commit '03c679eb9914d58d7d9b7afc2036c482a9a01236' from js2-mode,
Dmitry Gutov <=
- [elpa] master fbe58dc 18/49: Compute externs on demand, Dmitry Gutov, 2017/01/16
- [elpa] master d3dd406 46/49: fix: copyright year of tests/comsume.el, Dmitry Gutov, 2017/01/16
- [elpa] master cdbdca4 39/49: Rewrite js2--classify-variables, focusing only on name nodes, Dmitry Gutov, 2017/01/16
- [elpa] master 82bbd97 25/49: Move it up, Dmitry Gutov, 2017/01/16
- [elpa] master c303773 21/49: Fix dead link in the documentation, Dmitry Gutov, 2017/01/16
- [elpa] master 5855a45 22/49: Merge pull request #380 from JulianKniephoff/fix-dead-doc-link-js2-include-jslint-globals, Dmitry Gutov, 2017/01/16
- [elpa] master 94b2721 31/49: Merge pull request #385 from mishoo/master, Dmitry Gutov, 2017/01/16
- [elpa] master 91e722a 27/49: Merge pull request #381 from mgiles/template-pos, Dmitry Gutov, 2017/01/16
- [elpa] master 3106e3c 37/49: Fix arrow expression function's length, Dmitry Gutov, 2017/01/16
- [elpa] master 6f2d51b 41/49: Fix the breakage from the previous commit, Dmitry Gutov, 2017/01/16