Files
less.js/lib/less/parser/chunker.js
2014-08-24 18:56:01 +01:00

113 lines
5.0 KiB
JavaScript

// Split the input into chunks.
module.exports = function (input, fail) {
var len = input.length, level = 0, parenLevel = 0,
lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
chunks = [], emitFrom = 0,
chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
function emitChunk(force) {
var len = chunkerCurrentIndex - emitFrom;
if (((len < 512) && !force) || !len) {
return;
}
chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));
emitFrom = chunkerCurrentIndex + 1;
}
for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc = input.charCodeAt(chunkerCurrentIndex);
if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
// a-z or whitespace
continue;
}
switch (cc) {
case 40: // (
parenLevel++;
lastOpeningParen = chunkerCurrentIndex;
continue;
case 41: // )
if (--parenLevel < 0) {
return fail("missing opening `(`", chunkerCurrentIndex);
}
continue;
case 59: // ;
if (!parenLevel) { emitChunk(); }
continue;
case 123: // {
level++;
lastOpening = chunkerCurrentIndex;
continue;
case 125: // }
if (--level < 0) {
return fail("missing opening `{`", chunkerCurrentIndex);
}
if (!level && !parenLevel) { emitChunk(); }
continue;
case 92: // \
if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; }
return fail("unescaped `\\`", chunkerCurrentIndex);
case 34:
case 39:
case 96: // ", ' and `
matched = 0;
currentChunkStartIndex = chunkerCurrentIndex;
for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if (cc2 > 96) { continue; }
if (cc2 == cc) { matched = 1; break; }
if (cc2 == 92) { // \
if (chunkerCurrentIndex == len - 1) {
return fail("unescaped `\\`", chunkerCurrentIndex);
}
chunkerCurrentIndex++;
}
}
if (matched) { continue; }
return fail("unmatched `" + String.fromCharCode(cc) + "`", currentChunkStartIndex);
case 47: // /, check for comment
if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; }
cc2 = input.charCodeAt(chunkerCurrentIndex + 1);
if (cc2 == 47) {
// //, find lnfeed
for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
}
} else if (cc2 == 42) {
// /*, find */
lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;
for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; }
if (cc2 != 42) { continue; }
if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; }
}
if (chunkerCurrentIndex == len - 1) {
return fail("missing closing `*/`", currentChunkStartIndex);
}
chunkerCurrentIndex++;
}
continue;
case 42: // *, check for unmatched */
if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {
return fail("unmatched `/*`", chunkerCurrentIndex);
}
continue;
}
}
if (level !== 0) {
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
return fail("missing closing `}` or `*/`", lastOpening);
} else {
return fail("missing closing `}`", lastOpening);
}
} else if (parenLevel !== 0) {
return fail("missing closing `)`", lastOpeningParen);
}
emitChunk(true);
return chunks;
};