mixin guards

Allows functional-style guard expressions:

  .mixin (@a) ? @a > 0 {...}
This commit is contained in:
Alexis Sellier
2011-12-15 23:38:53 +01:00
parent db72c646bb
commit 321920a50d
6 changed files with 80 additions and 13 deletions

View File

@@ -73,12 +73,12 @@ var less = {
}
};
['color', 'directive', 'operation', 'dimension',
'keyword', 'variable', 'ruleset', 'element',
'selector', 'quoted', 'expression', 'rule',
'call', 'url', 'alpha', 'import',
'mixin', 'comment', 'anonymous', 'value',
'javascript', 'assignment'
['color', 'directive', 'operation', 'dimension',
'keyword', 'variable', 'ruleset', 'element',
'selector', 'quoted', 'expression', 'rule',
'call', 'url', 'alpha', 'import',
'mixin', 'comment', 'anonymous', 'value',
'javascript', 'assignment', 'condition'
].forEach(function (n) {
require('./tree/' + n);
});

View File

@@ -733,7 +733,7 @@ less.Parser = function Parser(env) {
// the `{...}` block.
//
definition: function () {
var name, params = [], match, ruleset, param, value;
var name, params = [], match, ruleset, param, value, cond, memo;
if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
peek(/^[^{]*(;|})/)) return;
@@ -761,10 +761,17 @@ less.Parser = function Parser(env) {
}
if (! $(')')) throw new(Error)("Expected )");
memo = i;
if ($('?')) { // Guard
cond = $(this.condition);
if (! cond) { i = memo }
}
ruleset = $(this.block);
if (ruleset) {
return new(tree.mixin.Definition)(name, params, ruleset);
return new(tree.mixin.Definition)(name, params, ruleset, cond);
}
}
}
@@ -1080,6 +1087,16 @@ less.Parser = function Parser(env) {
return operation || m;
}
},
condition: function () {
var a, op, index = i;
if (a = $(this.addition)) {
if (op = $(/^[<=>]/)) {
if (b = $(this.addition)) {
return new(tree.Condition)(op, a, b, index);
}
}
}
},
//
// An operand is anything that can be part of an operation,

View File

@@ -0,0 +1,28 @@
(function (tree) {
tree.Condition = function (op, l, r, i) {
this.op = op.trim();
this.lvalue = l;
this.rvalue = r;
this.index = i;
};
tree.Condition.prototype.eval = function (env) {
var a = this.lvalue.eval(env),
b = this.rvalue.eval(env);
var i = this.index;
if (a.compare) {
switch (a.compare(b)) {
case -1: return this.op === '<';
case 0: return this.op === '=';
case 1: return this.op === '>';
}
} else {
throw { type: "Type",
message: "Unable to perform comparison",
index: i };
}
};
})(require('../tree'));

View File

@@ -28,6 +28,19 @@ tree.Dimension.prototype = {
return new(tree.Dimension)
(tree.operate(op, this.value, other.value),
this.unit || other.unit);
},
// TODO: Perform unit conversion before comparing
compare: function (other) {
if (other instanceof tree.Dimension) {
if (other.value > this.value) {
return -1;
} else if (other.value < this.value) {
return 1;
} else {
return 0;
}
}
}
};

View File

@@ -15,7 +15,7 @@ tree.Expression.prototype = {
},
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS(env);
return e.toCSS ? e.toCSS(env) : '';
}).join(' ');
}
};

View File

@@ -41,10 +41,11 @@ tree.mixin.Call.prototype = {
}
};
tree.mixin.Definition = function (name, params, rules) {
tree.mixin.Definition = function (name, params, rules, condition) {
this.name = name;
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
this.params = params;
this.condition = condition;
this.arity = params.length;
this.rules = rules;
this._lookups = {};
@@ -62,8 +63,8 @@ tree.mixin.Definition.prototype = {
find: function () { return this.parent.find.apply(this, arguments) },
rulesets: function () { return this.parent.rulesets.apply(this) },
eval: function (env, args) {
var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
evalParams: function (env, args) {
var frame = new(tree.Ruleset)(null, []);
for (var i = 0, val; i < this.params.length; i++) {
if (this.params[i].name) {
@@ -75,6 +76,11 @@ tree.mixin.Definition.prototype = {
}
}
}
return frame;
},
eval: function (env, args) {
var frame = this.evalParams(env, args), context, _arguments = [];
for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
_arguments.push(args[i] || this.params[i].value);
}
@@ -85,10 +91,13 @@ tree.mixin.Definition.prototype = {
});
},
match: function (args, env) {
var argsLength = (args && args.length) || 0, len;
var argsLength = (args && args.length) || 0, len, frame;
if (argsLength < this.required) { return false }
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
if (this.condition && !this.condition.eval({
frames: [this.evalParams(env, args)]
})) { return false }
len = Math.min(argsLength, this.arity);