X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/af721abd3ad489f98cc8f67ba15d4dc44d187a5d..2763c9abdc4a8d5769ff25126534d94d316d0278:/packages/js2-mode/tests/parser.el diff --git a/packages/js2-mode/tests/parser.el b/packages/js2-mode/tests/parser.el index 0dd1502c2..bfc5653cb 100644 --- a/packages/js2-mode/tests/parser.el +++ b/packages/js2-mode/tests/parser.el @@ -198,6 +198,18 @@ the test." (js2-deftest-parse object-literal-computed-keys "var x = {[Symbol.iterator]: function() {}};") +(js2-deftest-parse object-literal-computed-function-keys + "var x = {[foo + bar](y) { return y;\n}};") + +(js2-deftest-parse object-literal-computed-getter-key + "var x = {get [foo + bar]() { return 42;\n}};") + +(js2-deftest-parse object-literal-generator + "var x = {*foo() { yield 42;\n}};") + +(js2-deftest-parse object-literal-computed-generator-key + "var x = {*[foo + bar]() { yield 42;\n}};") + ;;; Function definition (js2-deftest function-redeclaring-var "var gen = 3; function gen() {};" @@ -235,6 +247,59 @@ the test." (js2-deftest-parse function-with-rest-after-default-parameter "function foo(a = 1, ...rest) {\n}") +;;; Strict mode errors + +(js2-deftest-parse function-bad-strict-parameters + "'use strict';\nfunction foo(eval, {arguments}, bar) {\n}" + :syntax-error "eval" :errors-count 2) + +(js2-deftest-parse function-retroactive-bad-strict-parameters + "function foo(arguments) {'use strict';}" + :syntax-error "arguments" :errors-count 1) + +(js2-deftest-parse function-duplicate-strict-parameters + "'use strict';\nfunction foo(a, a) {\n}" + :syntax-error "a" :errors-count 1) + +(js2-deftest-parse function-bad-strict-function-name + "'use strict';\nfunction eval() {\n}" + :syntax-error "eval" :errors-count 1) + +(js2-deftest-parse function-bad-retroactive-strict-function-name + "function arguments() {'use strict';}" + :syntax-error "arguments" :errors-count 1) + +(js2-deftest-parse function-bad-strict-catch-name + "'use strict';\ntry {} catch (eval) {}" + :syntax-error "eval" :errors-count 1) + +(js2-deftest-parse function-bad-strict-variable-name + "'use strict';\nvar eval = 'kekeke';" + :syntax-error "eval" :errors-count 1) + +(js2-deftest-parse function-bad-strict-assignment + "'use strict';\narguments = 'fufufu';" + :syntax-error "arguments" :errors-count 1) + +(js2-deftest-parse function-property-strict-assignment + "'use strict';\narguments.okay = 'alright';") + +(js2-deftest-parse function-strict-with + "'use strict';\nwith ({}) {}" + :syntax-error "with" :errors-count 1) + +(js2-deftest-parse function-strict-octal + "'use strict';\nvar number = 0644;" + :syntax-error "0644" :errors-count 1) + +(js2-deftest-parse function-strict-duplicate-keys + "'use strict';\nvar object = {a: 1, a: 2, 'a': 3, ['a']: 4, 1: 5, '1': 6, [1 + 1]: 7};" + :syntax-error "a" :errors-count 4) ; "a" has 3 dupes, "1" has 1 dupe. + +;; errors... or lackthereof. +(js2-deftest-parse function-strict-const-scope + "'use strict';\nconst a;\nif (1) {\n const a;\n}") + ;;; Spread operator (js2-deftest-parse spread-in-array-literal @@ -709,19 +774,49 @@ the test." (should (= (js2-symbol-decl-type var-entry) js2-VAR)) (should (js2-name-node-p (js2-symbol-ast-node var-entry))))) -(js2-deftest for-node-is-declaration-scope "for (let i = 0; i; ++i) {};" - (js2-mode) - (search-forward "i") +(defun js2-test-scope-of-nth-variable-satisifies-predicate (variable nth predicate) + (goto-char (point-min)) + (dotimes (n (1+ nth)) (search-forward variable)) (forward-char -1) (let ((scope (js2-node-get-enclosing-scope (js2-node-at-point)))) - (should (js2-for-node-p (js2-get-defining-scope scope "i"))))) + (should (funcall predicate (js2-get-defining-scope scope variable))))) + +(js2-deftest for-node-is-declaration-scope "for (let i = 0; i; ++i) {};" + (js2-mode) + (js2-test-scope-of-nth-variable-satisifies-predicate "i" 0 #'js2-for-node-p)) + +(js2-deftest const-scope-sloppy-script "{const a;} a;" + (js2-mode) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-script-node-p) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'js2-script-node-p)) + +(js2-deftest const-scope-strict-script "'use strict'; { const a; } a;" + (js2-mode) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-block-node-p) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'null)) + +(js2-deftest const-scope-sloppy-function "function f() { { const a; } a; }" + (js2-mode) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-function-node-p) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'js2-function-node-p)) + +(js2-deftest const-scope-strict-function "function f() { 'use strict'; { const a; } a; }" + (js2-mode) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 0 #'js2-block-node-p) + (js2-test-scope-of-nth-variable-satisifies-predicate "a" 1 #'null)) (js2-deftest array-comp-is-result-scope "[x * 2 for (x in y)];" (js2-mode) - (search-forward "x") - (forward-char -1) - (let ((scope (js2-node-get-enclosing-scope (js2-node-at-point)))) - (should (js2-comp-loop-node-p (js2-get-defining-scope scope "x"))))) + (js2-test-scope-of-nth-variable-satisifies-predicate "x" 0 #'js2-comp-loop-node-p)) + +(js2-deftest array-comp-has-parent-scope + "var a,b=[for (i of [[1,2]]) for (j of i) j * a];" + (js2-mode) + (search-forward "for") + (forward-char -3) + (let ((node (js2-node-at-point))) + (should (js2-scope-parent-scope node)) + (should (js2-get-defining-scope node "j")))) ;;; Tokenizer @@ -805,3 +900,139 @@ the test." (js2-mode) (let ((node (js2-node-at-point (point-min)))) (should (= (js2-node-len node) 3)))) + +;;; Variables classification + +(defun js2--variables-summary (vars) + (let (r) + (setq vars (let (aslist) + (maphash (lambda (k v) (push (cons k v) aslist)) vars) + aslist)) + (dolist (v (sort vars (lambda (a b) (< (js2-node-abs-pos (js2-symbol-ast-node (car a))) + (js2-node-abs-pos (js2-symbol-ast-node (car b))))))) + (let* ((symbol (car v)) + (inition (cadr v)) + (uses (cddr v)) + (symn (js2-symbol-ast-node symbol)) + (namen (js2--get-name-node symn))) + (push (format "%s@%s:%s" + (js2-symbol-name symbol) + (js2-node-abs-pos namen) + (if (eq inition ?P) + "P" + (if uses + (if inition "I" "N") + "U"))) r) + (dolist (u (sort (cddr v) (lambda (a b) (< (js2-node-abs-pos a) + (js2-node-abs-pos b))))) + (push (js2-node-abs-pos u) r)))) + (reverse r))) + +(defmacro js2-deftest-classify-variables (name buffer-contents summary) + (declare (indent defun)) + `(ert-deftest ,(intern (format "js2-classify-variables-%s" name)) () + (with-temp-buffer + (save-excursion + (insert ,buffer-contents)) + (unwind-protect + (progn + (js2-mode) + (should (equal ,summary (js2--variables-summary + (js2--classify-variables))))) + (fundamental-mode))))) + +(js2-deftest-classify-variables incomplete-var-statement + "var" + '()) + +(js2-deftest-classify-variables unused-variable + "function foo () { var x; return 42; }" + '("foo@10:U" "x@23:U")) + +(js2-deftest-classify-variables unused-variable-declared-twice + "function foo (a) { var x; function bar () { var x; x=42; }; return a;}" + '("foo@10:U" "a@15:P" 68 "x@24:U" "bar@36:U" "x@49:U")) + +(js2-deftest-classify-variables assigned-variable + "function foo () { var x; x=42; return x; }" + '("foo@10:U" "x@23:I" 39)) + +(js2-deftest-classify-variables assignment-in-nested-function + "function foo () { var x; function bar () { x=42; }; }" + '("foo@10:U" "x@23:U" "bar@35:U")) + +(js2-deftest-classify-variables unused-nested-function + "function foo() { var i, j=1; function bar() { var x, y=42, z=i; return y; } return i; }" + '("foo@10:U" "i@22:N" 62 84 "j@25:U" "bar@39:U" "x@51:U" "y@54:I" 72 "z@60:U")) + +(js2-deftest-classify-variables prop-get-initialized + "function foo () { var x, y={}; y.a=x; }" + '("foo@10:U" "x@23:N" 36 "y@26:I" 32)) + +(js2-deftest-classify-variables prop-get-uninitialized + "function foo () { var x; if(x.foo) alert('boom'); }" + '("foo@10:U" "x@23:N" 29)) + +(js2-deftest-classify-variables prop-get-function-assignment + "(function(w) { w.f = function() { var a=42, m; return a; }; })(window);" + '("w@11:P" 11 16 "a@39:I" 55 "m@45:U")) + +(js2-deftest-classify-variables let-declaration + "function foo () { let x,y=1; return x; }" + '("foo@10:U" "x@23:N" 37 "y@25:U")) + +(js2-deftest-classify-variables external-function-call + "function foo (m) { console.log(m, arguments); }" + '("foo@10:U" "m@15:P" 32)) + +(js2-deftest-classify-variables global-function-call + "function bar () { return 42; } function foo (a) { return bar(); }" + '("bar@10:I" 58 "foo@41:U" "a@46:P")) + +(js2-deftest-classify-variables let-declaration-for-scope + "function foo () { for(let x=1,y; x