]> code.delx.au - gnu-emacs-elpa/blob - tests/parser.el
Implement two-token lookahead
[gnu-emacs-elpa] / tests / parser.el
1 (require 'ert)
2 (require 'ert-x)
3 (require 'js2-mode)
4
5 (defmacro js2-deftest (name buffer-contents &rest body)
6 `(ert-deftest ,(intern (format "js2-%s" name)) ()
7 (with-temp-buffer
8 (save-excursion
9 (insert ,buffer-contents))
10 (unwind-protect
11 (progn
12 ,@body)
13 (fundamental-mode)))))
14
15 (put 'js2-deftest 'lisp-indent-function 'defun)
16
17 (defun js2-test-string-to-ast (s)
18 (ert-with-test-buffer (:name 'origin)
19 (insert s)
20 (js2-mode)
21 (should (null js2-mode-buffer-dirty-p))
22 js2-mode-ast))
23
24 (defun* js2-test-parse-string (code-string &key syntax-error errors-count
25 reference)
26 (let ((ast (js2-test-string-to-ast code-string)))
27 (if syntax-error
28 (let ((errors (js2-ast-root-errors ast)))
29 (should (= (or errors-count 1) (length errors)))
30 (destructuring-bind (_ pos len) (first errors)
31 (should (string= syntax-error (substring code-string
32 (1- pos) (+ pos len -1))))))
33 (should (= 0 (length (js2-ast-root-errors ast))))
34 (ert-with-test-buffer (:name 'copy)
35 (js2-print-tree ast)
36 (skip-chars-backward " \t\n")
37 (should (string= (or reference code-string)
38 (buffer-substring-no-properties
39 (point-min) (point))))))))
40
41 (defmacro* js2-deftest-parse (name code-string &key bind syntax-error errors-count
42 reference)
43 "Parse CODE-STRING. If SYNTAX-ERROR is nil, print syntax tree
44 with `js2-print-tree' and assert the result to be equal to
45 REFERENCE, if present, or the original string. If SYNTAX-ERROR
46 is passed, expect syntax error highlighting substring equal to
47 SYNTAX-ERROR value. BIND defines bindings to apply them around
48 the test."
49 `(ert-deftest ,(intern (format "js2-%s" name)) ()
50 (let ,(append bind '((js2-basic-offset 2)))
51 (js2-test-parse-string ,code-string
52 :syntax-error ,syntax-error
53 :errors-count ,errors-count
54 :reference ,reference))))
55
56 (put 'js2-deftest-parse 'lisp-indent-function 'defun)
57
58 ;;; Basics
59
60 (js2-deftest-parse variable-assignment
61 "a = 1;")
62
63 (js2-deftest-parse empty-object-literal
64 "b = {};")
65
66 (js2-deftest-parse empty-array-literal
67 "c = [];")
68
69 (js2-deftest-parse comma-after-regexp
70 "d = /eee/, 42;")
71
72 (js2-deftest-parse return-statement
73 "function() {\n return 2;\n}")
74
75 ;;; Callers of `js2-valid-prop-name-token'.
76
77 (js2-deftest-parse parse-property-access-when-not-keyword
78 "A.foo = 3;")
79
80 (js2-deftest-parse parse-property-access-when-keyword
81 "A.in = 3;"
82 :bind ((js2-allow-keywords-as-property-names t)))
83
84 (js2-deftest-parse parse-property-access-when-keyword-no-xml
85 "A.in = 3;"
86 :bind ((js2-allow-keywords-as-property-names t)
87 (js2-compiler-xml-available nil)))
88
89 (js2-deftest-parse parse-object-literal-when-not-keyword
90 "a = {b: 1};")
91
92 (js2-deftest-parse parse-object-literal-when-keyword
93 "a = {in: 1};"
94 :bind ((js2-allow-keywords-as-property-names t)))
95
96 ;;; 'of' contextual keyword.
97
98 (js2-deftest-parse parse-array-comp-loop-with-of
99 "[a for (a of [])];")
100
101 (js2-deftest-parse parse-for-of
102 "for (var a of []) {\n}")
103
104 (js2-deftest-parse of-can-be-var-name
105 "var of = 3;")
106
107 (js2-deftest-parse of-can-be-function-name
108 "function of() {\n}")
109
110 ;;; Destructuring binding.
111
112 (js2-deftest-parse destruct-in-declaration
113 "var {a, b} = {a: 1, b: 2};")
114
115 (js2-deftest-parse destruct-in-arguments
116 "function f({a: aa, b: bb}) {\n}")
117
118 (js2-deftest-parse destruct-in-array-comp-loop
119 "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
120
121 (js2-deftest-parse destruct-in-catch-clause
122 "try {\n} catch ({a, b}) {\n a + b;\n}")
123
124 ;;; Function parameters.
125
126 (js2-deftest-parse function-with-default-parameters
127 "function foo(a = 1, b = a + 1) {\n}")
128
129 (js2-deftest-parse function-with-no-default-after-default
130 "function foo(a = 1, b) {\n}"
131 :syntax-error "b")
132
133 (js2-deftest-parse function-with-destruct-after-default
134 "function foo(a = 1, {b, c}) {\n}"
135 :syntax-error "{")
136
137 (js2-deftest-parse function-with-rest-parameter
138 "function foo(a, b, ...rest) {\n}")
139
140 (js2-deftest-parse function-with-param-after-rest-parameter
141 "function foo(a, ...b, rest) {\n}"
142 :syntax-error "rest")
143
144 (js2-deftest-parse function-with-destruct-after-rest-parameter
145 "function foo(a, ...b, {}) {\n}"
146 :syntax-error "{}")
147
148 (js2-deftest-parse function-with-rest-after-default-parameter
149 "function foo(a = 1, ...rest) {\n}")
150
151 ;;; Automatic semicolon insertion.
152
153 (js2-deftest-parse no-auto-semi-insertion-after-if
154 "if (true) {\n}")
155
156 (js2-deftest-parse auto-semi-insertion-after-function
157 "a = function() {}" :reference "a = function() {};")
158
159 (js2-deftest-parse auto-semi-one-variable-per-line
160 "x\ny" :reference "x;\ny;")
161
162 ;;; Labels
163
164 (js2-deftest-parse labeled-stmt-node
165 "foo:\nbar:\n x = y + 1;")
166
167 (js2-deftest no-label-node-inside-expr "x = y:"
168 (let (js2-parse-interruptable-p)
169 (js2-mode))
170 (let ((assignment (js2-expr-stmt-node-expr (car (js2-scope-kids js2-mode-ast)))))
171 (should (js2-name-node-p (js2-assign-node-right assignment)))))
172
173 ;;; Tokenizer
174
175 (js2-deftest get-token "(1+1)"
176 (js2-init-scanner)
177 (should (eq js2-LP (js2-next-token)))
178 (should (eq js2-NUMBER (js2-next-token)))
179 (should (eq js2-ADD (js2-next-token)))
180 (should (eq js2-NUMBER (js2-next-token)))
181 (should (eq js2-RP (js2-next-token))))
182
183 (js2-deftest unget-token "()"
184 (js2-init-scanner)
185 (should (eq js2-LP (js2-next-token)))
186 (js2-unget-token)
187 (should (eq js2-LP (js2-next-token)))
188 (should (eq js2-RP (js2-next-token))))
189
190 (js2-deftest get-token-or-eol "x\n++;"
191 (js2-init-scanner)
192 (should (eq js2-NAME (js2-next-token)))
193 (should (eq js2-EOL (js2-peek-token-or-eol)))
194 (should (eq js2-INC (js2-next-token)))
195 (should (eq js2-SEMI (js2-peek-token-or-eol))))
196
197 (js2-deftest unget-token-over-eol-and-comment "x\n//abc\ny"
198 (js2-init-scanner)
199 (should (eq js2-NAME (js2-next-token)))
200 (should (eq js2-NAME (js2-next-token)))
201 (should (equal "y" (js2-current-token-string)))
202 (js2-unget-token)
203 (should (eq js2-NAME (js2-current-token-type)))
204 (should (equal "x" (js2-current-token-string))))