From 6c854ad221bc420396963710d31732c6ff986b58 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 5 Sep 2014 15:31:15 +0200 Subject: [PATCH 1/4] [loose parser] Be more careful about calling resetTo It will try to eat whitespace, and can thus raise an unterminated comment exception Issue #375 --- acorn_loose.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/acorn_loose.js b/acorn_loose.js index 208c188afc..b3506b46b5 100644 --- a/acorn_loose.js +++ b/acorn_loose.js @@ -86,7 +86,7 @@ // Try to skip some text, based on the error message, and then continue var msg = e.message, pos = e.raisedAt, replace = true; if (/unterminated/i.test(msg)) { - pos = lineEnd(e.pos); + pos = lineEnd(e.pos + 1); if (/string/.test(msg)) { replace = {start: e.pos, end: pos, type: tt.string, value: input.slice(e.pos + 1, pos)}; } else if (/regular expr/i.test(msg)) { @@ -125,10 +125,18 @@ } function resetTo(pos) { - var ch = input.charAt(pos - 1); - var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || - /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos)); - fetchToken.jumpTo(pos, reAllowed); + for (;;) { + try { + var ch = input.charAt(pos - 1); + var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || + /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos)); + return fetchToken.jumpTo(pos, reAllowed); + } catch(e) { + if (!(e instanceof SyntaxError && /unterminated comment/i.test(e.message))) throw e; + pos = lineEnd(e.pos + 1); + if (pos >= input.length) return; + } + } } function lookAhead(n) { From 7da3b6f1fd3c97063b169daa4305638508d8098d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 3 Sep 2014 18:20:39 +0100 Subject: [PATCH 2/4] Fix start position for HTML comments and add tests. --- acorn.js | 14 ++++++-------- test/driver.js | 24 +++++++++++++++++++++--- test/tests.js | 47 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/acorn.js b/acorn.js index acf76f6a6c..d7e6ce4e85 100644 --- a/acorn.js +++ b/acorn.js @@ -565,16 +565,16 @@ startLoc, options.locations && new Position); } - function skipLineComment() { + function skipLineComment(startSkip) { var start = tokPos; var startLoc = options.onComment && options.locations && new Position; - var ch = input.charCodeAt(tokPos+=2); + var ch = input.charCodeAt(tokPos+=startSkip); while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { ++tokPos; ch = input.charCodeAt(tokPos); } if (options.onComment) - options.onComment(false, input.slice(start + 2, tokPos), start, tokPos, + options.onComment(false, input.slice(start + startSkip, tokPos), start, tokPos, startLoc, options.locations && new Position); } @@ -609,7 +609,7 @@ if (next === 42) { // '*' skipBlockComment(); } else if (next === 47) { // '/' - skipLineComment(); + skipLineComment(2); } else break; } else if (ch === 160) { // '\xa0' ++tokPos; @@ -678,8 +678,7 @@ if (next == 45 && input.charCodeAt(tokPos + 2) == 62 && newline.test(input.slice(lastEnd, tokPos))) { // A `-->` line comment - tokPos += 3; - skipLineComment(); + skipLineComment(3); skipSpace(); return readToken(); } @@ -700,8 +699,7 @@ if (next == 33 && code == 60 && input.charCodeAt(tokPos + 2) == 45 && input.charCodeAt(tokPos + 3) == 45) { // ` HTML comment", {}, {locations: true}, + [{ + block: false, + text: " HTML comment", + startLoc: { line: 2, column: 0 }, + endLoc: { line: 2, column: 16 } + }]); })(); (function() { @@ -28747,4 +28784,4 @@ testFail("for(const x = 0;;);", "Unexpected token (1:4)", {ecmaVersion: 6}); actualTokens.push(token); } }); -})(); \ No newline at end of file +})(); From a246bf83d00f6888268997dbf55533bb33e66bd3 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 5 Sep 2014 11:18:49 +0100 Subject: [PATCH 3/4] Do not throw syntax error if strict mode function has same name as one of its parameters. --- acorn.js | 2 +- index.html | 16 +++++++--------- test/tests.js | 2 ++ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/acorn.js b/acorn.js index d7e6ce4e85..f01d4a4ef5 100644 --- a/acorn.js +++ b/acorn.js @@ -2258,7 +2258,7 @@ if (strict || !isExpression && node.body.body.length && isUseStrict(node.body.body[0])) { var nameHash = {}; if (node.id) - checkFunctionParam(node.id, nameHash); + checkFunctionParam(node.id, {}); for (var i = 0; i < node.params.length; i++) checkFunctionParam(node.params[i], nameHash); if (node.rest) diff --git a/index.html b/index.html index bfdc2e1c12..d0d5e8de73 100644 --- a/index.html +++ b/index.html @@ -356,16 +356,16 @@ the next one's tokStart will point at the right position.

startLoc, options.locations && new Position); } - function skipLineComment() { + function skipLineComment(startSkip) { var start = tokPos; var startLoc = options.onComment && options.locations && new Position; - var ch = input.charCodeAt(tokPos+=2); + var ch = input.charCodeAt(tokPos+=startSkip); while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { ++tokPos; ch = input.charCodeAt(tokPos); } if (options.onComment) - options.onComment(false, input.slice(start + 2, tokPos), start, tokPos, + options.onComment(false, input.slice(start + startSkip, tokPos), start, tokPos, startLoc, options.locations && new Position); }

Called at the start of the parse and after every token. Skips whitespace and comments, and.

  function skipSpace() {
@@ -396,7 +396,7 @@ whitespace and comments, and.

if (next === 42) { // '*' skipBlockComment(); } else if (next === 47) { // '/' - skipLineComment(); + skipLineComment(2); } else break; } else if (ch === 160) { // '\xa0' ++tokPos; @@ -457,8 +457,7 @@ into it.

var next = input.charCodeAt(tokPos + 1); if (next === code) { if (next == 45 && input.charCodeAt(tokPos + 2) == 62 && - newline.test(input.slice(lastEnd, tokPos))) {

A --> line comment

        tokPos += 3;
-        skipLineComment();
+          newline.test(input.slice(lastEnd, tokPos))) {

A --> line comment

        skipLineComment(3);
         skipSpace();
         return readToken();
       }
@@ -477,8 +476,7 @@ into it.

return finishOp(_bitShift, size); } if (next == 33 && code == 60 && input.charCodeAt(tokPos + 2) == 45 && - input.charCodeAt(tokPos + 3) == 45) {

<!--, an XML-style comment that should be interpreted as a line comment

      tokPos += 4;
-      skipLineComment();
+        input.charCodeAt(tokPos + 3) == 45) {

<!--, an XML-style comment that should be interpreted as a line comment

      skipLineComment(4);
       skipSpace();
       return readToken();
     }
@@ -1750,7 +1748,7 @@ are not repeated, and it does not try to bind the words eval
 or arguments.

    if (strict || !isExpression && node.body.body.length && isUseStrict(node.body.body[0])) {
       var nameHash = {};
       if (node.id)
-        checkFunctionParam(node.id, nameHash);
+        checkFunctionParam(node.id, {});
       for (var i = 0; i < node.params.length; i++)
         checkFunctionParam(node.params[i], nameHash);
       if (node.rest)
diff --git a/test/tests.js b/test/tests.js
index 211d4a1bec..b51695ad24 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -28785,3 +28785,5 @@ test("