diff --git a/lib/less/index.js b/lib/less/index.js index ec2d302e3..009a37be2 100644 --- a/lib/less/index.js +++ b/lib/less/index.js @@ -88,7 +88,7 @@ var less = { 'call', 'url', 'alpha', 'import', 'mixin', 'comment', 'anonymous', 'value', 'javascript', 'assignment', 'condition', 'paren', - 'media', 'ratio' + 'media' ].forEach(function (n) { require('./tree/' + n); }); diff --git a/lib/less/parser.js b/lib/less/parser.js index 2bc229c6d..c00ca727b 100644 --- a/lib/less/parser.js +++ b/lib/less/parser.js @@ -61,6 +61,7 @@ less.Parser = function Parser(env) { furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` + parens = 0, // current depth of nested parentheses parser; var that = this; @@ -397,6 +398,7 @@ less.Parser = function Parser(env) { else throw new(LessError)(importError, env); } + css = css.replace(/\s+(\/)\s+/g, "$1"); if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { @@ -577,7 +579,7 @@ less.Parser = function Parser(env) { nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } - else { i += name.length } + else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); @@ -587,10 +589,15 @@ less.Parser = function Parser(env) { } $('('); // Parse the '(' and consume whitespace. + parens++; args = $(this.entities.arguments); - if (! $(')')) return; + if (! $(')')) { + parens--; + return; + } + parens--; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, @@ -604,8 +611,7 @@ less.Parser = function Parser(env) { return args; }, literal: function () { - return $(this.entities.ratio) || - $(this.entities.dimension) || + return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, @@ -702,20 +708,6 @@ less.Parser = function Parser(env) { } }, - // - // A Ratio - // - // 16/9 - // - ratio: function () { - var value, c = input.charCodeAt(i); - if (c > 57 || c < 48) return; - - if (value = $(/^(\d+\/\d+)/)) { - return new(tree.Ratio)(value[1]); - } - }, - // // JavaScript code to be evaluated // @@ -746,27 +738,6 @@ less.Parser = function Parser(env) { if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, - // - // A font size/line-height shorthand - // - // small/12px - // - // We need to peek first, or we'll match on keywords and dimensions - // - shorthand: function () { - var a, b; - - if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; - - save(); - - if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { - return new(tree.Shorthand)(a, b); - } - - restore(); - }, - // // Mixins // @@ -786,7 +757,7 @@ less.Parser = function Parser(env) { var elements = [], e, c, args = [], arg, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } - + save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { @@ -826,7 +797,7 @@ less.Parser = function Parser(env) { if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } - + restore(); }, @@ -885,7 +856,7 @@ less.Parser = function Parser(env) { } } while ($(',')) - // .mixincall("@{a}"); + // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; @@ -1014,7 +985,7 @@ less.Parser = function Parser(env) { // :nth-child(@a) // vs // .a:hover(@a) - + e = $('&'); $('('); if (e) { @@ -1098,8 +1069,6 @@ less.Parser = function Parser(env) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); - } else if (name === "font") { - value = $(this.font); } else { value = $(this.value); } @@ -1126,9 +1095,9 @@ less.Parser = function Parser(env) { // "import": function () { var path, features, index = i; - + save(); - + var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { @@ -1137,7 +1106,7 @@ less.Parser = function Parser(env) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index); } } - + restore(); }, @@ -1149,7 +1118,7 @@ less.Parser = function Parser(env) { nodes.push(e); } else if ($('(')) { p = $(this.property); - e = $(this.entity); + e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); @@ -1209,7 +1178,7 @@ less.Parser = function Parser(env) { if (value = $(this['import']) || $(this.media)) { return value; } - + save(); name = $(/^@[a-z-]+/); @@ -1265,24 +1234,8 @@ less.Parser = function Parser(env) { return new(tree.Directive)(name, value); } } - - restore(); - }, - font: function () { - var value = [], expression = [], weight, shorthand, font, e; - - while (e = $(this.shorthand) || $(this.entity)) { - expression.push(e); - } - value.push(new(tree.Expression)(expression)); - if ($(',')) { - while (e = $(this.expression)) { - value.push(e); - if (! $(',')) { break } - } - } - return new(tree.Value)(value); + restore(); }, // @@ -1313,15 +1266,28 @@ less.Parser = function Parser(env) { sub: function () { var e; - if ($('(') && (e = $(this.expression)) && $(')')) { - return e; + if ($('(')) { + parens++; + if (e = $(this.expression)) { + expect(')'); + parens--; + return e; + } } }, multiplication: function () { - var m, a, op, operation; + var m, a, op, operation, expression = []; if (m = $(this.operand)) { - while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { - operation = new(tree.Operation)(op, [operation || m, a]); + while (!peek(/^\/\*/) && (op = ($('/') || $('*')))) { + if (op === '/' && !parens) { + expression.push(operation || m); + expression.push(new(tree.Anonymous)('/')); + operation = new(tree.Expression)(expression); + } else if (a = $(this.operand)) { + operation = new(tree.Operation)(op, [operation || m, a]); + } else { + break; + } } return operation || m; } @@ -1393,6 +1359,9 @@ less.Parser = function Parser(env) { while (e = $(this.addition) || $(this.entity)) { entities.push(e); + if (!peek(/^\/\*/) && (delim = $('/'))) { + entities.push(new(tree.Anonymous)(delim)); + } } if (entities.length > 0) { return new(tree.Expression)(entities); diff --git a/lib/less/tree/ratio.js b/lib/less/tree/ratio.js deleted file mode 100644 index f7622fb89..000000000 --- a/lib/less/tree/ratio.js +++ /dev/null @@ -1,13 +0,0 @@ -(function (tree) { - -tree.Ratio = function (value) { - this.value = value; -}; -tree.Ratio.prototype = { - toCSS: function (env) { - return this.value; - }, - eval: function () { return this } -}; - -})(require('../tree')); diff --git a/test/css/css.css b/test/css/css.css index 78ea14dc7..4f06f4301 100644 --- a/test/css/css.css +++ b/test/css/css.css @@ -62,6 +62,9 @@ p + h1 { padding: 1px 0 2px 0; font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; font: 0/0 a; + border-radius: 5px/10px; + background: url("img.jpg") center/100px; + background: #ffffff url(image.png) center/1px 100px repeat-x scroll content-box padding-box; } .misc { -moz-border-radius: 2px; diff --git a/test/css/mixins-args.css b/test/css/mixins-args.css index d5b67f304..feba5c2e9 100644 --- a/test/css/mixins-args.css +++ b/test/css/mixins-args.css @@ -72,3 +72,8 @@ body { border: "{"; width: "{"; } +.slash-vs-math { + border-radius: 2px/5px; + border-radius: 5px/10px; + border-radius: 6px; +} diff --git a/test/css/parens.css b/test/css/parens.css index 36487fe59..71d3d0d5c 100644 --- a/test/css/parens.css +++ b/test/css/parens.css @@ -9,6 +9,7 @@ width: 96; height: 113; margin: 12; + border-radius: 8px/7px; } .nested-parens { width: 71; diff --git a/test/less/css.less b/test/less/css.less index abcd2c08d..3d2017891 100644 --- a/test/less/css.less +++ b/test/less/css.less @@ -67,8 +67,11 @@ p + h1 { #more-shorthands { margin: 0; padding: 1px 0 2px 0; - font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; + font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; font: 0/0 a; + border-radius: 5px / 10px; + background: url("img.jpg") center / 100px; + background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; } .misc { diff --git a/test/less/media.less b/test/less/media.less index 3dc1aabba..66f9fc447 100644 --- a/test/less/media.less +++ b/test/less/media.less @@ -20,7 +20,7 @@ body { max-width: @base * 60; } } -@media all and (device-aspect-ratio: 16/9) { +@media all and (device-aspect-ratio: 16 / 9) { body { max-width: 800px; } } @@ -172,7 +172,7 @@ body { } } -@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { +@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2 / 1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { .b { background: red; } diff --git a/test/less/mixins-args.less b/test/less/mixins-args.less index ea43a0a53..656ad023d 100644 --- a/test/less/mixins-args.less +++ b/test/less/mixins-args.less @@ -128,3 +128,13 @@ body { .edge-case { .mixin-arguments("{"); } + +// Division vs. Literal Slash +.border-radius(@r: 2px/5px) { + border-radius: @r; +} +.slash-vs-math { + .border-radius(); + .border-radius(5px/10px); + .border-radius((3px * 2px)); +} diff --git a/test/less/operations.less b/test/less/operations.less index 46b0aa393..637d43e3c 100644 --- a/test/less/operations.less +++ b/test/less/operations.less @@ -1,13 +1,13 @@ #operations { color: #110000 + #000011 + #001100; // #111111 - height: 10px / 2px + 6px - 1px * 2; // 9px + height: (10px / 2px + 6px - 1px * 2); // 9px width: 2 * 4 - 5em; // 3em .spacing { - height: 10px / 2px+6px-1px*2; + height: (10px / 2px+6px-1px*2); width: 2 * 4-5em; } substraction: 20 - 10 - 5 - 5; // 0 - division: 20 / 5 / 4; // 1 + division: (20 / 5 / 4); // 1 } @x: 4; @@ -20,7 +20,7 @@ } .with-functions { - color: rgb(200, 200, 200) / 2; + color: (rgb(200, 200, 200) / 2); color: 2 * hsl(0, 50%, 50%); color: rgb(10, 10, 10) + hsl(0, 50%, 50%); } @@ -37,7 +37,7 @@ } .rem-dimensions { - font-size: 20rem / 5 + 1.5rem; // 5.5rem + font-size: (20rem / 5 + 1.5rem); // 5.5rem } .colors { @@ -46,7 +46,7 @@ background-color: #222222 - #fff; // #000000 .other { color: 2 * #111; // #222222 - border-color: #333333 / 3 + #111; // #222222 + border-color: (#333333 / 3 + #111); // #222222 } } diff --git a/test/less/parens.less b/test/less/parens.less index e020c7eb3..51bd21f7b 100644 --- a/test/less/parens.less +++ b/test/less/parens.less @@ -11,7 +11,8 @@ padding: (2 * @var) 4 4 (@var * 1px); width: (@var * @var) * 6; height: (7 * 7) + (8 * 8); - margin: 4 * (5 + 5) / 2 - (@var * 2); + margin: (4 * (5 + 5) / 2) - (@var * 2); + border-radius: 4px * (1 + 1) / @var + 3px; //margin: (6 * 6)px; }