[Pkg-javascript-commits] [uglifyjs] 25/50: improve keyword-related parser errors (#1941)

Jonas Smedegaard dr at jones.dk
Thu Aug 17 23:06:45 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository uglifyjs.

commit ecb63ad8bc07f024b3517762434ab941d7c4d0e7
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Mon May 15 23:02:55 2017 +0800

    improve keyword-related parser errors (#1941)
    
    fixes #1937
---
 lib/parse.js                 |  61 ++++++--
 test/input/invalid/else.js   |   1 +
 test/input/invalid/return.js |   1 +
 test/mocha/cli.js            | 360 +++++++++++++++++++++++--------------------
 4 files changed, 241 insertions(+), 182 deletions(-)

diff --git a/lib/parse.js b/lib/parse.js
index edd55e7..b9911fa 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -803,17 +803,16 @@ function parse($TEXT, options) {
     };
 
     var statement = embed_tokens(function() {
-        var tmp;
         handle_regexp();
         switch (S.token.type) {
           case "string":
             if (S.in_directives) {
-                tmp = peek();
+                var token = peek();
                 if (S.token.raw.indexOf("\\") == -1
-                    && (tmp.nlb
-                        || is_token(tmp, "eof")
-                        || is_token(tmp, "punc", ";")
-                        || is_token(tmp, "punc", "}"))) {
+                    && (token.nlb
+                        || is_token(token, "eof")
+                        || is_token(token, "punc", ";")
+                        || is_token(token, "punc", "}"))) {
                     S.input.add_directive(S.token.value);
                 } else {
                     S.in_directives = false;
@@ -852,75 +851,103 @@ function parse($TEXT, options) {
             }
 
           case "keyword":
-            switch (tmp = S.token.value, next(), tmp) {
+            switch (S.token.value) {
               case "break":
+                next();
                 return break_cont(AST_Break);
 
               case "continue":
+                next();
                 return break_cont(AST_Continue);
 
               case "debugger":
+                next();
                 semicolon();
                 return new AST_Debugger();
 
               case "do":
+                next();
+                var body = in_loop(statement);
+                expect_token("keyword", "while");
+                var condition = parenthesised();
+                semicolon(true);
                 return new AST_Do({
-                    body      : in_loop(statement),
-                    condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(true), tmp)
+                    body      : body,
+                    condition : condition
                 });
 
               case "while":
+                next();
                 return new AST_While({
                     condition : parenthesised(),
                     body      : in_loop(statement)
                 });
 
               case "for":
+                next();
                 return for_();
 
               case "function":
+                next();
                 return function_(AST_Defun);
 
               case "if":
+                next();
                 return if_();
 
               case "return":
                 if (S.in_function == 0 && !options.bare_returns)
                     croak("'return' outside of function");
+                next();
+                var value = null;
+                if (is("punc", ";")) {
+                    next();
+                } else if (!can_insert_semicolon()) {
+                    value = expression(true);
+                    semicolon();
+                }
                 return new AST_Return({
-                    value: ( is("punc", ";")
-                             ? (next(), null)
-                             : can_insert_semicolon()
-                             ? null
-                             : (tmp = expression(true), semicolon(), tmp) )
+                    value: value
                 });
 
               case "switch":
+                next();
                 return new AST_Switch({
                     expression : parenthesised(),
                     body       : in_loop(switch_body_)
                 });
 
               case "throw":
+                next();
                 if (S.token.nlb)
                     croak("Illegal newline after 'throw'");
+                var value = expression(true);
+                semicolon();
                 return new AST_Throw({
-                    value: (tmp = expression(true), semicolon(), tmp)
+                    value: value
                 });
 
               case "try":
+                next();
                 return try_();
 
               case "var":
-                return tmp = var_(), semicolon(), tmp;
+                next();
+                var node = var_();
+                semicolon();
+                return node;
 
               case "const":
-                return tmp = const_(), semicolon(), tmp;
+                next();
+                var node = const_();
+                semicolon();
+                return node;
 
               case "with":
                 if (S.input.has_directive("use strict")) {
                     croak("Strict mode may not include a with statement");
                 }
+                next();
                 return new AST_With({
                     expression : parenthesised(),
                     body       : statement()
diff --git a/test/input/invalid/else.js b/test/input/invalid/else.js
new file mode 100644
index 0000000..89e8e50
--- /dev/null
+++ b/test/input/invalid/else.js
@@ -0,0 +1 @@
+if (0) else 1;
diff --git a/test/input/invalid/return.js b/test/input/invalid/return.js
new file mode 100644
index 0000000..d232c62
--- /dev/null
+++ b/test/input/invalid/return.js
@@ -0,0 +1 @@
+return 42;
diff --git a/test/mocha/cli.js b/test/mocha/cli.js
index d5c9585..9b3b637 100644
--- a/test/mocha/cli.js
+++ b/test/mocha/cli.js
@@ -51,15 +51,15 @@ describe("bin/uglifyjs", function () {
         });
     });
     it("Should append source map to output when using --source-map-inline", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1323/sample.js --source-map-inline';
+        var command = uglifyjscmd + ' test/input/issue-1323/sample.js --source-map-inline';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
-               "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
-           done();
-       });
+            assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
+                "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
+            done();
+        });
     });
     it("should not append source map to output when not using --source-map-inline", function (done) {
         var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
@@ -72,84 +72,84 @@ describe("bin/uglifyjs", function () {
         });
     });
     it("Should work with --keep-fnames (mangle only)", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
+        var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
+            done();
+        });
     });
     it("Should work with --keep-fnames (mangle & compress)", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
+        var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
-           done();
-       });
+            assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
+            done();
+        });
     });
     it("Should work with keep_fnames under mangler options", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
+        var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
+            done();
+        });
     });
     it("Should work with --define (simple)", function (done) {
-       var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
+        var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "console.log(5);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "console.log(5);\n");
+            done();
+        });
     });
     it("Should work with --define (nested)", function (done) {
-       var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
+        var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "console.log(3,5);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "console.log(3,5);\n");
+            done();
+        });
     });
     it("Should work with --define (AST_Node)", function (done) {
-       var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
+        var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "stdout.println(D);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "stdout.println(D);\n");
+            done();
+        });
     });
     it("Should work with `--beautify`", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
+        var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8"));
-           done();
-       });
+            assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8"));
+            done();
+        });
     });
     it("Should work with `--beautify bracketize`", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
+        var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8"));
-           done();
-       });
+            assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8"));
+            done();
+        });
     });
     it("Should process inline source map", function(done) {
         var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline';
@@ -252,133 +252,163 @@ describe("bin/uglifyjs", function () {
         });
     });
     it("Should support hyphen as shorthand", function(done) {
-       var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true';
+        var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true';
 
-       exec(command, function (err, stdout) {
-           if (err) throw err;
+        exec(command, function (err, stdout) {
+            if (err) throw err;
 
-           assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
-           done();
-       });
+            assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
+            done();
+        });
     });
     it("Should throw syntax error (5--)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/assign_1.js:1,18",
-               "console.log(1 || 5--);",
-               "                  ^",
-               "SyntaxError: Invalid use of -- operator"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/assign_1.js:1,18",
+                "console.log(1 || 5--);",
+                "                  ^",
+                "SyntaxError: Invalid use of -- operator"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (Math.random() /= 2)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/assign_2.js:1,32",
-               "console.log(2 || (Math.random() /= 2));",
-               "                                ^",
-               "SyntaxError: Invalid assignment"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/assign_2.js:1,32",
+                "console.log(2 || (Math.random() /= 2));",
+                "                                ^",
+                "SyntaxError: Invalid assignment"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (++this)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/assign_3.js:1,17",
-               "console.log(3 || ++this);",
-               "                 ^",
-               "SyntaxError: Invalid use of ++ operator"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/assign_3.js:1,17",
+                "console.log(3 || ++this);",
+                "                 ^",
+                "SyntaxError: Invalid use of ++ operator"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (++null)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/assign_4.js:1,0",
-               "++null",
-               "^",
-               "SyntaxError: Invalid use of ++ operator"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/assign_4.js:1,0",
+                "++null",
+                "^",
+                "SyntaxError: Invalid use of ++ operator"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (a.=)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/dot_1.js:1,2",
-               "a.=",
-               "  ^",
-               "SyntaxError: Unexpected token: operator (=)"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/dot_1.js:1,2",
+                "a.=",
+                "  ^",
+                "SyntaxError: Unexpected token: operator (=)"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (%.a)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/dot_2.js:1,0",
-               "%.a;",
-               "^",
-               "SyntaxError: Unexpected token: operator (%)"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/dot_2.js:1,0",
+                "%.a;",
+                "^",
+                "SyntaxError: Unexpected token: operator (%)"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error (a./();)", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/dot_3.js:1,2",
-               "a./();",
-               "  ^",
-               "SyntaxError: Unexpected token: operator (/)"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/dot_3.js:1,2",
+                "a./();",
+                "  ^",
+                "SyntaxError: Unexpected token: operator (/)"
+            ].join("\n"));
+            done();
+        });
     });
     it("Should throw syntax error ({%: 1})", function(done) {
-       var command = uglifyjscmd + ' test/input/invalid/object.js';
-
-       exec(command, function (err, stdout, stderr) {
-           assert.ok(err);
-           assert.strictEqual(stdout, "");
-           assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
-               "Parse error at test/input/invalid/object.js:1,13",
-               "console.log({%: 1});",
-               "             ^",
-               "SyntaxError: Unexpected token: operator (%)"
-           ].join("\n"));
-           done();
-       });
+        var command = uglifyjscmd + ' test/input/invalid/object.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/object.js:1,13",
+                "console.log({%: 1});",
+                "             ^",
+                "SyntaxError: Unexpected token: operator (%)"
+            ].join("\n"));
+            done();
+        });
+    });
+    it("Should throw syntax error (else)", function(done) {
+        var command = uglifyjscmd + ' test/input/invalid/else.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/else.js:1,7",
+                "if (0) else 1;",
+                "       ^",
+                "SyntaxError: Unexpected token: keyword (else)"
+            ].join("\n"));
+            done();
+        });
+    });
+    it("Should throw syntax error (return)", function(done) {
+        var command = uglifyjscmd + ' test/input/invalid/return.js';
+
+        exec(command, function (err, stdout, stderr) {
+            assert.ok(err);
+            assert.strictEqual(stdout, "");
+            assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
+                "Parse error at test/input/invalid/return.js:1,0",
+                "return 42;",
+                "^",
+                "SyntaxError: 'return' outside of function"
+            ].join("\n"));
+            done();
+        });
     });
 });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list