diff --git a/lessc.inc.php b/lessc.inc.php index c42147c5..b2096d2f 100644 --- a/lessc.inc.php +++ b/lessc.inc.php @@ -38,9 +38,9 @@ * handling things like indentation. */ class lessc { - static public $VERSION = "v0.3.8"; - static protected $TRUE = array("keyword", "true"); - static protected $FALSE = array("keyword", "false"); + static public $VERSION = 'v0.3.8'; + static protected $TRUE = array('keyword', 'true'); + static protected $FALSE = array('keyword', 'false'); protected $libFunctions = array(); protected $registeredVars = array(); @@ -60,7 +60,7 @@ class lessc { protected $sourceParser = null; protected $sourceLoc = null; - static public $defaultValue = array("keyword", ""); + static public $defaultValue = array('keyword', ''); static protected $nextImportId = 0; // uniquely identify imports @@ -90,7 +90,7 @@ static public function preg_quote($what) { } protected function tryImport($importPath, $parentBlock, $out) { - if ($importPath[0] == "function" && $importPath[1] == "url") { + if ($importPath[0] == 'function' && $importPath[1] == 'url') { $importPath = $this->flattenList($importPath[2]); } @@ -106,7 +106,7 @@ protected function tryImport($importPath, $parentBlock, $out) { if ($realPath === null) return false; if ($this->importDisabled) { - return array(false, "/* import disabled */"); + return array(false, '/* import disabled */'); } $this->addParsedFile($realPath); @@ -115,7 +115,7 @@ protected function tryImport($importPath, $parentBlock, $out) { // set the parents of all the block props foreach ($root->props as $prop) { - if ($prop[0] == "block") { + if ($prop[0] == 'block') { $prop[1]->parent = $parentBlock; } } @@ -134,7 +134,7 @@ protected function tryImport($importPath, $parentBlock, $out) { } $pi = pathinfo($realPath); - $dir = $pi["dirname"]; + $dir = $pi['dirname']; list($top, $bottom) = $this->sortProps($root->props, true); $this->compileImportedProps($top, $parentBlock, $out, $parser, $dir); @@ -182,19 +182,19 @@ protected function compileImportedProps($props, $block, $out, $sourceParser, $im */ protected function compileBlock($block) { switch ($block->type) { - case "root": + case 'root': $this->compileRoot($block); break; case null: $this->compileCSSBlock($block); break; - case "media": + case 'media': $this->compileMedia($block); break; - case "directive": - $name = "@" . $block->name; + case 'directive': + $name = '@' . $block->name; if (!empty($block->value)) { - $name .= " " . $this->compileValue($this->reduce($block->value)); + $name .= ' ' . $this->compileValue($this->reduce($block->value)); } $this->compileNestedBlock($block, array($name)); @@ -245,7 +245,7 @@ protected function compileMedia($media) { protected function mediaParent($scope) { while (!empty($scope->parent)) { - if (!empty($scope->type) && $scope->type != "media") { + if (!empty($scope->type) && $scope->type != 'media') { break; } $scope = $scope->parent; @@ -285,18 +285,18 @@ protected function sortProps($props, $split = false) { foreach ($props as $prop) { switch ($prop[0]) { - case "assign": + case 'assign': if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) { $vars[] = $prop; } else { $other[] = $prop; } break; - case "import": + case 'import': $id = self::$nextImportId++; $prop[] = $id; $imports[] = $prop; - $other[] = array("import_mixin", $id); + $other[] = array('import_mixin', $id); break; default: $other[] = $prop; @@ -316,13 +316,13 @@ protected function compileMediaQuery($queries) { $parts = array(); foreach ($query as $q) { switch ($q[0]) { - case "mediaType": - $parts[] = implode(" ", array_slice($q, 1)); + case 'mediaType': + $parts[] = implode(' ', array_slice($q, 1)); break; - case "mediaExp": + case 'mediaExp': if (isset($q[2])) { $parts[] = "($q[1]: " . - $this->compileValue($this->reduce($q[2])) . ")"; + $this->compileValue($this->reduce($q[2])) . ')'; } else { $parts[] = "($q[1])"; } @@ -331,13 +331,13 @@ protected function compileMediaQuery($queries) { } if (count($parts) > 0) { - $compiledQueries[] = implode(" and ", $parts); + $compiledQueries[] = implode(' and ', $parts); } } - $out = "@media"; + $out = '@media'; if (!empty($parts)) { - $out .= " " . + $out .= ' ' . implode($this->formatter->selectorSeparator, $compiledQueries); } return $out; @@ -345,7 +345,7 @@ protected function compileMediaQuery($queries) { protected function multiplyMedia($env, $childQueries = null) { if (is_null($env) || - !empty($env->block->type) && $env->block->type != "media") + !empty($env->block->type) && $env->block->type != 'media') { return $childQueries; } @@ -371,7 +371,7 @@ protected function multiplyMedia($env, $childQueries = null) { } protected function expandParentSelectors(&$tag, $replace) { - $parts = explode("$&$", $tag); + $parts = explode('$&$', $tag); $count = 0; foreach ($parts as &$part) { $part = str_replace($this->parentSelector, $replace, $part, $c); @@ -404,7 +404,7 @@ protected function multiplySelectors($selectors) { if (is_null($parentSelectors)) { // kill parent reference in top level selector foreach ($selectors as &$s) { - $this->expandParentSelectors($s, ""); + $this->expandParentSelectors($s, ''); } return $selectors; @@ -458,7 +458,7 @@ protected function patternMatch($block, $callingArgs) { $this->zipSetArgs($block->args, $callingArgs); $negate = false; - if ($guard[0] == "negate") { + if ($guard[0] == 'negate') { $guard = $guard[1]; $negate = true; } @@ -494,18 +494,18 @@ protected function patternMatch($block, $callingArgs) { // try to match by arity or by argument literal foreach ($block->args as $i => $arg) { switch ($arg[0]) { - case "lit": + case 'lit': if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) { return false; } break; - case "arg": + case 'arg': // no arg and no default value if (!isset($callingArgs[$i]) && !isset($arg[2])) { return false; } break; - case "rest": + case 'rest': $i--; // rest can be empty break 2; } @@ -575,7 +575,7 @@ protected function zipSetArgs($args, $values) { $i = 0; $assignedValues = array(); foreach ($args as $a) { - if ($a[0] == "arg") { + if ($a[0] == 'arg') { if ($i < count($values) && !is_null($values[$i])) { $value = $values[$i]; } elseif (isset($a[2])) { @@ -591,9 +591,9 @@ protected function zipSetArgs($args, $values) { // check for a rest $last = end($args); - if ($last[0] == "rest") { + if ($last[0] == 'rest') { $rest = array_slice($values, count($args) - 1); - $this->set($last[1], $this->reduce(array("list", " ", $rest))); + $this->set($last[1], $this->reduce(array('list', ' ', $rest))); } $this->env->arguments = $assignedValues; @@ -621,7 +621,7 @@ protected function compileProp($prop, $block, $out) { case 'mixin': list(, $path, $args, $suffix) = $prop; - $args = array_map(array($this, "reduce"), (array)$args); + $args = array_map(array($this, 'reduce'), (array)$args); $mixins = $this->findBlocks($block, $path, $args); if ($mixins === null) { @@ -649,7 +649,7 @@ protected function compileProp($prop, $block, $out) { foreach ($this->sortProps($mixin->props) as $subProp) { if ($suffix !== null && - $subProp[0] == "assign" && + $subProp[0] == 'assign' && is_string($subProp[1]) && $subProp[1]{0} != $this->vPrefix) { @@ -672,14 +672,14 @@ protected function compileProp($prop, $block, $out) { case 'raw': $out->lines[] = $prop[1]; break; - case "directive": + case 'directive': list(, $name, $value) = $prop; $out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';'; break; - case "comment": + case 'comment': $out->lines[] = $prop[1]; break; - case "import"; + case 'import'; list(, $importPath, $importId) = $prop; $importPath = $this->reduce($importPath); @@ -690,11 +690,11 @@ protected function compileProp($prop, $block, $out) { $result = $this->tryImport($importPath, $block, $out); $this->env->imports[$importId] = $result === false ? - array(false, "@import " . $this->compileValue($importPath).";") : + array(false, '@import ' . $this->compileValue($importPath).';') : $result; break; - case "import_mixin": + case 'import_mixin': list(,$importId) = $prop; $import = $this->env->imports[$importId]; if ($import[0] === false) { @@ -767,7 +767,7 @@ protected function compileValue($value) { return 'rgba('.$r.','.$g.','.$b.','.$value[4].')'; } - $h = sprintf("#%02x%02x%02x", $r, $g, $b); + $h = sprintf('#%02x%02x%02x', $r, $g, $b); if (!empty($this->formatter->compressColors)) { // Converting hex color to short notation (e.g. #003399 to #039) @@ -787,11 +787,11 @@ protected function compileValue($value) { } protected function lib_isnumber($value) { - return $this->toBool($value[0] == "number"); + return $this->toBool($value[0] == 'number'); } protected function lib_isstring($value) { - return $this->toBool($value[0] == "string"); + return $this->toBool($value[0] == 'string'); } protected function lib_iscolor($value) { @@ -799,27 +799,27 @@ protected function lib_iscolor($value) { } protected function lib_iskeyword($value) { - return $this->toBool($value[0] == "keyword"); + return $this->toBool($value[0] == 'keyword'); } protected function lib_ispixel($value) { - return $this->toBool($value[0] == "number" && $value[2] == "px"); + return $this->toBool($value[0] == 'number' && $value[2] == 'px'); } protected function lib_ispercentage($value) { - return $this->toBool($value[0] == "number" && $value[2] == "%"); + return $this->toBool($value[0] == 'number' && $value[2] == '%'); } protected function lib_isem($value) { - return $this->toBool($value[0] == "number" && $value[2] == "em"); + return $this->toBool($value[0] == 'number' && $value[2] == 'em'); } protected function lib_rgbahex($color) { $color = $this->coerceColor($color); if (is_null($color)) - $this->throwError("color expected for rgbahex"); + $this->throwError('color expected for rgbahex'); - return sprintf("#%02x%02x%02x%02x", + return sprintf('#%02x%02x%02x%02x', isset($color[4]) ? $color[4]*255 : 255, $color[1],$color[2], $color[3]); } @@ -831,24 +831,24 @@ protected function lib_argb($color){ // utility func to unquote a string protected function lib_e($arg) { switch ($arg[0]) { - case "list": + case 'list': $items = $arg[2]; if (isset($items[0])) { return $this->lib_e($items[0]); } return self::$defaultValue; - case "string": - $arg[1] = ""; + case 'string': + $arg[1] = ''; return $arg; - case "keyword": + case 'keyword': return $arg; default: - return array("keyword", $this->compileValue($arg)); + return array('keyword', $this->compileValue($arg)); } } protected function lib__sprintf($args) { - if ($args[0] != "list") return $args; + if ($args[0] != 'list') return $args; $values = $args[2]; $string = array_shift($values); $template = $this->compileValue($this->lib_e($string)); @@ -871,23 +871,23 @@ protected function lib__sprintf($args) { } } - $d = $string[0] == "string" ? $string[1] : '"'; - return array("string", $d, array($template)); + $d = $string[0] == 'string' ? $string[1] : '"'; + return array('string', $d, array($template)); } protected function lib_floor($arg) { $value = $this->assertNumber($arg); - return array("number", floor($value), $arg[2]); + return array('number', floor($value), $arg[2]); } protected function lib_ceil($arg) { $value = $this->assertNumber($arg); - return array("number", ceil($value), $arg[2]); + return array('number', ceil($value), $arg[2]); } protected function lib_round($arg) { $value = $this->assertNumber($arg); - return array("number", round($value), $arg[2]); + return array('number', round($value), $arg[2]); } /** @@ -992,15 +992,15 @@ protected function lib_fade($args) { protected function lib_percentage($arg) { $num = $this->assertNumber($arg); - return array("number", $num*100, "%"); + return array('number', $num*100, '%'); } // mixes two colors by weight // mix(@color1, @color2, @weight); // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method protected function lib_mix($args) { - if ($args[0] != "list" || count($args[2]) < 3) - $this->throwError("mix expects (color1, color2, weight)"); + if ($args[0] != 'list' || count($args[2]) < 3) + $this->throwError('mix expects (color1, color2, weight)'); list($first, $second, $weight) = $args[2]; $first = $this->assertColor($first); @@ -1029,14 +1029,14 @@ protected function lib_mix($args) { return $this->fixColor($new); } - protected function assertColor($value, $error = "expected color value") { + protected function assertColor($value, $error = 'expected color value') { $color = $this->coerceColor($value); if (is_null($color)) $this->throwError($error); return $color; } - protected function assertNumber($value, $error = "expecting number") { - if ($value[0] == "number") return $value[1]; + protected function assertNumber($value, $error = 'expecting number') { + if ($value[0] == 'number') return $value[1]; $this->throwError($error); } @@ -1154,13 +1154,13 @@ protected function funcToColor($func) { foreach ($rawComponents as $c) { $c = $this->reduce($c); if ($i < 4) { - if ($c[0] == "number" && $c[2] == "%") { + if ($c[0] == 'number' && $c[2] == '%') { $components[] = 255 * ($c[1] / 100); } else { $components[] = floatval($c[1]); } } elseif ($i == 4) { - if ($c[0] == "number" && $c[2] == "%") { + if ($c[0] == 'number' && $c[2] == '%') { $components[] = 1.0 * ($c[1] / 100); } else { $components[] = floatval($c[1]); @@ -1179,7 +1179,7 @@ protected function funcToColor($func) { protected function reduce($value, $forExpression = false) { switch ($value[0]) { - case "variable": + case 'variable': $key = $value[1]; if (is_array($key)) { $key = $this->reduce($key); @@ -1196,31 +1196,31 @@ protected function reduce($value, $forExpression = false) { $out = $this->reduce($this->get($key, self::$defaultValue)); $seen[$key] = false; return $out; - case "list": + case 'list': foreach ($value[2] as &$item) { $item = $this->reduce($item, $forExpression); } return $value; - case "expression": + case 'expression': return $this->evaluate($value); - case "string": + case 'string': foreach ($value[2] as &$part) { if (is_array($part)) { - $strip = $part[0] == "variable"; + $strip = $part[0] == 'variable'; $part = $this->reduce($part); if ($strip) $part = $this->lib_e($part); } } return $value; - case "escape": + case 'escape': list(,$inner) = $value; return $this->lib_e($this->reduce($inner)); - case "function": + case 'function': $color = $this->funcToColor($value); if ($color) return $color; list(, $name, $args) = $value; - if ($name == "%") $name = "_sprintf"; + if ($name == '%') $name = '_sprintf'; $f = isset($this->libFunctions[$name]) ? $this->libFunctions[$name] : array($this, 'lib_'.$name); @@ -1231,13 +1231,13 @@ protected function reduce($value, $forExpression = false) { $ret = call_user_func($f, $this->reduce($args, true), $this); if (is_null($ret)) { - return array("string", "", array( - $name, "(", $args, ")" + return array('string', '', array( + $name, '(', $args, ')' )); } // convert to a typed value if the result is a php primitive - if (is_numeric($ret)) $ret = array('number', $ret, ""); + if (is_numeric($ret)) $ret = array('number', $ret, ''); elseif (!is_array($ret)) $ret = array('keyword', $ret); return $ret; @@ -1246,30 +1246,30 @@ protected function reduce($value, $forExpression = false) { // plain function, reduce args $value[2] = $this->reduce($value[2]); return $value; - case "unary": + case 'unary': list(, $op, $exp) = $value; $exp = $this->reduce($exp); - if ($exp[0] == "number") { + if ($exp[0] == 'number') { switch ($op) { - case "+": + case '+': return $exp; - case "-": + case '-': $exp[1] *= -1; return $exp; } } - return array("string", "", array($op, $exp)); + return array('string', '', array($op, $exp)); } if ($forExpression) { switch ($value[0]) { - case "keyword": + case 'keyword': if ($color = $this->coerceColor($value)) { return $color; } break; - case "raw_color": + case 'raw_color': return $this->coerceColor($value); } } @@ -1283,7 +1283,7 @@ protected function coerceColor($value) { switch($value[0]) { case 'color': return $value; case 'raw_color': - $c = array("color", 0, 0, 0); + $c = array('color', 0, 0, 0); $colorStr = substr($value[1], 1); $num = hexdec($colorStr); $width = strlen($colorStr) == 3 ? 16 : 256; @@ -1309,17 +1309,17 @@ protected function coerceColor($value) { // make something string like into a string protected function coerceString($value) { switch ($value[0]) { - case "string": + case 'string': return $value; - case "keyword": - return array("string", "", array($value[1])); + case 'keyword': + return array('string', '', array($value[1])); } return null; } // turn list of length 1 into value type protected function flattenList($value) { - if ($value[0] == "list" && count($value[2]) == 1) { + if ($value[0] == 'list' && count($value[2]) == 1) { return $this->flattenList($value[2][0]); } return $value; @@ -1349,15 +1349,15 @@ protected function evaluate($exp) { $rtype = $right[0]; // operators that work on all types - if ($op == "and") { + if ($op == 'and') { return $this->toBool($left == self::$TRUE && $right == self::$TRUE); } - if ($op == "=") { + if ($op == '=') { return $this->toBool($this->eq($left, $right) ); } - if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) { + if ($op == '+' && !is_null($str = $this->stringConcatenate($left, $right))) { return $str; } @@ -1370,16 +1370,16 @@ protected function evaluate($exp) { // make the expression look it did before being parsed $paddedOp = $op; - if ($whiteBefore) $paddedOp = " " . $paddedOp; - if ($whiteAfter) $paddedOp .= " "; + if ($whiteBefore) $paddedOp = ' ' . $paddedOp; + if ($whiteAfter) $paddedOp .= ' '; - return array("string", "", array($left, $paddedOp, $right)); + return array('string', '', array($left, $paddedOp, $right)); } protected function stringConcatenate($left, $right) { if ($strLeft = $this->coerceString($left)) { - if ($right[0] == "string") { - $right[1] = ""; + if ($right[0] == 'string') { + $right[1] = ''; } $strLeft[2][] = $right; return $strLeft; @@ -1479,7 +1479,7 @@ protected function op_number_number($op, $left, $right) { $this->throwError('parse error: unknown number operator: '.$op); } - return array("number", $value, $unit); + return array('number', $value, $unit); } @@ -1569,7 +1569,7 @@ public function __construct($fname = null) { public function compile($string, $name = null) { $locale = setlocale(LC_NUMERIC, 0); - setlocale(LC_NUMERIC, "C"); + setlocale(LC_NUMERIC, 'C'); $this->parser = $this->makeParser($name); $root = $this->parser->parse($string); @@ -1707,7 +1707,7 @@ public function parse($str = null, $initialVariables = null) { if ($str == null) { if (empty($this->_parseFile)) { - throw new exception("nothing to parse"); + throw new exception('nothing to parse'); } $out = $this->compileFile($this->_parseFile); @@ -1731,7 +1731,7 @@ public function setFormatter($name) { } protected function newFormatter() { - $className = "lessc_formatter_lessjs"; + $className = 'lessc_formatter_lessjs'; if (!empty($this->formatterName)) { if (!is_string($this->formatterName)) return $this->formatterName; @@ -1977,9 +1977,9 @@ class lessc_parser { static protected $whitePattern; static protected $commentMulti; - static protected $commentSingle = "//"; - static protected $commentMultiLeft = "/*"; - static protected $commentMultiRight = "*/"; + static protected $commentSingle = '//'; + static protected $commentMultiLeft = '/*'; + static protected $commentMultiRight = '*/'; // regex string to match any of the operators static protected $operatorString; @@ -1988,8 +1988,8 @@ class lessc_parser { static protected $supressDivisionProps = array('/border-radius$/i', '/^font$/i'); - protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document"); - protected $lineDirectives = array("charset"); + protected $blockDirectives = array('font-face', 'keyframes', 'page', '-moz-document'); + protected $lineDirectives = array('charset'); /** * if we are in parens we can be more liberal with whitespace around @@ -2034,7 +2034,7 @@ public function parse($buffer) { $this->env = null; // block stack $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer); - $this->pushSpecialBlock("root"); + $this->pushSpecialBlock('root'); $this->eatWhiteDefault = true; $this->seenComments = array(); @@ -2119,7 +2119,7 @@ protected function parseChunk() { if (($this->mediaQueryList($mediaQueries) || true) && $this->literal('{')) { - $media = $this->pushSpecialBlock("media"); + $media = $this->pushSpecialBlock('media'); $media->queries = is_null($mediaQueries) ? array() : $mediaQueries; return true; } else { @@ -2128,19 +2128,19 @@ protected function parseChunk() { } } - if ($this->literal("@", false) && $this->keyword($dirName)) { + if ($this->literal('@', false) && $this->keyword($dirName)) { if ($this->isDirective($dirName, $this->blockDirectives)) { - if (($this->openString("{", $dirValue, null, array(";")) || true) && - $this->literal("{")) + if (($this->openString('{', $dirValue, null, array(';')) || true) && + $this->literal('{')) { - $dir = $this->pushSpecialBlock("directive"); + $dir = $this->pushSpecialBlock('directive'); $dir->name = $dirName; if (isset($dirValue)) $dir->value = $dirValue; return true; } } elseif ($this->isDirective($dirName, $this->lineDirectives)) { if ($this->propertyValue($dirValue) && $this->end()) { - $this->append(array("directive", $dirName, $dirValue)); + $this->append(array('directive', $dirName, $dirValue)); return true; } } @@ -2245,8 +2245,8 @@ protected function parseChunk() { protected function isDirective($dirname, $directives) { // TODO: cache pattern in parser - $pattern = implode("|", - array_map(array("lessc", "preg_quote"), $directives)); + $pattern = implode('|', + array_map(array('lessc', 'preg_quote'), $directives)); $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i'; return preg_match($pattern, $dirname); @@ -2287,9 +2287,9 @@ protected function expression(&$out) { if (!empty($this->env->supressedDivision)) { unset($this->env->supressedDivision); $s = $this->seek(); - if ($this->literal("/") && $this->value($rhs)) { - $out = array("list", "", - array($out, array("keyword", "/"), $rhs)); + if ($this->literal('/') && $this->value($rhs)) { + $out = array('list', '', + array($out, array('keyword', '/'), $rhs)); } else { $this->seek($s); } @@ -2316,7 +2316,7 @@ protected function expHelper($lhs, $minP) { $needWhite = $whiteBefore && !$this->inParens; if ($this->match(self::$operatorString.($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) { - if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) { + if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == '/' && empty($this->env->supressedDivision)) { foreach (self::$supressDivisionProps as $pattern) { if (preg_match($pattern, $this->env->currentProperty)) { $this->env->supressedDivision = true; @@ -2377,14 +2377,14 @@ protected function parenValue(&$out) { $s = $this->seek(); // speed shortcut - if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") { + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != '(') { return false; } $inParens = $this->inParens; - if ($this->literal("(") && + if ($this->literal('(') && ($this->inParens = true) && $this->expression($exp) && - $this->literal(")")) + $this->literal(')')) { $out = $exp; $this->inParens = $inParens; @@ -2402,14 +2402,14 @@ protected function value(&$value) { $s = $this->seek(); // speed shortcut - if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") { + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == '-') { // negation - if ($this->literal("-", false) && - (($this->variable($inner) && $inner = array("variable", $inner)) || + if ($this->literal('-', false) && + (($this->variable($inner) && $inner = array('variable', $inner)) || $this->unit($inner) || $this->parenValue($inner))) { - $value = array("unary", "-", $inner); + $value = array('unary', '-', $inner); return true; } else { $this->seek($s); @@ -2434,8 +2434,8 @@ protected function value(&$value) { } // unquote string (should this work on any type? - if ($this->literal("~") && $this->string($str)) { - $value = array("escape", $str); + if ($this->literal('~') && $this->string($str)) { + $value = array('escape', $str); return true; } else { $this->seek($s); @@ -2462,13 +2462,13 @@ protected function import(&$out) { // @import url(something.css) media; if ($this->propertyValue($value)) { - $out = array("import", $value); + $out = array('import', $value); return true; } } protected function mediaQueryList(&$out) { - if ($this->genericList($list, "mediaQuery", ",", false)) { + if ($this->genericList($list, 'mediaQuery', ',', false)) { $out = $list[2]; return true; } @@ -2481,10 +2481,10 @@ protected function mediaQuery(&$out) { $expressions = null; $parts = array(); - if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) { - $prop = array("mediaType"); - if (isset($only)) $prop[] = "only"; - if (isset($not)) $prop[] = "not"; + if (($this->literal('only') && ($only = true) || $this->literal('not') && ($not = true) || true) && $this->keyword($mediaType)) { + $prop = array('mediaType'); + if (isset($only)) $prop[] = 'only'; + if (isset($not)) $prop[] = 'not'; $prop[] = $mediaType; $parts[] = $prop; } else { @@ -2492,10 +2492,10 @@ protected function mediaQuery(&$out) { } - if (!empty($mediaType) && !$this->literal("and")) { + if (!empty($mediaType) && !$this->literal('and')) { // ~ } else { - $this->genericList($expressions, "mediaExpression", "and", false); + $this->genericList($expressions, 'mediaExpression', 'and', false); if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]); } @@ -2511,12 +2511,12 @@ protected function mediaQuery(&$out) { protected function mediaExpression(&$out) { $s = $this->seek(); $value = null; - if ($this->literal("(") && + if ($this->literal('(') && $this->keyword($feature) && - ($this->literal(":") && $this->expression($value) || true) && - $this->literal(")")) + ($this->literal(':') && $this->expression($value) || true) && + $this->literal(')')) { - $out = array("mediaExp", $feature); + $out = array('mediaExp', $feature); if ($value) $out[] = $value; return true; } @@ -2530,15 +2530,15 @@ protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; - $stop = array("'", '"', "@{", $end); - $stop = array_map(array("lessc", "preg_quote"), $stop); + $stop = array("'", '"', '@{', $end); + $stop = array_map(array('lessc', 'preg_quote'), $stop); // $stop[] = self::$commentMulti; if (!is_null($rejectStrs)) { $stop = array_merge($stop, $rejectStrs); } - $patt = '(.*?)('.implode("|", $stop).')'; + $patt = '(.*?)('.implode('|', $stop).')'; $nestingLevel = 0; @@ -2567,7 +2567,7 @@ protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null continue; } - if ($tok == "@{" && $this->interpolation($inter)) { + if ($tok == '@{' && $this->interpolation($inter)) { $content[] = $inter; continue; } @@ -2591,7 +2591,7 @@ protected function openString($end, &$out, $nestingOpen=null, $rejectStrs = null $content[count($content) - 1] = rtrim(end($content)); } - $out = array("string", "", $content); + $out = array('string', '', $content); return true; } @@ -2616,13 +2616,13 @@ protected function string(&$out) { while ($this->match($patt, $m, false)) { $content[] = $m[1]; - if ($m[2] == "@{") { + if ($m[2] == '@{') { $this->count -= strlen($m[2]); if ($this->interpolation($inter, false)) { $content[] = $inter; } else { $this->count += strlen($m[2]); - $content[] = "@{"; // ignore it + $content[] = '@{'; // ignore it } } elseif ($m[2] == '\\') { $content[] = $m[2]; @@ -2638,7 +2638,7 @@ protected function string(&$out) { $this->eatWhiteDefault = $oldWhite; if ($this->literal($delim)) { - $out = array("string", $delim, $content); + $out = array('string', $delim, $content); return true; } @@ -2651,11 +2651,11 @@ protected function interpolation(&$out) { $this->eatWhiteDefault = true; $s = $this->seek(); - if ($this->literal("@{") && + if ($this->literal('@{') && $this->keyword($var) && - $this->literal("}", false)) + $this->literal('}', false)) { - $out = array("variable", $this->lessc->vPrefix . $var); + $out = array('variable', $this->lessc->vPrefix . $var); $this->eatWhiteDefault = $oldWhite; if ($this->eatWhiteDefault) $this->whitespace(); return true; @@ -2670,11 +2670,11 @@ protected function unit(&$unit) { // speed shortcut if (isset($this->buffer[$this->count])) { $char = $this->buffer[$this->count]; - if (!ctype_digit($char) && $char != ".") return false; + if (!ctype_digit($char) && $char != '.') return false; } if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) { - $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]); + $unit = array('number', $m[1], empty($m[2]) ? '' : $m[2]); return true; } return false; @@ -2684,9 +2684,9 @@ protected function unit(&$unit) { protected function color(&$out) { if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) { if (strlen($m[1]) > 7) { - $out = array("string", "", array($m[1])); + $out = array('string', '', array($m[1])); } else { - $out = array("raw_color", $m[1]); + $out = array('raw_color', $m[1]); } return true; } @@ -2729,20 +2729,20 @@ protected function argumentDef(&$args, &$isVararg, $delim = ',') { $isVararg = false; while (true) { - if ($this->literal("...")) { + if ($this->literal('...')) { $isVararg = true; break; } if ($this->variable($vname)) { - $arg = array("arg", $vname); + $arg = array('arg', $vname); $ss = $this->seek(); if ($this->assign() && $this->expressionList($value)) { $arg[] = $value; } else { $this->seek($ss); - if ($this->literal("...")) { - $arg[0] = "rest"; + if ($this->literal('...')) { + $arg[0] = 'rest'; $isVararg = true; } } @@ -2752,7 +2752,7 @@ protected function argumentDef(&$args, &$isVararg, $delim = ',') { } if ($this->value($literal)) { - $values[] = array("lit", $literal); + $values[] = array('lit', $literal); } if (!$this->literal($delim)) break; @@ -2788,7 +2788,7 @@ protected function mixinTags(&$tags) { $tags = array(); while ($this->tag($tt, true)) { $tags[] = $tt; - $this->literal(">"); + $this->literal('>'); } if (count($tags) == 0) return false; @@ -2799,7 +2799,7 @@ protected function mixinTags(&$tags) { // a bracketed value (contained within in a tag definition) protected function tagBracket(&$value) { // speed shortcut - if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") { + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != '[') { return false; } @@ -2807,10 +2807,10 @@ protected function tagBracket(&$value) { if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) { $value = '['.$c.']'; // whitespace? - if ($this->whitespace()) $value .= " "; + if ($this->whitespace()) $value .= ' '; // escape parent selector, (yuck) - $value = str_replace($this->lessc->parentSelector, "$&$", $value); + $value = str_replace($this->lessc->parentSelector, '$&$', $value); return true; } @@ -2820,7 +2820,7 @@ protected function tagBracket(&$value) { protected function tagExpression(&$value) { $s = $this->seek(); - if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + if ($this->literal('(') && $this->expression($exp) && $this->literal(')')) { $value = array('exp', $exp); return true; } @@ -2878,7 +2878,7 @@ protected function func(&$func) { $ss = $this->seek(); // this ugly nonsense is for ie filter properties if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) { - $args[] = array("string", "", array($name, "=", $value)); + $args[] = array('string', '', array($name, '=', $value)); } else { $this->seek($ss); if ($this->expressionList($value)) { @@ -2896,7 +2896,7 @@ protected function func(&$func) { } elseif ($fname == 'url') { // couldn't parse and in url? treat as string $this->seek($sPreArgs); - if ($this->openString(")", $string) && $this->literal(")")) { + if ($this->openString(')', $string) && $this->literal(')')) { $func = array('function', $fname, $string); return true; } @@ -2958,7 +2958,7 @@ protected function end() { protected function guards(&$guards) { $s = $this->seek(); - if (!$this->literal("when")) { + if (!$this->literal('when')) { $this->seek($s); return false; } @@ -2967,7 +2967,7 @@ protected function guards(&$guards) { while ($this->guardGroup($g)) { $guards[] = $g; - if (!$this->literal(",")) break; + if (!$this->literal(',')) break; } if (count($guards) == 0) { @@ -2986,7 +2986,7 @@ protected function guardGroup(&$guardGroup) { $guardGroup = array(); while ($this->guard($guard)) { $guardGroup[] = $guard; - if (!$this->literal("and")) break; + if (!$this->literal('and')) break; } if (count($guardGroup) == 0) { @@ -3000,11 +3000,11 @@ protected function guardGroup(&$guardGroup) { protected function guard(&$guard) { $s = $this->seek(); - $negate = $this->literal("not"); + $negate = $this->literal('not'); - if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) { + if ($this->literal('(') && $this->expression($exp) && $this->literal(')')) { $guard = $exp; - if ($negate) $guard = array("negate", $guard); + if ($negate) $guard = array('negate', $guard); return true; } @@ -3037,7 +3037,7 @@ protected function literal($what, $eatWhitespace = null) { return $this->match(self::$literalCache[$what], $m, $eatWhitespace); } - protected function genericList(&$out, $parseItem, $delim="", $flatten=true) { + protected function genericList(&$out, $parseItem, $delim='', $flatten=true) { $s = $this->seek(); $items = array(); while ($this->$parseItem($value)) { @@ -3055,7 +3055,7 @@ protected function genericList(&$out, $parseItem, $delim="", $flatten=true) { if ($flatten && count($items) == 1) { $out = $items[0]; } else { - $out = array("list", $delim, $items); + $out = array('list', $delim, $items); } return true; @@ -3069,7 +3069,7 @@ protected function to($what, &$out, $until = false, $allowNewline = false) { if (is_string($allowNewline)) { $validChars = $allowNewline; } else { - $validChars = $allowNewline ? "." : "[^\n]"; + $validChars = $allowNewline ? '.' : "[^\n]"; } if (!$this->match('('.$validChars.'*?)'.lessc::preg_quote($what), $m, !$until)) return false; if ($until) $this->count -= strlen($what); // give back $what @@ -3096,7 +3096,7 @@ protected function whitespace() { $gotWhite = false; while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { - $this->append(array("comment", $m[1])); + $this->append(array('comment', $m[1])); $this->commentsSeen[$this->count] = true; } $this->count += strlen($m[0]); @@ -3104,7 +3104,7 @@ protected function whitespace() { } return $gotWhite; } else { - $this->match("", $m); + $this->match('', $m); return strlen($m[0]) > 0; } } @@ -3127,7 +3127,7 @@ protected function seek($where = null) { /* misc functions */ - public function throwError($msg = "parse error", $count = null) { + public function throwError($msg = 'parse error', $count = null) { $count = is_null($count) ? $this->count : $count; $line = $this->line + @@ -3242,21 +3242,22 @@ protected function removeComments($text) { } class lessc_formatter_classic { - public $indentChar = " "; + public $indentChar = ' '; public $break = "\n"; - public $open = " {"; - public $close = "}"; - public $selectorSeparator = ", "; - public $assignSeparator = ":"; + public $open = ' {'; + public $close = '}'; + public $selectorSeparator = ', '; + public $assignSeparator = ':'; - public $openSingle = " { "; - public $closeSingle = " }"; + public $openSingle = ' { '; + public $closeSingle = ' }'; public $disableSingle = false; public $breakSelectors = false; public $compressColors = false; + public $removeLastSemicolon = false; public function __construct() { $this->indentLevel = 0; @@ -3267,7 +3268,7 @@ public function indentStr($n = 0) { } public function property($name, $value) { - return $name . $this->assignSeparator . $value . ";"; + return $name . $this->assignSeparator . $value . ';'; } protected function isEmpty($block) { @@ -3302,7 +3303,7 @@ public function block($block) { implode($selectorSeparator, $block->selectors); if ($isSingle) { echo $this->openSingle; - $inner = ""; + $inner = ''; } else { echo $this->open . $this->break; $inner = $this->indentStr(); @@ -3312,7 +3313,15 @@ public function block($block) { if (!empty($block->lines)) { $glue = $this->break.$inner; - echo $inner . implode($glue, $block->lines); + $lines = $block->lines; + + if ($this->removeLastSemicolon) { + $lastIndex = count($lines) - 1; + $lines[$lastIndex] = rtrim($lines[$lastIndex], ';'); + } + + echo $inner . implode($glue, $lines); + if (!$isSingle && !empty($block->children)) { echo $this->break; } @@ -3338,22 +3347,23 @@ public function block($block) { class lessc_formatter_compressed extends lessc_formatter_classic { public $disableSingle = true; - public $open = "{"; - public $selectorSeparator = ","; - public $assignSeparator = ":"; - public $break = ""; + public $open = '{'; + public $selectorSeparator = ','; + public $assignSeparator = ':'; + public $break = ''; public $compressColors = true; + public $removeLastSemicolon = true; public function indentStr($n = 0) { - return ""; + return ''; } } class lessc_formatter_lessjs extends lessc_formatter_classic { public $disableSingle = true; public $breakSelectors = true; - public $assignSeparator = ": "; - public $selectorSeparator = ","; + public $assignSeparator = ': '; + public $selectorSeparator = ','; }