diff --git a/lib/compiler/passes/generate-code.js b/lib/compiler/passes/generate-code.js index 3faf8f2..79e5b97 100644 --- a/lib/compiler/passes/generate-code.js +++ b/lib/compiler/passes/generate-code.js @@ -334,6 +334,8 @@ module.exports = function(ast, options) { ' ', ' var pos = 0;', ' var reportedPos = 0;', + ' var cachedReportedPos = 0;', + ' var cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };', ' var reportFailures = 0;', // 0 = report, anything > 0 = do not report ' var rightmostFailuresPos = 0;', ' var rightmostFailuresExpected = [];', @@ -370,16 +372,48 @@ module.exports = function(ast, options) { ' return \'\\\\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), \'0\', length);', ' }', ' ', + ' function computeReportedPosDetails() {', + ' function advanceCachedReportedPos() {', + ' var ch;', + ' ', + ' for (; cachedReportedPos < reportedPos; cachedReportedPos++) {', + ' ch = input.charAt(cachedReportedPos);', + ' if (ch === "\\n") {', + ' if (!cachedReportedPosDetails.seenCR) { cachedReportedPosDetails.line++; }', + ' cachedReportedPosDetails.column = 1;', + ' cachedReportedPosDetails.seenCR = false;', + ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {', + ' cachedReportedPosDetails.line++;', + ' cachedReportedPosDetails.column = 1;', + ' cachedReportedPosDetails.seenCR = true;', + ' } else {', + ' cachedReportedPosDetails.column++;', + ' cachedReportedPosDetails.seenCR = false;', + ' }', + ' }', + ' }', + ' ', + ' if (cachedReportedPos !== reportedPos) {', + ' if (cachedReportedPos > reportedPos) {', + ' cachedReportedPos = 0;', + ' cachedReportedPosDetails = { line: 1, column: 1, seenCR: false };', + ' }', + ' advanceCachedReportedPos();', + ' }', + ' ', + ' return cachedReportedPosDetails;', + ' }', + ' ', ' function offset() {', ' return reportedPos;', ' }', ' ', ' function line() {', - ' return computePosDetails(reportedPos).line;', + ' return computeReportedPosDetails().line;', ' }', ' ', ' function column() {', - ' return computePosDetails(reportedPos).column;', + ' return computeReportedPosDetails().column;', ' }', ' ', ' function matchFailed(failure) {', @@ -414,37 +448,6 @@ module.exports = function(ast, options) { ' return cleanExpected;', ' }', ' ', - ' function computePosDetails(pos) {', - ' /*', - ' * The first idea was to use |String.split| to break the input up to the', - ' * error position along newlines and derive the line and column from', - ' * there. However IE\'s |split| implementation is so broken that it was', - ' * enough to prevent it.', - ' */', - ' ', - ' var line = 1;', - ' var column = 1;', - ' var seenCR = false;', - ' ', - ' for (var i = 0; i < pos; i++) {', - ' var ch = input.charAt(i);', - ' if (ch === "\\n") {', - ' if (!seenCR) { line++; }', - ' column = 1;', - ' seenCR = false;', - ' } else if (ch === "\\r" || ch === "\\u2028" || ch === "\\u2029") {', - ' line++;', - ' column = 1;', - ' seenCR = true;', - ' } else {', - ' column++;', - ' seenCR = false;', - ' }', - ' }', - ' ', - ' return { line: line, column: column };', - ' }', - ' ', ' #if node.initializer', ' #block emit(node.initializer)', ' #end', @@ -476,16 +479,16 @@ module.exports = function(ast, options) { ' * handle these states.', ' */', ' if (result === null || pos !== input.length) {', - ' var offset = Math.max(pos, rightmostFailuresPos);', - ' var found = offset < input.length ? input.charAt(offset) : null;', - ' var errorPosition = computePosDetails(Math.max(pos, rightmostFailuresPos));', + ' reportedPos = Math.max(pos, rightmostFailuresPos);', + ' var found = reportedPos < input.length ? input.charAt(reportedPos) : null;', + ' var reportedPosDetails = computeReportedPosDetails();', ' ', ' throw new this.SyntaxError(', ' cleanupExpected(rightmostFailuresExpected),', ' found,', - ' offset,', - ' errorPosition.line,', - ' errorPosition.column', + ' reportedPos,', + ' reportedPosDetails.line,', + ' reportedPosDetails.column', ' );', ' }', ' ',