mirror of
https://github.com/less/less.js.git
synced 2026-01-23 06:07:56 -05:00
New input chunker in parser.js. #1615
This commit is contained in:
@@ -359,96 +359,136 @@ less.Parser = function Parser(env) {
|
||||
parser.imports.contents[env.currentFileInfo.filename] = str;
|
||||
|
||||
// Split the input into chunks.
|
||||
chunks = (function (chunks, input) {
|
||||
var j = 0,
|
||||
skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
|
||||
comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
|
||||
string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
|
||||
level = 0,
|
||||
match,
|
||||
chunk = chunks[0],
|
||||
inputLen = input.length,
|
||||
inParam;
|
||||
chunks = (function (input) {
|
||||
var checkParenLevel = false; // todo: enable?
|
||||
|
||||
for (var i = 0, c, cc; i < inputLen;) {
|
||||
skip.lastIndex = i;
|
||||
if (match = skip.exec(input)) {
|
||||
if (match.index === i) {
|
||||
i += match[0].length;
|
||||
chunk.push(match[0]);
|
||||
}
|
||||
}
|
||||
c = input.charAt(i);
|
||||
comment.lastIndex = string.lastIndex = i;
|
||||
var len = input.length, level = 0, parenLevel = 0,
|
||||
lastOpening, lastClosing, lastMultiComment, lastMultiCommentEndBrace,
|
||||
chunks = [], emitFrom = 0,
|
||||
k, ko, cc, cc2, matched;
|
||||
|
||||
if (match = string.exec(input)) {
|
||||
if (match.index === i) {
|
||||
i += match[0].length;
|
||||
chunk.push(match[0]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inParam && c === '/') {
|
||||
cc = input.charAt(i + 1);
|
||||
if (cc === '/' || cc === '*') {
|
||||
if (match = comment.exec(input)) {
|
||||
if (match.index === i) {
|
||||
i += match[0].length;
|
||||
chunk.push(match[0]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '{':
|
||||
if (!inParam) {
|
||||
level++;
|
||||
chunk.push(c);
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
case '}':
|
||||
if (!inParam) {
|
||||
level--;
|
||||
chunk.push(c);
|
||||
chunks[++j] = chunk = [];
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
case '(':
|
||||
if (!inParam) {
|
||||
inParam = true;
|
||||
chunk.push(c);
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
case ')':
|
||||
if (inParam) {
|
||||
inParam = false;
|
||||
chunk.push(c);
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
default:
|
||||
chunk.push(c);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
if (level !== 0) {
|
||||
function fail(msg, index) {
|
||||
index = index || k;
|
||||
error = new(LessError)({
|
||||
index: i-1,
|
||||
index: index || k,
|
||||
type: 'Parse',
|
||||
message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
|
||||
message: msg,
|
||||
filename: env.currentFileInfo.filename
|
||||
}, env);
|
||||
}
|
||||
|
||||
return chunks.map(function (c) { return c.join(''); });
|
||||
})([[]], str);
|
||||
function emitChunk(force) {
|
||||
var len = k - emitFrom;
|
||||
if (((len < 512) && !force) || !len) {
|
||||
return;
|
||||
}
|
||||
chunks.push(input.slice(emitFrom, k + 1));
|
||||
emitFrom = k + 1;
|
||||
}
|
||||
|
||||
for (k = 0; k < len; k++) {
|
||||
cc = input.charCodeAt(k);
|
||||
if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
|
||||
// a-z or whitespace
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cc) {
|
||||
case 40: // (
|
||||
parenLevel++; continue;
|
||||
case 41: // )
|
||||
parenLevel--; continue;
|
||||
case 59: // ;
|
||||
if (!parenLevel) { emitChunk(); }
|
||||
continue;
|
||||
case 123: // {
|
||||
level++; lastOpening = k; continue;
|
||||
case 125: // }
|
||||
level--; lastClosing = k;
|
||||
if (!level) { emitChunk(); }
|
||||
continue;
|
||||
case 92: // \
|
||||
if (k < len - 1) { k++; continue; }
|
||||
fail("unescaped '\\'");
|
||||
break;
|
||||
case 34:
|
||||
case 39:
|
||||
case 96: // ", ' and `
|
||||
matched = 0;
|
||||
ko = k;
|
||||
for (k = k + 1; k < len; k++) {
|
||||
cc2 = input.charCodeAt(k);
|
||||
if (cc2 > 96) { continue; }
|
||||
if (cc2 == cc) { matched = 1; break; }
|
||||
if (cc2 == 92) { // \
|
||||
if (k == len - 1) {
|
||||
fail("unescaped '\\'");
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
if (matched) { continue; }
|
||||
if (!error) {
|
||||
fail("unmatched '" + String.fromCharCode(cc) + "'", ko);
|
||||
}
|
||||
break;
|
||||
case 47: // /, check for comment
|
||||
if (parenLevel || (k == len - 1)) { continue; }
|
||||
cc2 = input.charCodeAt(k + 1);
|
||||
if (cc2 == 47) {
|
||||
// //, find lnfeed
|
||||
for (k = k + 2; k < len; k++) {
|
||||
cc2 = input.charCodeAt(k);
|
||||
if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
|
||||
}
|
||||
} else if (cc2 == 42) {
|
||||
// /*, find */
|
||||
lastMultiComment = ko = k;
|
||||
for (k = k + 2; k < len - 1; k++) {
|
||||
cc2 = input.charCodeAt(k);
|
||||
if (cc2 == 125) { lastMultiCommentEndBrace = k; }
|
||||
if (cc2 != 42) { continue; }
|
||||
if (input.charCodeAt(k + 1) == 47) { break; }
|
||||
}
|
||||
if (k == len - 1) {
|
||||
fail("missing closing `*/`", ko);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case 42: // *, check for unmatched */
|
||||
if ((k < len - 1) && (input.charCodeAt(k + 1) == 47)) {
|
||||
fail("unmatched `/*`");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// only reaches here on error
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
if (level !== 0) {
|
||||
if (level > 0) {
|
||||
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
|
||||
fail("missing closing `}` or `*/`", lastOpening);
|
||||
} else {
|
||||
fail("missing closing `}`", lastOpening);
|
||||
}
|
||||
} else {
|
||||
fail("missing opening `{`", lastClosing);
|
||||
}
|
||||
} else if (checkParenLevel && (parenLevel !== 0)) {
|
||||
fail((parenLevel > 0) ? "missing closing `)`" : "missing opening `(`");
|
||||
}
|
||||
}
|
||||
|
||||
emitChunk(true);
|
||||
return chunks;
|
||||
})(str);
|
||||
|
||||
current = chunks[0];
|
||||
|
||||
@@ -938,7 +978,7 @@ less.Parser = function Parser(env) {
|
||||
option = option && option[1];
|
||||
|
||||
extend = new(tree.Extend)(new(tree.Selector)(elements), option, index);
|
||||
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
||||
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
||||
|
||||
} while($char(","));
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 3, column 1:
|
||||
ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 1, column 6:
|
||||
1 body {
|
||||
2 background-color: #fff;
|
||||
3
|
||||
|
||||
Reference in New Issue
Block a user