From 6915519498661a1924da832f7186b216760c834b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 11 Dec 2014 17:44:45 +0100 Subject: [PATCH] Give TemplateElements a narrower range Issue #169 --- acorn.js | 44 ++++++++++++++++++++++++++++++------------- acorn_loose.js | 14 ++++++++++++-- test/tests-harmony.js | 36 +++++++++++++++++------------------ 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/acorn.js b/acorn.js index 2a21b4cd26..d7a73623b9 100644 --- a/acorn.js +++ b/acorn.js @@ -43,7 +43,7 @@ input = String(inpt); inputLen = input.length; setOptions(opts); initTokenState(); - var startPos = options.locations ? [tokPos, new Position] : tokPos; + var startPos = options.locations ? [tokPos, curPosition()] : tokPos; initParserState(); return parseTopLevel(options.program || startNodeAt(startPos)); }; @@ -314,7 +314,7 @@ function initParserState() { lastStart = lastEnd = tokPos; - if (options.locations) lastEndLoc = new Position; + if (options.locations) lastEndLoc = curPosition(); inFunction = inGenerator = strict = false; labels = []; skipSpace(); @@ -588,9 +588,17 @@ // These are used when `options.locations` is on, for the // `tokStartLoc` and `tokEndLoc` properties. - function Position() { - this.line = tokCurLine; - this.column = tokPos - tokLineStart; + function Position(line, col) { + this.line = line; + this.column = col; + } + + Position.prototype.offset = function(n) { + return new Position(this.line, this.column + n); + } + + function curPosition() { + return new Position(tokCurLine, tokPos - tokLineStart); } // Reset the token state. Used at the start of a parse. @@ -615,7 +623,7 @@ function finishToken(type, val, shouldSkipSpace) { tokEnd = tokPos; - if (options.locations) tokEndLoc = new Position; + if (options.locations) tokEndLoc = curPosition(); tokType = type; if (shouldSkipSpace !== false) skipSpace(); tokVal = val; @@ -626,7 +634,7 @@ } function skipBlockComment() { - var startLoc = options.onComment && options.locations && new Position; + var startLoc = options.onComment && options.locations && curPosition(); var start = tokPos, end = input.indexOf("*/", tokPos += 2); if (end === -1) raise(tokPos - 2, "Unterminated comment"); tokPos = end + 2; @@ -640,12 +648,12 @@ } if (options.onComment) options.onComment(true, input.slice(start + 2, end), start, tokPos, - startLoc, options.locations && new Position); + startLoc, options.locations && curPosition()); } function skipLineComment(startSkip) { var start = tokPos; - var startLoc = options.onComment && options.locations && new Position; + var startLoc = options.onComment && options.locations && curPosition(); var ch = input.charCodeAt(tokPos+=startSkip); while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { ++tokPos; @@ -653,7 +661,7 @@ } if (options.onComment) options.onComment(false, input.slice(start + startSkip, tokPos), start, tokPos, - startLoc, options.locations && new Position); + startLoc, options.locations && curPosition()); } // Called at the start of the parse and after every token. Skips @@ -881,7 +889,7 @@ function readToken(forceRegexp) { if (!forceRegexp) tokStart = tokPos; else tokPos = tokStart + 1; - if (options.locations) tokStartLoc = new Position; + if (options.locations) tokStartLoc = curPosition(); if (forceRegexp) return readRegexp(); if (tokPos >= inputLen) return finishToken(_eof); @@ -1303,6 +1311,15 @@ return node; } + function finishNodeAt(node, type, pos) { + if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; } + node.type = type; + node.end = pos; + if (options.ranges) + node.range[1] = pos; + return node; + } + // Test whether a statement node is the string literal `"use strict"`. function isUseStrict(stmt) { @@ -2154,11 +2171,12 @@ // Parse template expression. function parseTemplateElement() { - var elem = startNode(); + var elem = startNodeAt(options.locations ? [tokStart + 1, tokStartLoc.offset(1)] : tokStart + 1); elem.value = tokVal; elem.tail = input.charCodeAt(tokEnd - 1) !== 123; // '{' next(); - return finishNode(elem, "TemplateElement"); + var endOff = elem.tail ? 1 : 2; + return finishNodeAt(elem, "TemplateElement", options.locations ? [lastEnd - endOff, lastEndLoc.offset(-endOff)] : lastEnd - endOff); } function parseTemplate() { diff --git a/acorn_loose.js b/acorn_loose.js index fe11e5b114..16176d7da8 100644 --- a/acorn_loose.js +++ b/acorn_loose.js @@ -254,6 +254,14 @@ return node; } + function finishNodeAt(node, type, pos) { + if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; } + node.type = type; + node.end = pos; + if (options.ranges) node.range[1] = pos; + return node; + } + function dummyIdent() { var dummy = startNode(); dummy.name = "✖"; @@ -801,11 +809,13 @@ } function parseTemplateElement() { - var elem = startNode(); + var elem = startNodeAt(options.locations ? [token.start + 1, token.startLoc.offset(1)] : token.start + 1); elem.value = token.value; elem.tail = input.charCodeAt(token.end - 1) !== 123; // '{' + var endOff = elem.tail ? 1 : 2; + var endPos = options.locations ? [token.end - endOff, token.endLoc.offset(-endOff)] : token.end - endOff; next(); - return finishNode(elem, "TemplateElement"); + return finishNodeAt(elem, "TemplateElement", endPos); } function parseTemplate() { diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 9723073690..fbe33bee07 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -628,8 +628,8 @@ test("`42`", { value: {raw: "42", cooked: "42"}, tail: true, loc: { - start: {line: 1, column: 0}, - end: {line: 1, column:4} + start: {line: 1, column: 1}, + end: {line: 1, column: 3} } }], expressions: [], @@ -674,8 +674,8 @@ test("raw`42`", { value: {raw: "42", cooked: "42"}, tail: true, loc: { - start: {line: 1, column: 3}, - end: {line: 1, column: 7} + start: {line: 1, column: 4}, + end: {line: 1, column: 6} } }], expressions: [], @@ -726,8 +726,8 @@ test("raw`hello ${name}`", { value: {raw: "hello ", cooked: "hello "}, tail: false, loc: { - start: {line: 1, column: 3}, - end: {line: 1, column: 12} + start: {line: 1, column: 4}, + end: {line: 1, column: 10} } }, { @@ -735,8 +735,8 @@ test("raw`hello ${name}`", { value: {raw: "", cooked: ""}, tail: true, loc: { - start: {line: 1, column: 16}, - end: {line: 1, column: 18} + start: {line: 1, column: 17}, + end: {line: 1, column: 17} } } ], @@ -784,8 +784,8 @@ test("`$`", { value: {raw: "$", cooked: "$"}, tail: true, loc: { - start: {line: 1, column: 0}, - end: {line: 1, column: 3} + start: {line: 1, column: 1}, + end: {line: 1, column: 2} } }], expressions: [], @@ -820,8 +820,8 @@ test("`\\n\\r\\b\\v\\t\\f\\\n\\\r\n`", { value: {raw: "\\n\\r\\b\\v\\t\\f\\\n\\\r\n", cooked: "\n\r\b\u000b\t\f"}, tail: true, loc: { - start: {line: 1, column: 0}, - end: {line: 3, column: 1} + start: {line: 1, column: 1}, + end: {line: 3, column: 0} } }], expressions: [], @@ -856,8 +856,8 @@ test("`\n\r\n`", { value: {raw: "\n\r\n", cooked: "\n\n"}, tail: true, loc: { - start: {line: 1, column: 0}, - end: {line: 3, column: 1} + start: {line: 1, column: 1}, + end: {line: 3, column: 0} } }], expressions: [], @@ -892,8 +892,8 @@ test("`\\u{000042}\\u0042\\x42u0\\102\\A`", { value: {raw: "\\u{000042}\\u0042\\x42u0\\102\\A", cooked: "BBBu0BA"}, tail: true, loc: { - start: {line: 1, column: 0}, - end: {line: 1, column: 30} + start: {line: 1, column: 1}, + end: {line: 1, column: 29} } }], expressions: [], @@ -940,8 +940,8 @@ test("new raw`42`", { value: {raw: "42", cooked: "42"}, tail: true, loc: { - start: {line: 1, column: 7}, - end: {line: 1, column: 11} + start: {line: 1, column: 8}, + end: {line: 1, column: 10} } }], expressions: [],