[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 9525eb3 10/45: Merge branch 'master' of github.com:shicks/
From: |
Dmitry Gutov |
Subject: |
[elpa] master 9525eb3 10/45: Merge branch 'master' of github.com:shicks/js2-mode into shicks-master |
Date: |
Mon, 02 Feb 2015 03:18:36 +0000 |
branch: master
commit 9525eb373466e9ad7cbae4a7bed7b108b49316f5
Merge: 3abcd90 3f09ff3
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>
Merge branch 'master' of github.com:shicks/js2-mode into shicks-master
Conflicts:
js2-mode.el
---
js2-mode.el | 305 +++++++++++++++++++++++++++++++++++++++++++++----------
tests/parser.el | 101 +++++++++++++++----
2 files changed, 332 insertions(+), 74 deletions(-)
diff --git a/js2-mode.el b/js2-mode.el
index 806de54..9f9cba8 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -203,6 +203,12 @@ Set `js2-include-node-externs' to t to include them.")
in node.js >= 0.6. If `js2-include-node-externs' or
`js2-include-browser-externs'
are enabled, these will also be included.")
+(defvar js2-harmony-externs
+ (mapcar 'symbol-name
+ '(Map Promise Proxy Reflect Set Symbol WeakMap WeakSet))
+ "ES6 externs. If `js2-include-browser-externs' is enabled and
+`js2-language-version' is sufficiently high, these will be included.")
+
;;; Variables
(defun js2-mark-safe-local (name pred)
@@ -654,8 +660,12 @@ which doesn't seem particularly useful, but Rhino permits
it."
(defvar js2-COMMENT 160)
(defvar js2-TRIPLEDOT 161) ; for rest parameter
(defvar js2-ARROW 162) ; function arrow (=>)
+(defvar js2-CLASS 163)
+(defvar js2-EXTENDS 164)
+(defvar js2-STATIC 165)
+(defvar js2-SUPER 166)
-(defconst js2-num-tokens (1+ js2-ARROW))
+(defconst js2-num-tokens (1+ js2-SUPER))
(defconst js2-debug-print-trees nil)
@@ -1955,6 +1965,25 @@ the correct number of ARGS must be provided."
(js2-msg "msg.yield.closing"
"Yield from closing generator")
+;; Classes
+(js2-msg "msg.unnamed.class.stmt" ; added by js2-mode
+ "class statement requires a name")
+
+(js2-msg "msg.class.unexpected.comma" ; added by js2-mode
+ "unexpected ',' between class properties")
+
+(js2-msg "msg.unexpected.static" ; added by js2-mode
+ "unexpected 'static'")
+
+(js2-msg "msg.missing.extends" ; added by js2-mode
+ "name is required after extends")
+
+(js2-msg "msg.no.brace.class" ; added by js2-mode
+ "missing '{' before class body")
+
+(js2-msg "msg.missing.computed.rb" ; added by js2-mode
+ "missing ']' after computed property expression")
+
;;; Tokens Buffer
(defconst js2-ti-max-lookahead 2)
@@ -3332,15 +3361,17 @@ The node type is set to js2-NULL, js2-THIS, etc.")
(let ((tt (js2-node-type n)))
(cond
((= tt js2-THIS) "this")
+ ((= tt js2-SUPER) "super")
((= tt js2-NULL) "null")
((= tt js2-TRUE) "true")
((= tt js2-FALSE) "false")
((= tt js2-DEBUGGER) "debugger")
(t (error "Invalid keyword literal type: %d" tt))))))
-(defsubst js2-this-node-p (node)
- "Return t if NODE is a `js2-literal-node' of type js2-THIS."
- (eq (js2-node-type node) js2-THIS))
+(defsubst js2-this-or-super-node-p (node)
+ "Return t if NODE is a `js2-literal-node' of type js2-THIS or js2-SUPER."
+ (let ((type (js2-node-type node)))
+ (or (eq type js2-THIS) (eq type js2-SUPER))))
(defstruct (js2-new-node
(:include js2-node)
@@ -3490,6 +3521,52 @@ You can tell the quote type by looking at the first
character."
(insert ",")))
(insert "]"))
+(defstruct (js2-class-node
+ (:include js2-node)
+ (:constructor nil)
+ (:constructor make-js2-class-node (&key (type js2-CLASS)
+ (pos js2-ts-cursor)
+ (form 'CLASS_STATEMENT)
+ (name "")
+ extends len elems)))
+ "AST node for an class expression.
+`elems' is a list of `js2-object-prop-node', and `extends' is an
+optional `js2-expr-node'"
+ form ; CLASS_{STATEMENT|EXPRESSION}
+ name ; class name (a `js2-node-name', or nil if anonymous)
+ extends ; class heritage (a `js2-expr-node', or nil if none)
+ elems)
+
+(put 'cl-struct-js2-class-node 'js2-visitor 'js2-visit-class-node)
+(put 'cl-struct-js2-class-node 'js2-printer 'js2-print-class-node)
+
+(defun js2-visit-class-node (n v)
+ (js2-visit-ast (js2-class-node-name n) v)
+ (js2-visit-ast (js2-class-node-extends n) v)
+ (dolist (e (js2-class-node-elems n))
+ (js2-visit-ast e v)))
+
+(defun js2-print-class-node (n i)
+ (let* ((pad (js2-make-pad i))
+ (name (js2-class-node-name n))
+ (extends (js2-class-node-extends n))
+ (elems (js2-class-node-elems n)))
+ (insert pad "class")
+ (when name
+ (insert " ")
+ (js2-print-ast name 0))
+ (when extends
+ (insert " extends ")
+ (js2-print-ast extends))
+ (insert " {")
+ (dolist (elem elems)
+ (insert "\n")
+ (if (js2-node-get-prop elem 'STATIC)
+ (progn (insert (js2-make-pad (1+ i)) "static ")
+ (js2-print-ast elem 0)) ;; TODO(sdh): indentation isn't quite
right
+ (js2-print-ast elem (1+ i))))
+ (insert "\n" pad "}")))
+
(defstruct (js2-object-node
(:include js2-node)
(:constructor nil)
@@ -3529,21 +3606,31 @@ The `right' field is a `js2-node' representing the
initializer value.")
(put 'cl-struct-js2-object-prop-node 'js2-printer 'js2-print-object-prop-node)
(defun js2-print-object-prop-node (n i)
- (insert (js2-make-pad i))
- (js2-print-ast (js2-object-prop-node-left n) 0)
- (insert ": ")
- (js2-print-ast (js2-object-prop-node-right n) 0))
+ (let* ((left (js2-object-prop-node-left n))
+ (computed (not (or (js2-string-node-p left)
+ (js2-number-node-p left)
+ (js2-name-node-p left)))))
+ (insert (js2-make-pad i))
+ (if computed
+ (insert "["))
+ (js2-print-ast left 0)
+ (if computed
+ (insert "]"))
+ (if (not (js2-node-get-prop n 'SHORTHAND))
+ (progn
+ (insert ": ")
+ (js2-print-ast (js2-object-prop-node-right n) 0)))))
(defstruct (js2-getter-setter-node
(:include js2-infix-node)
(:constructor nil)
- (:constructor make-js2-getter-setter-node (&key type ; GET or SET
+ (:constructor make-js2-getter-setter-node (&key type ; GET, SET,
or FUNCTION
(pos js2-ts-cursor)
len left right)))
"AST node for a getter/setter property in an object literal.
The `left' field is the `js2-name-node' naming the getter/setter prop.
The `right' field is always an anonymous `js2-function-node' with a node
-property `GETTER_SETTER' set to js2-GET or js2-SET. ")
+property `GETTER_SETTER' set to js2-GET, js2-SET, or js2-FUNCTION. ")
(put 'cl-struct-js2-getter-setter-node 'js2-visitor 'js2-visit-infix-node)
(put 'cl-struct-js2-getter-setter-node 'js2-printer 'js2-print-getter-setter)
@@ -3553,7 +3640,8 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
(left (js2-getter-setter-node-left n))
(right (js2-getter-setter-node-right n)))
(insert pad)
- (insert (if (= (js2-node-type n) js2-GET) "get " "set "))
+ (if (/= (js2-node-type n) js2-FUNCTION)
+ (insert (if (= (js2-node-type n) js2-GET) "get " "set ")))
(js2-print-ast left 0)
(js2-print-ast right 0)))
@@ -4645,6 +4733,7 @@ You should use `js2-print-tree' instead of this function."
js2-CALL
js2-CATCH
js2-CATCH_SCOPE
+ js2-CLASS
js2-CONST
js2-CONTINUE
js2-DEBUGGER
@@ -5268,15 +5357,15 @@ into temp buffers."
(defconst js2-keywords
'(break
- case catch const continue
+ case catch class const continue
debugger default delete do
- else
+ else extends
false finally for function
if in instanceof import
let
new null
return
- switch
+ static super switch
this throw true try typeof
var void
while with
@@ -5288,15 +5377,15 @@ into temp buffers."
(let ((table (make-vector js2-num-tokens nil))
(tokens
(list js2-BREAK
- js2-CASE js2-CATCH js2-CONST js2-CONTINUE
+ js2-CASE js2-CATCH js2-CLASS js2-CONST js2-CONTINUE
js2-DEBUGGER js2-DEFAULT js2-DELPROP js2-DO
- js2-ELSE
+ js2-ELSE js2-EXTENDS
js2-FALSE js2-FINALLY js2-FOR js2-FUNCTION
js2-IF js2-IN js2-INSTANCEOF js2-IMPORT
js2-LET
js2-NEW js2-NULL
js2-RETURN
- js2-SWITCH
+ js2-STATIC js2-SUPER js2-SWITCH
js2-THIS js2-THROW js2-TRUE js2-TRY js2-TYPEOF
js2-VAR
js2-WHILE js2-WITH
@@ -5307,6 +5396,7 @@ into temp buffers."
(aset table js2-REGEXP 'font-lock-string-face)
(aset table js2-COMMENT 'font-lock-comment-face)
(aset table js2-THIS 'font-lock-builtin-face)
+ (aset table js2-SUPER 'font-lock-builtin-face)
(aset table js2-VOID 'font-lock-constant-face)
(aset table js2-NULL 'font-lock-constant-face)
(aset table js2-TRUE 'font-lock-constant-face)
@@ -5947,6 +6037,12 @@ its relevant fields and puts it into `js2-ti-tokens'."
(push ?i flags))
((js2-match-char ?m)
(push ?m flags))
+ ((and (js2-match-char ?u)
+ (>= js2-language-version 200))
+ (push ?u flags))
+ ((and (js2-match-char ?y)
+ (>= js2-language-version 200))
+ (push ?y flags))
(t
(setq continue nil))))
(if (js2-alpha-p (js2-peek-char))
@@ -6555,7 +6651,8 @@ of a simple name. Called before EXPR has a parent node."
"Highlight function properties and external variables."
(let (leftpos name)
;; highlight vars and props assigned function values
- (when (js2-function-node-p right)
+ (when (or (js2-function-node-p right)
+ (js2-class-node-p right))
(cond
;; var foo = function() {...}
((js2-name-node-p left)
@@ -6604,6 +6701,8 @@ it is considered declared."
(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)
@@ -6722,8 +6821,10 @@ returns nil. Otherwise returns the string name/value of
the node."
((and (js2-number-node-p node)
(string-match "^[0-9]+$" (js2-number-node-value node)))
(js2-number-node-value node))
- ((js2-this-node-p node)
- "this")))
+ ((eq (js2-node-type node) js2-THIS)
+ "this")
+ ((eq (js2-node-type node) js2-SUPER)
+ "super")))
(defun js2-node-qname-component (node)
"Return the name of this node, if it contributes to a qname.
@@ -6781,7 +6882,7 @@ as property-gets if the index expression is a string, or
a positive integer."
(let (left right head)
(cond
((or (js2-name-node-p node)
- (js2-this-node-p node))
+ (js2-this-or-super-node-p node))
(list node))
;; foo.bar.baz is parenthesized as (foo.bar).baz => right operand is a
leaf
((js2-prop-get-node-p node) ; foo.bar
@@ -6834,7 +6935,7 @@ that it's an external variable, which must also be in the
top-level scope."
(this-scope (js2-node-get-enclosing-scope node))
defining-scope)
(cond
- ((js2-this-node-p node)
+ ((js2-this-or-super-node-p node)
nil)
((null this-scope)
t)
@@ -6871,7 +6972,7 @@ For instance, processing a nested scope requires a parent
function node."
;; Pre-processed chain, or top-level/external, keep as-is.
(if (or (stringp head) (js2-node-top-level-decl-p head))
(push chain result)
- (when (js2-this-node-p head)
+ (when (js2-this-or-super-node-p head)
(setq chain (cdr chain))) ; discard this-node
(when (setq fn (js2-node-parent-script-or-fn current-fn))
(setq parent-qname (gethash fn js2-imenu-function-map 'not-found))
@@ -7601,6 +7702,7 @@ node are given relative start positions and correct
lengths."
(let ((parsers (make-vector js2-num-tokens
#'js2-parse-expr-stmt)))
(aset parsers js2-BREAK #'js2-parse-break)
+ (aset parsers js2-CLASS #'js2-parse-class-stmt)
(aset parsers js2-CONST #'js2-parse-const-var)
(aset parsers js2-CONTINUE #'js2-parse-continue)
(aset parsers js2-DEBUGGER #'js2-parse-debugger)
@@ -7646,6 +7748,7 @@ node are given relative start positions and correct
lengths."
js2-LC
js2-ERROR
js2-SEMI
+ js2-CLASS
js2-FUNCTION)
"List of tokens that don't do automatic semicolon insertion.")
@@ -9225,6 +9328,8 @@ array-literals, array comprehensions and regular
expressions."
tt)
(setq tt (js2-current-token-type))
(cond
+ ((= tt js2-CLASS)
+ (js2-parse-class-expr))
((= tt js2-FUNCTION)
(js2-parse-function-expr))
((= tt js2-LB)
@@ -9260,6 +9365,7 @@ array-literals, array comprehensions and regular
expressions."
(js2-record-text-property px-pos end 'syntax-table '(2)))))
((or (= tt js2-NULL)
(= tt js2-THIS)
+ (= tt js2-SUPER)
(= tt js2-FALSE)
(= tt js2-TRUE))
(make-js2-keyword-node :type tt))
@@ -9526,29 +9632,85 @@ If ONLY-OF-P is non-nil, only the 'for (foo of bar)'
form is allowed."
(js2-node-add-children pn iter obj)
pn))
+(defun js2-parse-class-stmt ()
+ (let ((pos (js2-current-token-beg)))
+ (js2-must-match-name "msg.unnamed.class.stmt")
+ (js2-parse-class pos 'CLASS_STATEMENT (js2-create-name-node t))))
+
+(defun js2-parse-class-expr ()
+ (let ((pos (js2-current-token-beg))
+ name)
+ (when (js2-match-token js2-NAME)
+ (setq name (js2-create-name-node t)))
+ (js2-parse-class pos 'CLASS_EXPRESSION name)))
+
+(defun js2-parse-class (pos form name)
+ ;; class X [extends ...] {
+ (let (pn elems extends)
+ (when name
+ (js2-set-face (js2-node-pos name) (js2-node-end name)
+ 'font-lock-function-name-face 'record))
+ (if (js2-match-token js2-EXTENDS)
+ (if (= (js2-peek-token) js2-LC)
+ (js2-report-error "msg.missing.extends")
+ ;; TODO(sdh): this should be left-hand-side-expr, not assign-expr
+ (setq extends (js2-parse-assign-expr))
+ (if (not extends)
+ (js2-report-error "msg.bad.extends"))))
+ (js2-must-match js2-LC "msg.no.brace.class")
+ (setq elems (js2-parse-object-literal-elems t)
+ pn (make-js2-class-node :pos pos
+ :len (- js2-ts-cursor pos)
+ :form form
+ :name name
+ :extends extends
+ :elems elems))
+ (apply #'js2-node-add-children pn (js2-class-node-elems pn))
+ pn))
+
(defun js2-parse-object-literal ()
+ (let* ((pos (js2-current-token-beg))
+ (elems (js2-parse-object-literal-elems))
+ (result (make-js2-object-node :pos pos
+ :len (- js2-ts-cursor pos)
+ :elems elems)))
+ (apply #'js2-node-add-children result (js2-object-node-elems result))
+ result))
+
+(defun js2-parse-object-literal-elems (&optional class-p)
(let ((pos (js2-current-token-beg))
- tt elems result after-comma
- (continue t))
+ (static nil)
+ (continue t)
+ tt elems elem after-comma)
(while continue
- (setq tt (js2-get-token))
+ (setq static (and class-p (js2-match-token js2-STATIC))
+ tt (js2-get-token)
+ elem nil)
(cond
;; {foo: ...}, {'foo': ...}, {foo, bar, ...},
- ;; {get foo() {...}}, or {set foo(x) {...}}
+ ;; {get foo() {...}}, {set foo(x) {...}}, or {foo(x) {...}}
+ ;; TODO(sdh): support *foo() {...}
((or (js2-valid-prop-name-token tt)
(= tt js2-STRING))
(setq after-comma nil
- result (js2-parse-named-prop tt))
- (if (and (null result)
+ elem (js2-parse-named-prop tt))
+ (if (and (null elem)
(not js2-recover-from-parse-errors))
- (setq continue nil)
- (push result elems)))
+ (setq continue nil)))
+ ;; {[Symbol.iterator]: ...}
+ ((and (= tt js2-LB)
+ (>= js2-language-version 200))
+ (let ((expr (js2-parse-expr)))
+ (js2-must-match js2-RB "msg.missing.computed.rb")
+ (setq after-comma nil
+ elem (js2-parse-plain-property expr))))
;; {12: x} or {10.7: x}
((= tt js2-NUMBER)
- (setq after-comma nil)
- (push (js2-parse-plain-property (make-js2-number-node)) elems))
- ;; trailing comma
- ((= tt js2-RC)
+ (setq after-comma nil
+ elem (js2-parse-plain-property (make-js2-number-node))))
+ ;; Break out of loop, and handle trailing commas.
+ ((or (= tt js2-RC)
+ (= tt js2-EOF))
(js2-unget-token)
(setq continue nil)
(if after-comma
@@ -9558,15 +9720,22 @@ If ONLY-OF-P is non-nil, only the 'for (foo of bar)'
form is allowed."
(js2-report-error "msg.bad.prop")
(unless js2-recover-from-parse-errors
(setq continue nil)))) ; end switch
- (if (js2-match-token js2-COMMA)
- (setq after-comma (js2-current-token-end))
- (setq continue nil))) ; end loop
+ ;; Handle static for classes' codegen.
+ (if static
+ (if elem (js2-node-set-prop elem 'STATIC t)
+ (js2-report-error "msg.unexpected.static")))
+ ;; Handle commas, depending on class-p.
+ (let ((comma (js2-match-token js2-COMMA)))
+ (if class-p
+ (if comma
+ (js2-report-error "msg.class.unexpected.comma"))
+ (if comma
+ (setq after-comma (js2-current-token-end))
+ (setq continue nil))))
+ ;; Append any parsed element.
+ (if elem (push elem elems))) ; end loop
(js2-must-match js2-RC "msg.no.brace.prop")
- (setq result (make-js2-object-node :pos pos
- :len (- js2-ts-cursor pos)
- :elems (nreverse elems)))
- (apply #'js2-node-add-children result (js2-object-node-elems result))
- result))
+ (nreverse elems)))
(defun js2-parse-named-prop (tt)
"Parse a name, string, or getter/setter object property.
@@ -9588,7 +9757,12 @@ When `js2-is-in-destructuring' is t, forms like {a, b,
c} will be permitted."
(js2-set-face ppos pend 'font-lock-keyword-face 'record) ; get/set
(js2-record-face 'font-lock-function-name-face) ; for peeked name
(setq name (js2-create-name-node)) ; discard get/set & use peeked name
- (js2-parse-getter-setter-prop ppos name (string= prop "get")))
+ (js2-parse-getter-setter-prop ppos name prop))
+ ;; method definition: {f() {...}}
+ ((and (= (js2-peek-token) js2-LP)
+ (>= js2-language-version 200))
+ (js2-set-face ppos pend 'font-lock-keyword-face 'record) ; name
+ (js2-parse-getter-setter-prop ppos name ""))
;; Abbreviated destructuring binding, e.g. {a, b} = c;
;; XXX: To be honest, the value of `js2-is-in-destructuring' becomes t
only
;; when patterns are used in variable declarations, function parameters,
@@ -9617,13 +9791,31 @@ When `js2-is-in-destructuring' is t, forms like {a, b,
c} will be permitted."
(defun js2-parse-plain-property (prop)
"Parse a non-getter/setter property in an object literal.
PROP is the node representing the property: a number, name or string."
- (let ((pos (js2-node-pos prop))
- colon expr)
- (if (js2-must-match js2-COLON "msg.no.colon.prop")
- (setq colon (- (js2-current-token-beg) pos)
- expr (js2-parse-assign-expr))
- (setq expr (make-js2-error-node)))
- (let ((result (make-js2-object-prop-node
+ (let* ((tt (js2-get-token))
+ (pos (js2-node-pos prop))
+ colon expr result)
+ (cond
+ ;; Abbreviated property, as in {foo, bar}
+ ((and (>= js2-language-version 200)
+ (or (= tt js2-COMMA)
+ (= tt js2-RC)))
+ (js2-unget-token)
+ (setq result (make-js2-object-prop-node
+ :pos pos
+ :left prop
+ :right prop
+ :op-pos (js2-current-token-len)))
+ (js2-node-add-children result prop)
+ (js2-node-set-prop result 'SHORTHAND t)
+ result)
+ ;; Normal property
+ (t
+ (if (= tt js2-COLON)
+ (setq colon (- (js2-current-token-beg) pos)
+ expr (js2-parse-assign-expr))
+ (js2-report-error "msg.no.colon.prop")
+ (setq expr (make-js2-error-node)))
+ (setq result (make-js2-object-prop-node
:pos pos
;; don't include last consumed token in length
:len (- (+ (js2-node-pos expr)
@@ -9631,11 +9823,11 @@ PROP is the node representing the property: a number,
name or string."
pos)
:left prop
:right expr
- :op-pos colon)))
+ :op-pos colon))
(js2-node-add-children result prop expr)
- result)))
+ result))))
-(defun js2-parse-getter-setter-prop (pos prop get-p)
+(defun js2-parse-getter-setter-prop (pos prop type-string)
"Parse getter or setter property in an object literal.
JavaScript syntax is:
@@ -9648,7 +9840,10 @@ and expression closure style is also supported
POS is the start position of the `get' or `set' keyword.
PROP is the `js2-name-node' representing the property name.
GET-P is non-nil if the keyword was `get'."
- (let ((type (if get-p js2-GET js2-SET))
+ (let ((type (cond
+ ((string= "get" type-string) js2-GET)
+ ((string= "set" type-string) js2-SET)
+ (t js2-FUNCTION)))
result end
(fn (js2-parse-function-expr)))
;; it has to be an anonymous function, as we already parsed the name
diff --git a/tests/parser.el b/tests/parser.el
index ffda856..d986ffc 100644
--- a/tests/parser.el
+++ b/tests/parser.el
@@ -36,28 +36,28 @@
(put 'js2-deftest 'lisp-indent-function 'defun)
(defun js2-test-string-to-ast (s)
- (ert-with-test-buffer (:name 'origin)
- (insert s)
- (js2-mode)
- (should (null js2-mode-buffer-dirty-p))
- js2-mode-ast))
+ (insert s)
+ (js2-mode)
+ (should (null js2-mode-buffer-dirty-p))
+ js2-mode-ast)
(defun* js2-test-parse-string (code-string &key syntax-error errors-count
reference)
- (let ((ast (js2-test-string-to-ast code-string)))
- (if syntax-error
- (let ((errors (js2-ast-root-errors ast)))
- (should (= (or errors-count 1) (length errors)))
- (destructuring-bind (_ pos len) (first errors)
- (should (string= syntax-error (substring code-string
- (1- pos) (+ pos len
-1))))))
- (should (= 0 (length (js2-ast-root-errors ast))))
- (ert-with-test-buffer (:name 'copy)
- (js2-print-tree ast)
- (skip-chars-backward " \t\n")
- (should (string= (or reference code-string)
- (buffer-substring-no-properties
- (point-min) (point))))))))
+ (ert-with-test-buffer (:name 'origin)
+ (let ((ast (js2-test-string-to-ast code-string)))
+ (if syntax-error
+ (let ((errors (js2-ast-root-errors ast)))
+ (should (= (or errors-count 1) (length errors)))
+ (destructuring-bind (_ pos len) (first errors)
+ (should (string= syntax-error (substring code-string
+ (1- pos) (+ pos len
-1))))))
+ (should (= 0 (length (js2-ast-root-errors ast))))
+ (ert-with-test-buffer (:name 'copy)
+ (js2-print-tree ast)
+ (skip-chars-backward " \t\n")
+ (should (string= (or reference code-string)
+ (buffer-substring-no-properties
+ (point-min) (point)))))))))
(defmacro* js2-deftest-parse (name code-string &key bind syntax-error
errors-count
reference)
@@ -179,6 +179,23 @@ the test."
(js2-deftest-parse destruct-in-catch-clause
"try {\n} catch ({a, b}) {\n a + b;\n}")
+;;; Object literals
+
+(js2-deftest-parse object-literal-shorthand
+ "var x = {a: 1, b, c: 1, d};")
+
+(js2-deftest-parse object-literal-method
+ "var x = {f(y) { return y;\n}};")
+
+(js2-deftest-parse object-literal-getter-method
+ "var x = {get f() { return 42;\n}};")
+
+(js2-deftest-parse object-literal-setter-method
+ "var x = {set f(y) { x = y;\n}};")
+
+(js2-deftest-parse object-literal-computed-keys
+ "var x = {[Symbol.iterator]: function() {}};")
+
;;; Function parameters
(js2-deftest-parse function-with-default-parameters
@@ -315,6 +332,52 @@ the test."
(js2-deftest-parse octal-number-broken "0o812;"
:syntax-error "0o8" :errors-count 2)
+;;; Strings
+
+(js2-deftest-parse string-literal
+ "var x = 'y';")
+
+(js2-deftest-parse object-get-string-literal
+ "var x = {y: 5};\nvar z = x[\"y\"];")
+
+;;; Classes
+
+(js2-deftest-parse parse-harmony-class-statement
+ "class Foo {\n get bar() { return 42;\n}\n set bar(x) { y = x;\n}\n}")
+
+(js2-deftest-parse parse-harmony-class-statement-without-name-is-not-ok
+ "class {\n get bar() { return 42;\n}\n}"
+ :syntax-error "{")
+
+(js2-deftest-parse parse-harmony-class-expression
+ "var Foo1 = class Foo {\n bar() { return 42;\n}\n};")
+
+(js2-deftest-parse parse-harmony-anonymous-class-expression
+ "var Foo = class {\n set bar(x) { bar = x;\n}\n};")
+
+(js2-deftest-parse parse-harmony-class-with-extends
+ "class Foo extends Bar {\n}")
+
+(js2-deftest-parse parse-harmony-anonymous-class-with-extends
+ "foo.Foo = class extends Bar {\n set bar(x) { bar = x;\n}\n};")
+
+(js2-deftest-parse parse-harmony-class-with-complex-extends
+ "class Foo extends foo[BAR][2].Baz {\n}")
+
+(js2-deftest-parse parse-harmony-class-missing-extended-class-is-not-ok
+ "class Foo extends {\n}"
+ :syntax-error "extends")
+
+(js2-deftest-parse parse-harmony-class-static-method
+ "class Foo extends Bar {\n static bar() { return 42;\n}\n}")
+
+(js2-deftest-parse parse-unterminated-class-is-not-okay
+ "class Foo {\n get bar() { return 42;\n}"
+ :syntax-error "}")
+
+(js2-deftest-parse parse-super-keyword
+ "class Foo {\n constructor() { super(42);\n}\n foo() {
super.foo();\n}\n}")
+
;;; Scopes
(js2-deftest ast-symbol-table-includes-fn-node "function foo() {}"
- [elpa] master dd344ff 01/45: Support short-hand object literals {foo, bar} everywhere., (continued)
- [elpa] master dd344ff 01/45: Support short-hand object literals {foo, bar} everywhere., Dmitry Gutov, 2015/02/01
- [elpa] master b1f7e6c 11/45: Simplify parsing of destructuring literals, Dmitry Gutov, 2015/02/01
- [elpa] master 68b4abd 02/45: Add ES6 class externs, Dmitry Gutov, 2015/02/01
- [elpa] master ee17084 13/45: js2-parse-plain-property: Disallow numbers as abbreviated props, Dmitry Gutov, 2015/02/01
- [elpa] master b19ea52 12/45: js2-parse-named-prop: Highlight externals in abbreviated props, Dmitry Gutov, 2015/02/01
- [elpa] master 31c49e0 14/45: js2-imenu-extension-styles: Turn into defvar, Dmitry Gutov, 2015/02/01
- [elpa] master 9b77d64 15/45: Implement template strings, ignoring substitutions, Dmitry Gutov, 2015/02/01
- [elpa] master 7b3d590 17/45: No need to explicitly apply face to string nodes, Dmitry Gutov, 2015/02/01
- [elpa] master 3f09ff3 09/45: Fix string literals in parser.el test harness., Dmitry Gutov, 2015/02/01
- [elpa] master d0c6bf3 18/45: Comment the new token types, Dmitry Gutov, 2015/02/01
- [elpa] master 9525eb3 10/45: Merge branch 'master' of github.com:shicks/js2-mode into shicks-master,
Dmitry Gutov <=
- [elpa] master c910d1b 19/45: Parse tagged templates, Dmitry Gutov, 2015/02/01
- [elpa] master 8df508e 16/45: Handle template substitutions, Dmitry Gutov, 2015/02/01
- [elpa] master 92063fe 22/45: Fix js2-visit-tagged-template, Dmitry Gutov, 2015/02/01
- [elpa] master 94c2ec9 20/45: Drop `js2-allow-keywords-as-property-names' and `js2-valid-prop-name-token', Dmitry Gutov, 2015/02/01
- [elpa] master ab82544 23/45: Do not declare fn expression's name in the enclosing scope, Dmitry Gutov, 2015/02/01
- [elpa] master e6dc986 24/45: Limit the scope of `with-silent-modifications', Dmitry Gutov, 2015/02/01
- [elpa] master 6a4e84b 26/45: js2-parse-for: Reword docstring and comments, Dmitry Gutov, 2015/02/01
- [elpa] master 8088e75 21/45: Add js2-language-version check for template literals, Dmitry Gutov, 2015/02/01
- [elpa] master 395d4ae 29/45: Highlight methods with font-lock-function-name-face, Dmitry Gutov, 2015/02/01
- [elpa] master a117465 32/45: Handle "arguments" specially, Dmitry Gutov, 2015/02/01