slice parsing
This commit is contained in:
parent
89a5a03ca0
commit
843aeffa41
@ -50,6 +50,9 @@ less.Parser = function Parser(env) {
|
||||
var input, // LeSS input string
|
||||
i, // current index in `input`
|
||||
j, // current chunk
|
||||
temp,
|
||||
memo,
|
||||
chunk,
|
||||
furthest, // furthest index the parser has gone to
|
||||
chunks, // chunkified input
|
||||
current, // index of current chunk, in `input`
|
||||
@ -84,11 +87,27 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
};
|
||||
|
||||
function save(){
|
||||
temp = chunk;
|
||||
memo = i;
|
||||
current = i;
|
||||
}
|
||||
function restore() {
|
||||
chunks[j] = chunk = temp;
|
||||
i = memo;
|
||||
current = i;
|
||||
}
|
||||
function sync() {
|
||||
if (i > current) {
|
||||
chunks[j] = chunk = chunk.slice(i - current);
|
||||
current = i;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Parse from a token, regexp or string, and move forward if match
|
||||
//
|
||||
function $(tok) {
|
||||
var match, args, length, c, index, endIndex;
|
||||
var match, args, length, c, index, endIndex, k;
|
||||
|
||||
//
|
||||
// Non-terminal
|
||||
@ -104,6 +123,7 @@ less.Parser = function Parser(env) {
|
||||
} else if (typeof(tok) === 'string') {
|
||||
match = input.charAt(i) === tok ? tok : null;
|
||||
length = 1;
|
||||
sync ();
|
||||
|
||||
// 1. We move to the next chunk, if necessary.
|
||||
// 2. Set the `lastIndex` to be relative
|
||||
@ -114,14 +134,11 @@ less.Parser = function Parser(env) {
|
||||
// index, which we stored in [2].
|
||||
//
|
||||
} else {
|
||||
if (i >= current + chunks[j].length &&
|
||||
j < chunks.length - 1) { // 1.
|
||||
current += chunks[j++].length;
|
||||
}
|
||||
tok.lastIndex = index = i - current; // 2.
|
||||
match = tok.exec(chunks[j]);
|
||||
sync ();
|
||||
|
||||
if (match && (match.index === index)) { // 3.
|
||||
match = tok.exec(chunk);
|
||||
|
||||
if (match) { // 3.
|
||||
length = match[0].length;
|
||||
} else { return }
|
||||
}
|
||||
@ -133,13 +150,18 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
if (match) {
|
||||
i += length;
|
||||
endIndex = current + chunks[j].length;
|
||||
var mem = i;
|
||||
endIndex = i + chunk.length - length;
|
||||
|
||||
while (i <= endIndex) {
|
||||
while (i < endIndex) {
|
||||
c = input.charCodeAt(i);
|
||||
if (! (c === 32 || c === 10 || c === 9)) { break }
|
||||
i++;
|
||||
}
|
||||
chunks[j] = chunk = chunk.slice(length + (i - mem));
|
||||
current = i;
|
||||
|
||||
if (chunk.length === 0 && j < chunks.length - 1) { chunk = chunks[++j] }
|
||||
|
||||
if(typeof(match) === 'string') {
|
||||
return match;
|
||||
@ -152,21 +174,25 @@ less.Parser = function Parser(env) {
|
||||
// Same as $(), but don't change the state of the parser,
|
||||
// just return the match.
|
||||
function peek(tok) {
|
||||
var match, index;
|
||||
|
||||
if (typeof(tok) === 'string') {
|
||||
return input.charAt(i) === tok;
|
||||
} else {
|
||||
index = i - current;
|
||||
tok.lastIndex = index;
|
||||
|
||||
if ((match = tok.exec(chunks[j])) &&
|
||||
(match.index === index)) {
|
||||
return match;
|
||||
if (tok.test(chunk)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function exec(tok) {
|
||||
var match;
|
||||
|
||||
if ((match = tok.exec(chunks[j]))) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
this.env = env || {};
|
||||
|
||||
// The optimization level dictates the thoroughness of the parser,
|
||||
@ -246,6 +272,7 @@ less.Parser = function Parser(env) {
|
||||
chunks = [input];
|
||||
}
|
||||
inputLength = input.length;
|
||||
chunk = chunks[0];
|
||||
|
||||
// Start with the primary rule.
|
||||
// The whole syntax tree is held under a Ruleset node,
|
||||
@ -387,7 +414,7 @@ less.Parser = function Parser(env) {
|
||||
|
||||
while (node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
|
||||
$(this.mixin.call) || $(this.comment) ||
|
||||
$(/[\n\s]+/g) || $(this.directive)) {
|
||||
$(/^[\n\s]+/) || $(this.directive)) {
|
||||
root.push(node);
|
||||
}
|
||||
return root;
|
||||
@ -402,8 +429,8 @@ less.Parser = function Parser(env) {
|
||||
if (input.charAt(i) !== '/') return;
|
||||
|
||||
if (input.charAt(i + 1) === '/') {
|
||||
return new(tree.Comment)($(/\/\/.*/g), true);
|
||||
} else if (comment = $(/\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/g)) {
|
||||
return new(tree.Comment)($(/^\/\/.*/), true);
|
||||
} else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
|
||||
return new(tree.Comment)(comment);
|
||||
}
|
||||
},
|
||||
@ -421,7 +448,7 @@ less.Parser = function Parser(env) {
|
||||
var str;
|
||||
if (input.charAt(i) !== '"' && input.charAt(i) !== "'") return;
|
||||
|
||||
if (str = $(/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/g)) {
|
||||
if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
|
||||
return new(tree.Quoted)(str[0], str[1] || str[2]);
|
||||
}
|
||||
},
|
||||
@ -433,7 +460,7 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
keyword: function () {
|
||||
var k;
|
||||
if (k = $(/[A-Za-z-]+/g)) { return new(tree.Keyword)(k) }
|
||||
if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) }
|
||||
},
|
||||
|
||||
//
|
||||
@ -449,7 +476,7 @@ less.Parser = function Parser(env) {
|
||||
call: function () {
|
||||
var name, args;
|
||||
|
||||
if (! (name = $(/([\w-]+|%)\(/g))) return;
|
||||
if (! (name = $(/^([\w-]+|%)\(/))) return;
|
||||
|
||||
if (name[1].toLowerCase() === 'alpha') { return $(this.alpha) }
|
||||
|
||||
@ -484,8 +511,8 @@ less.Parser = function Parser(env) {
|
||||
url: function () {
|
||||
var value;
|
||||
|
||||
if (input.charAt(i) !== 'u' || !$(/url\(/g)) return;
|
||||
value = $(this.entities.quoted) || $(/[-\w%@$\/.&=:;#+?]+/g);
|
||||
if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
|
||||
value = $(this.entities.quoted) || $(/^[-\w%@$\/.&=:;#+?]+/);
|
||||
if (! $(')')) throw new(Error)("missing closing ) for url()");
|
||||
|
||||
return new(tree.URL)(value.value ? value : new(tree.Anonymous)(value));
|
||||
@ -502,7 +529,7 @@ less.Parser = function Parser(env) {
|
||||
variable: function () {
|
||||
var name, index = i;
|
||||
|
||||
if (input.charAt(i) === '@' && (name = $(/@[\w-]+/g))) {
|
||||
if (input.charAt(i) === '@' && (name = $(/^@[\w-]+/))) {
|
||||
return new(tree.Variable)(name, index);
|
||||
}
|
||||
},
|
||||
@ -517,7 +544,7 @@ less.Parser = function Parser(env) {
|
||||
color: function () {
|
||||
var rgb;
|
||||
|
||||
if (input.charAt(i) === '#' && (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g))) {
|
||||
if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
|
||||
return new(tree.Color)(rgb[1]);
|
||||
}
|
||||
},
|
||||
@ -531,7 +558,7 @@ less.Parser = function Parser(env) {
|
||||
var value, c = input.charCodeAt(i);
|
||||
if ((c > 57 || c < 45) || c === 47) return;
|
||||
|
||||
if (value = $(/(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm)?/g)) {
|
||||
if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm)?/)) {
|
||||
return new(tree.Dimension)(value[1], value[2]);
|
||||
}
|
||||
}
|
||||
@ -545,7 +572,7 @@ less.Parser = function Parser(env) {
|
||||
variable: function () {
|
||||
var name;
|
||||
|
||||
if (input.charAt(i) === '@' && (name = $(/(@[\w-]+)\s*:/g))) { return name[1] }
|
||||
if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
|
||||
},
|
||||
|
||||
//
|
||||
@ -558,7 +585,7 @@ less.Parser = function Parser(env) {
|
||||
shorthand: function () {
|
||||
var a, b;
|
||||
|
||||
if (! peek(/[@\w.-]+\/[@\w.-]+/g)) return;
|
||||
if (! peek(/^[@\w.-]+\/[@\w.-]+/)) return;
|
||||
|
||||
if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
|
||||
return new(tree.Shorthand)(a, b);
|
||||
@ -585,7 +612,7 @@ less.Parser = function Parser(env) {
|
||||
|
||||
if (s !== '.' && s !== '#') { return }
|
||||
|
||||
while (e = $(/[#.][\w-]+/g)) {
|
||||
while (e = $(/^[#.][\w-]+/)) {
|
||||
elements.push(new(tree.Element)(c, e));
|
||||
c = $('>');
|
||||
}
|
||||
@ -618,12 +645,13 @@ less.Parser = function Parser(env) {
|
||||
definition: function () {
|
||||
var name, params = [], match, ruleset, param, value;
|
||||
|
||||
if (input.charAt(i) !== '.' || peek(/[^{]*(;|})/g)) return;
|
||||
if (input.charAt(i) !== '.' || peek(/^[^{]*(;|})/)) return;
|
||||
|
||||
if (match = $(/([#.][\w-]+)\s*\(/g)) {
|
||||
|
||||
if (match = $(/^([#.][\w-]+)\s*\(/)) {
|
||||
name = match[1];
|
||||
|
||||
while (param = $(/@[\w-]+/g) || $(this.entities.literal)
|
||||
while (param = $(/^@[\w-]+/) || $(this.entities.literal)
|
||||
|| $(this.entities.keyword)) {
|
||||
// Variable
|
||||
if (param[0] === '@') {
|
||||
@ -678,8 +706,8 @@ less.Parser = function Parser(env) {
|
||||
alpha: function () {
|
||||
var value;
|
||||
|
||||
if (! $(/opacity=/gi)) return;
|
||||
if (value = $(/\d+/g) || $(this.entities.variable)) {
|
||||
if (! $(/^opacity=/i)) return;
|
||||
if (value = $(/^\d+/) || $(this.entities.variable)) {
|
||||
if (! $(')')) throw new(Error)("missing closing ) for alpha()");
|
||||
return new(tree.Alpha)(value);
|
||||
}
|
||||
@ -701,7 +729,7 @@ less.Parser = function Parser(env) {
|
||||
var e, t;
|
||||
|
||||
c = $(this.combinator);
|
||||
e = $(/[.#:]?[\w-]+/g) || $('*') || $(this.attribute) || $(/\([^)@]+\)/g);
|
||||
e = $(/^[.#:]?[\w-]+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
|
||||
|
||||
if (e) { return new(tree.Element)(c, e) }
|
||||
},
|
||||
@ -753,16 +781,16 @@ less.Parser = function Parser(env) {
|
||||
if (elements.length > 0) { return new(tree.Selector)(elements) }
|
||||
},
|
||||
tag: function () {
|
||||
return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $('*');
|
||||
return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
|
||||
},
|
||||
attribute: function () {
|
||||
var attr = '', key, val, op;
|
||||
|
||||
if (! $('[')) return;
|
||||
|
||||
if (key = $(/[a-z-]+/g) || $(this.entities.quoted)) {
|
||||
if ((op = $(/[|~*$^]?=/g)) &&
|
||||
(val = $(this.entities.quoted) || $(/[\w-]+/g))) {
|
||||
if (key = $(/^[a-z-]+/) || $(this.entities.quoted)) {
|
||||
if ((op = $(/^[|~*$^]?=/)) &&
|
||||
(val = $(this.entities.quoted) || $(/^[\w-]+/))) {
|
||||
attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
|
||||
} else { attr = key }
|
||||
}
|
||||
@ -788,9 +816,10 @@ less.Parser = function Parser(env) {
|
||||
// div, .class, body > p {...}
|
||||
//
|
||||
ruleset: function () {
|
||||
var selectors = [], s, rules, match, memo = i;
|
||||
var selectors = [], s, rules, match;
|
||||
save();
|
||||
|
||||
if (match = peek(/([.#: \w-]+)[\s\n]*\{/g)) {
|
||||
if (match = exec(/^([.#: \w-]+)[\s\n]*\{/)) {
|
||||
i += match[0].length - 1;
|
||||
selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])];
|
||||
} else {
|
||||
@ -806,17 +835,17 @@ less.Parser = function Parser(env) {
|
||||
} else {
|
||||
// Backtrack
|
||||
furthest = i;
|
||||
i = memo;
|
||||
restore();
|
||||
}
|
||||
},
|
||||
rule: function () {
|
||||
var value, c = input.charAt(i);
|
||||
var memo = i;
|
||||
save();
|
||||
|
||||
if (c === '.' || c === '#' || c === '&') { return }
|
||||
|
||||
if (name = $(this.variable) || $(this.property)) {
|
||||
if ((name.charAt(0) != '@') && (match = peek(/([^@+\/*(;{}-]*);/g))) {
|
||||
if ((name.charAt(0) != '@') && (match = exec(/^([^@+\/*(;{}-]*);/))) {
|
||||
i += match[0].length - 1;
|
||||
value = new(tree.Anonymous)(match[1]);
|
||||
} else if (name === "font") {
|
||||
@ -829,7 +858,7 @@ less.Parser = function Parser(env) {
|
||||
return new(tree.Rule)(name, value, memo);
|
||||
} else {
|
||||
furthest = i;
|
||||
i = memo;
|
||||
restore();
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -846,7 +875,7 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
"import": function () {
|
||||
var path;
|
||||
if ($(/@import\s+/g) &&
|
||||
if ($(/^@import\s+/) &&
|
||||
(path = $(this.entities.quoted) || $(this.entities.url)) &&
|
||||
$(';')) {
|
||||
return new(tree.Import)(path, imports);
|
||||
@ -865,12 +894,12 @@ less.Parser = function Parser(env) {
|
||||
|
||||
if (value = $(this['import'])) {
|
||||
return value;
|
||||
} else if (name = $(/@media|@page/g)) {
|
||||
types = $(/[^{]+/g).trim();
|
||||
} else if (name = $(/^@media|@page/)) {
|
||||
types = $(/^[^{]+/).trim();
|
||||
if (rules = $(this.block)) {
|
||||
return new(tree.Directive)(name + " " + types, rules);
|
||||
}
|
||||
} else if (name = $(/@[-a-z]+/g)) {
|
||||
} else if (name = $(/^@[-a-z]+/)) {
|
||||
if (name === '@font-face') {
|
||||
if (rules = $(this.block)) {
|
||||
return new(tree.Directive)(name, rules);
|
||||
@ -920,7 +949,7 @@ less.Parser = function Parser(env) {
|
||||
},
|
||||
important: function () {
|
||||
if (input.charAt(i) === '!') {
|
||||
return $(/!\s*important/g);
|
||||
return $(/^!\s*important/);
|
||||
}
|
||||
},
|
||||
sub: function () {
|
||||
@ -942,7 +971,7 @@ less.Parser = function Parser(env) {
|
||||
addition: function () {
|
||||
var m, a, op, operation;
|
||||
if (m = $(this.multiplication)) {
|
||||
while ((op = $(/[-+]\s+/g) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
|
||||
while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
|
||||
(a = $(this.multiplication))) {
|
||||
operation = new(tree.Operation)(op, [operation || m, a]);
|
||||
}
|
||||
@ -979,7 +1008,7 @@ less.Parser = function Parser(env) {
|
||||
property: function () {
|
||||
var name;
|
||||
|
||||
if (name = $(/(\*?-?[-a-z_0-9]+)\s*:/g)) {
|
||||
if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
|
||||
return name[1];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user