diff --git a/lib/parse.js b/lib/parse.js index edd55e76..b9911fa2 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 00000000..89e8e501 --- /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 00000000..d232c623 --- /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 d5c9585f..9b3b6376 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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'; + 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(); - }); + 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(); + }); }); });