From bdfff94920b8046bae6ec7062f73903aa2f0e6a8 Mon Sep 17 00:00:00 2001 From: seven-phases-max Date: Sun, 22 Dec 2013 18:25:39 +0400 Subject: [PATCH 1/2] * functions.js: (minor) reworking to clean-up initialization of "externally" defined functions (math, blending, `default`). * `default` function "front-end" reworked for a bit higher-level control from its "back-end" code (e.g. tree.mixin.eval). --- lib/less/functions.js | 101 +++++++++++++++++++++++++++-------------- lib/less/tree/mixin.js | 7 ++- 2 files changed, 70 insertions(+), 38 deletions(-) diff --git a/lib/less/functions.js b/lib/less/functions.js index 9cbced11e..9f2703f0d 100644 --- a/lib/less/functions.js +++ b/lib/less/functions.js @@ -232,12 +232,6 @@ tree.functions = { str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, - default: function () { - if (this.default.enabled) { - return this.default.value - ? tree.True : tree.False; - } - }, unit: function (val, unit) { if(!(val instanceof tree.Dimension)) { throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof tree.Operation ? ". Have you forgotten parenthesis?" : "") }; @@ -249,7 +243,7 @@ tree.functions = { }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; - return this._math(function(num) { return num.toFixed(fraction); }, null, n); + return _math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); @@ -267,15 +261,6 @@ tree.functions = { return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, - _math: function (fn, unit, n) { - if (n instanceof tree.Dimension) { - return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); - } else if (typeof(n) === 'number') { - return fn(n); - } else { - throw { type: "Argument", message: "argument must be a number" }; - } - }, _minmax: function (isMin, args) { args = Array.prototype.slice.call(args); switch(args.length) { @@ -565,22 +550,36 @@ tree._mime = { } }; -var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, - {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, - {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], - createMathFunction = function(name, unit) { - return function(n) { - if (unit != null) { - n = n.unify(); - } - return this._math(Math[name], unit, n); - }; - }; +// Math + +var mathFunctions = { + // name, unit + ceil: null, + floor: null, + sqrt: null, + abs: null, + tan: "", + sin: "", + cos: "", + atan: "rad", + asin: "rad", + acos: "rad" +}; -for(var i = 0; i < mathFunctions.length; i++) { - tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); +function _math(fn, unit, n) { + if (!(n instanceof tree.Dimension)) { + throw { type: "Argument", message: "argument must be a number" }; + } + if (unit == null) { + unit = n.unit; + } else { + n = n.unify(); + } + return new(tree.Dimension)(fn(parseFloat(n.value)), unit); } +// ~ End of Math + // Color Blending // ref: http://www.w3.org/TR/compositing-1 @@ -645,13 +644,47 @@ var colorBlendMode = { } }; -function colorBlendInit() { - for (var f in colorBlendMode) { - tree.functions[f] = colorBlend.bind(null, colorBlendMode[f]); +// ~ End of Color Blending + +tree.defaultFunc = { + eval: function () { + var v = this.value_, e = this.error_; + if (e) { + throw e; + } + if (v != null) { + return v ? tree.True : tree.False; + } + }, + value: function (v) { + this.value_ = v; + }, + error: function (e) { + this.error_ = e; + }, + reset: function () { + this.value_ = this.error_ = null; } -} colorBlendInit(); +}; -// ~ End of Color Blending +function initFunctions() { + var f, tf = tree.functions; + + // math + for (f in mathFunctions) { + tf[f] = _math.bind(null, Math[f], mathFunctions[f]); + } + + // color blending + for (f in colorBlendMode) { + tf[f] = colorBlend.bind(null, colorBlendMode[f]); + } + + // default + f = tree.defaultFunc; + tf.default = f.eval.bind(f); + +} initFunctions(); function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); diff --git a/lib/less/tree/mixin.js b/lib/less/tree/mixin.js index ac4dd888b..f5beded0f 100644 --- a/lib/less/tree/mixin.js +++ b/lib/less/tree/mixin.js @@ -20,7 +20,7 @@ tree.mixin.Call.prototype = { }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule; - var candidates = [], candidate, conditionResult = [], defaultFunc = tree.functions.default, defaultUsed = false; + var candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc, defaultUsed = false; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; @@ -29,7 +29,6 @@ tree.mixin.Call.prototype = { for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; - defaultFunc.enabled = true; // To make `default()` function independent of definition order we have two "subpasses" here. // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`), @@ -54,7 +53,7 @@ tree.mixin.Call.prototype = { if (mixin.matchCondition) { for (f = 0; f < 2; f++) { - defaultFunc.value = f; + defaultFunc.value(f); conditionResult[f] = mixin.matchCondition(args, env); } if (conditionResult[0] || conditionResult[1]) { @@ -86,7 +85,7 @@ tree.mixin.Call.prototype = { } } - defaultFunc.enabled = false; + defaultFunc.reset(); for (m in candidates) { candidate = candidates[m]; From bbc15a413bb54251f23e00175a7e534cec896c58 Mon Sep 17 00:00:00 2001 From: seven-phases-max Date: Sun, 22 Dec 2013 18:54:39 +0400 Subject: [PATCH 2/2] `default` function: added error when used with css-guards. updated tests. --- lib/less/tree/ruleset.js | 8 +++++++- test/css/mixins-guards-default-func.css | 6 ++++++ test/less/errors/css-guard-default-func.less | 4 ++++ test/less/errors/css-guard-default-func.txt | 4 ++++ test/less/mixins-guards-default-func.less | 20 ++++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/less/errors/css-guard-default-func.less create mode 100644 test/less/errors/css-guard-default-func.txt diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js index 0618c245d..d224df8d1 100644 --- a/lib/less/tree/ruleset.js +++ b/lib/less/tree/ruleset.js @@ -19,12 +19,18 @@ tree.Ruleset.prototype = { } }, eval: function (env) { - var thisSelectors = this.selectors, selectors, selCnt, i; + var thisSelectors = this.selectors, selectors, + selCnt, i, defaultFunc = tree.defaultFunc; if (thisSelectors && (selCnt = thisSelectors.length)) { selectors = []; + defaultFunc.error({ + type: "Syntax", + message: "it is currently only allowed in parametric mixin guards," + }); for (i = 0; i < selCnt; i++) { selectors.push(thisSelectors[i].eval(env)); } + defaultFunc.reset(); } var rules = this.rules ? this.rules.slice(0) : null, diff --git a/test/css/mixins-guards-default-func.css b/test/css/mixins-guards-default-func.css index efc993858..4b6910c34 100644 --- a/test/css/mixins-guards-default-func.css +++ b/test/css/mixins-guards-default-func.css @@ -112,3 +112,9 @@ guard-default-multi-4 { always: 2; case: 2; } +guard-default-scopes-3 { + 3: when default; +} +guard-default-scopes-1 { + 1: no condition; +} diff --git a/test/less/errors/css-guard-default-func.less b/test/less/errors/css-guard-default-func.less new file mode 100644 index 000000000..db6639e17 --- /dev/null +++ b/test/less/errors/css-guard-default-func.less @@ -0,0 +1,4 @@ + +selector when (default()) { + color: red; +} diff --git a/test/less/errors/css-guard-default-func.txt b/test/less/errors/css-guard-default-func.txt new file mode 100644 index 000000000..ea670295e --- /dev/null +++ b/test/less/errors/css-guard-default-func.txt @@ -0,0 +1,4 @@ +SyntaxError: error evaluating function `default`: it is currently only allowed in parametric mixin guards, in {path}css-guard-default-func.less on line 2, column 16: +1 +2 selector when (default()) { +3 color: red; diff --git a/test/less/mixins-guards-default-func.less b/test/less/mixins-guards-default-func.less index 7b75dd93f..56a8e4b6a 100644 --- a/test/less/mixins-guards-default-func.less +++ b/test/less/mixins-guards-default-func.less @@ -157,3 +157,23 @@ guard-default-multi-4 { .m(1); .m(2); } + +// default & scope + +guard-default-scopes { + .s1() {.m(@v) {1: no condition}} + .s2() {.m(@v) when (@v) {2: when true}} + .s3() {.m(@v) when (default()) {3: when default}} + + &-3 { + .s2(); + .s3(); + .m(false); + } + + &-1 { + .s1(); + .s3(); + .m(false); + } +}