Changeset 115043 in spip-zone


Ignore:
Timestamp:
Apr 24, 2019, 3:48:13 PM (4 weeks ago)
Author:
cedric@…
Message:

On integre le gros upgrade de la librairie ScssPHP en provenance de https://github.com/Cerdic/scssphp/tree/maint/leafo/master qui est une branche de maintenance forkee de https://github.com/leafo/scssphp et qui intègre proprement toutes les PR en attente chez leafo
Notamment des ameliorations de perf notables sur le parseur, et un vrai fix pour la compilation de BS4, car celui qui etait integre provoquait d'autre bug
Tout est propre, tous les patchs mis a jour sont dans des PR chez leafo, donc si il veut maintenir il peut tout integrer, mais comme rien ne bouge chez lui depuis un moment on bascule sur ce fork en attendant de voir ce qu'il se passe

Location:
_plugins_/scssphp/trunk
Files:
19 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/scssphp/trunk/lib/scssphp/README.md

    r114927 r115043  
    11# scssphp
     2### <http://leafo.github.io/scssphp>
     3### Maintenance branch forked from leafo/master
    24
    3 Forked version for SPIP SCSSPHP plugin : https://github.com/Cerdic/scssphp/tree/version-plugin-spip
    4 used in https://plugins.spip.net/scssphp
    5 
    6 ### <http://leafo.github.io/scssphp>
    7 
    8 [![Build](https://travis-ci.org/leafo/scssphp.svg?branch=master)](http://travis-ci.org/leafo/scssphp)
     5[![Build](https://travis-ci.org/Cerdic/scssphp.svg?branch=maint/leafo/master)](https://travis-ci.org/Cerdic/scssphp)
    96[![License](https://poser.pugx.org/leafo/scssphp/license.svg)](https://packagist.org/packages/leafo/scssphp)
    107
  • _plugins_/scssphp/trunk/lib/scssphp/composer.json

    r114927 r115043  
    1919    },
    2020    "autoload-dev": {
    21         "psr-4": { "Leafo\\ScssPhp\\Test\\": "tests/" },
    22         "classmap": [
    23             "src/"
    24         ]
     21        "psr-4": { "Leafo\\ScssPhp\\Test\\": "tests/" }
    2522    },
    2623    "require": {
     
    2926    "require-dev": {
    3027        "squizlabs/php_codesniffer": "~2.5",
    31         "phpunit/phpunit": "^7"
     28        "phpunit/phpunit": "~4.6"
    3229    },
    3330    "bin": ["bin/pscss"],
  • _plugins_/scssphp/trunk/lib/scssphp/src/Block.php

    r114927 r115043  
    6666     * @var \Leafo\ScssPhp\Block
    6767     */
    68     public $atrootParent;
    69     /**
    70      * @var array
    71      */
    72     public $atrootParentSelectors;
     68    public $selfParent;
    7369}
  • _plugins_/scssphp/trunk/lib/scssphp/src/Cache.php

    r114986 r115043  
    1212namespace Leafo\ScssPhp;
    1313
    14 
    1514use Exception;
    1615
     
    2827 * @author Cedric Morin
    2928 */
    30 class Cache {
    31 
    32         const cache_version = 0;
    33 
    34 
    35         // directory used for storing data
    36         public static $cache_dir = false;
    37 
    38         // prefix for the storing data
    39         public static $prefix = 'scssphp_';
    40 
    41         public static $force_refresh = false;
    42 
    43         // specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
    44         public static $gc_lifetime = 604800;
    45 
    46 
    47         /**
    48          * Constructor
    49          */
    50         public function __construct($options){
    51                 //check $cache_dir
    52                 if (isset($options['cache_dir'])){
    53                         self::$cache_dir = $options['cache_dir'];
    54                 }
    55 
    56                 if (empty(self::$cache_dir)){
    57                         throw new Exception('cache_dir not set');
    58                 }
    59 
    60                 if (isset($options['prefix'])){
    61                         self::$prefix = $options['prefix'];
    62                 }
    63 
    64                 if (empty(self::$prefix)){
    65                         throw new Exception('prefix not set');
    66                 }
    67 
    68                 if (isset($options['force_refresh'])){
    69                         self::$force_refresh = $options['force_refresh'];
    70                 }
    71 
    72                 self::checkCacheDir();
    73         }
    74 
    75 
    76         /**
    77          * Generic get
    78          *    Get the previous computed result of $what, affected by $options
    79          *
    80          * @param string $operation
    81          *   parse, compile?
    82          * @param $what
    83          *  content key (filename to be treated?)
    84          * @param array $options
    85          *  any option that affect the operation result on the content
    86          * @param int $last_modified
    87          * @return mixed
    88          * @throws Exception
    89          */
    90         public function getCache( $operation, $what, $options = array(), $last_modified = null){
    91                
    92                 $fileCache = self::$cache_dir . self::cacheName( $operation, $what, $options);
    93                
    94                 if (!self::$force_refresh
    95                   and file_exists($fileCache)) {
    96 
    97                         $cache_time = filemtime($fileCache);
    98                         if (
    99                                 (is_null($last_modified) or $cache_time > $last_modified)
    100                                 and $cache_time + self::$gc_lifetime > time() ) {
    101 
    102                                 $c = file_get_contents($fileCache);
    103                                 $c = unserialize($c);
    104                                 if (is_array($c) and isset($c['value'])) {
    105                                         return $c['value'];
    106                                 }
    107                         }
    108 
    109                 }
    110 
    111                 return null;
    112 
    113         }
    114 
    115         public function setCache( $operation, $what, $value, $options = array()){
    116                 $fileCache = self::$cache_dir . self::cacheName( $operation, $what, $options);
    117 
    118                 $c = array('value' => $value);
    119                 $c = serialize($c);
    120                 file_put_contents($fileCache, $c);
    121         }
    122 
    123 
    124         private static function cacheName( $operation, $what, $options = array() ){
    125 
    126                 $t = array(
    127                         'version' => self::cache_version,
    128                         'operation' => $operation,
    129                         'what' => $what,
    130                         'options' => $options
    131                 );
    132 
    133                 $t = self::$prefix
    134                         . sha1(json_encode($t))
    135                         . ".$operation"
    136                         . ".scsscache";
    137 
    138                 return $t;
    139         }
    140 
    141 
    142         public static function checkCacheDir(){
    143 
    144                 self::$cache_dir = str_replace('\\', '/', self::$cache_dir);
    145                 self::$cache_dir = rtrim(self::$cache_dir, '/') . '/';
    146 
    147                 if (!file_exists(self::$cache_dir)){
    148                         if (!mkdir(self::$cache_dir)){
    149                                 throw new Exception('Cache directory couldn\'t be created: ' . self::$cache_dir);
    150                         }
    151 
    152                 } elseif (!is_dir(self::$cache_dir)) {
    153                         throw new Exception('Cache directory doesn\'t exist: ' . self::$cache_dir);
    154 
    155                 } elseif (!is_writable(self::$cache_dir)) {
    156                         throw new Exception('Cache directory isn\'t writable: ' . self::$cache_dir);
    157 
    158                 }
    159 
    160         }
    161 
    162         /**
    163          * Delete unused cached files
    164          *
    165          */
    166         public static function CleanCache(){
    167                 static $clean = false;
    168 
    169 
    170                 if( $clean || empty(self::$cache_dir) ){
    171                         return;
    172                 }
    173 
    174                 $clean = true;
    175 
    176                 // only remove files with extensions created by SCSSPHP Cache
    177                 // css files removed based on the list files
    178                 $remove_types = array('scsscache'=>1);
    179 
    180                 $files = scandir(self::$cache_dir);
    181                 if( !$files ){
    182                         return;
    183                 }
    184 
    185                 $check_time = time() - self::$gc_lifetime;
    186                 foreach($files as $file){
    187 
    188 
    189                         // don't delete if the file wasn't created with SCSSPHP Cache
    190                         if( strpos($file,self::$prefix) !== 0 ){
    191                                 continue;
    192                         }
    193 
    194                         $parts = explode('.',$file);
    195                         $type = array_pop($parts);
    196 
    197 
    198                         if( !isset($remove_types[$type]) ){
    199                                 continue;
    200                         }
    201 
    202                         $full_path = self::$cache_dir . $file;
    203                         $mtime = filemtime($full_path);
    204 
    205                         // don't delete if it's a relatively new file
    206                         if( $mtime > $check_time ){
    207                                 continue;
    208                         }
    209 
    210                         unlink($full_path);
    211                 }
    212 
    213         }
    214 
     29class Cache
     30{
     31
     32    const CACHE_VERSION = 0;
     33
     34
     35    // directory used for storing data
     36    public static $cache_dir = false;
     37
     38    // prefix for the storing data
     39    public static $prefix = 'scssphp_';
     40
     41    public static $force_refresh = false;
     42
     43    // specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
     44    public static $gc_lifetime = 604800;
     45
     46
     47    /**
     48     * Constructor
     49     */
     50    public function __construct($options)
     51    {
     52        //check $cache_dir
     53        if (isset($options['cache_dir'])) {
     54            self::$cache_dir = $options['cache_dir'];
     55        }
     56
     57        if (empty(self::$cache_dir)) {
     58            throw new Exception('cache_dir not set');
     59        }
     60
     61        if (isset($options['prefix'])) {
     62            self::$prefix = $options['prefix'];
     63        }
     64
     65        if (empty(self::$prefix)) {
     66            throw new Exception('prefix not set');
     67        }
     68
     69        if (isset($options['force_refresh'])) {
     70            self::$force_refresh = $options['force_refresh'];
     71        }
     72
     73        self::checkCacheDir();
     74    }
     75
     76
     77    /**
     78     * Generic get
     79     *    Get the previous computed result of $what, affected by $options
     80     *
     81     * @param string $operation
     82     *   parse, compile?
     83     * @param $what
     84     *  content key (filename to be treated?)
     85     * @param array $options
     86     *  any option that affect the operation result on the content
     87     * @param int $last_modified
     88     * @return mixed
     89     * @throws Exception
     90     */
     91    public function getCache($operation, $what, $options = array(), $last_modified = null)
     92    {
     93
     94        $fileCache = self::$cache_dir . self::cacheName($operation, $what, $options);
     95
     96        if (! self::$force_refresh
     97          and file_exists($fileCache)) {
     98            $cache_time = filemtime($fileCache);
     99            if ((is_null($last_modified) or $cache_time > $last_modified)
     100              and $cache_time + self::$gc_lifetime > time()) {
     101                $c = file_get_contents($fileCache);
     102                $c = unserialize($c);
     103                if (is_array($c) and isset($c['value'])) {
     104                    return $c['value'];
     105                }
     106            }
     107        }
     108
     109        return null;
     110    }
     111
     112    public function setCache($operation, $what, $value, $options = array())
     113    {
     114        $fileCache = self::$cache_dir . self::cacheName($operation, $what, $options);
     115
     116        $c = array('value' => $value);
     117        $c = serialize($c);
     118        file_put_contents($fileCache, $c);
     119    }
     120
     121
     122    private static function cacheName($operation, $what, $options = array())
     123    {
     124
     125        $t = array(
     126          'version' => self::CACHE_VERSION,
     127          'operation' => $operation,
     128          'what' => $what,
     129          'options' => $options
     130        );
     131
     132        $t = self::$prefix
     133          . sha1(json_encode($t))
     134          . ".$operation"
     135          . ".scsscache";
     136
     137        return $t;
     138    }
     139
     140
     141    public static function checkCacheDir()
     142    {
     143
     144        self::$cache_dir = str_replace('\\', '/', self::$cache_dir);
     145        self::$cache_dir = rtrim(self::$cache_dir, '/') . '/';
     146
     147        if (! file_exists(self::$cache_dir)) {
     148            if (! mkdir(self::$cache_dir)) {
     149                throw new Exception('Cache directory couldn\'t be created: ' . self::$cache_dir);
     150            }
     151        } elseif (! is_dir(self::$cache_dir)) {
     152            throw new Exception('Cache directory doesn\'t exist: ' . self::$cache_dir);
     153        } elseif (! is_writable(self::$cache_dir)) {
     154            throw new Exception('Cache directory isn\'t writable: ' . self::$cache_dir);
     155        }
     156    }
     157
     158    /**
     159     * Delete unused cached files
     160     *
     161     */
     162    public static function cleanCache()
     163    {
     164        static $clean = false;
     165
     166
     167        if ($clean || empty(self::$cache_dir)) {
     168            return;
     169        }
     170
     171        $clean = true;
     172
     173        // only remove files with extensions created by SCSSPHP Cache
     174        // css files removed based on the list files
     175        $remove_types = array('scsscache' => 1);
     176
     177        $files = scandir(self::$cache_dir);
     178        if (! $files) {
     179            return;
     180        }
     181
     182        $check_time = time() - self::$gc_lifetime;
     183        foreach ($files as $file) {
     184            // don't delete if the file wasn't created with SCSSPHP Cache
     185            if (strpos($file, self::$prefix) !== 0) {
     186                continue;
     187            }
     188
     189            $parts = explode('.', $file);
     190            $type = array_pop($parts);
     191
     192
     193            if (! isset($remove_types[$type])) {
     194                continue;
     195            }
     196
     197            $full_path = self::$cache_dir . $file;
     198            $mtime = filemtime($full_path);
     199
     200            // don't delete if it's a relatively new file
     201            if ($mtime > $check_time) {
     202                continue;
     203            }
     204
     205            unlink($full_path);
     206        }
     207    }
    215208}
  • _plugins_/scssphp/trunk/lib/scssphp/src/Compiler.php

    r114986 r115043  
    1313
    1414use Leafo\ScssPhp\Base\Range;
    15 use Leafo\ScssPhp\Block;
    1615use Leafo\ScssPhp\Cache;
    17 use Leafo\ScssPhp\Colors;
    1816use Leafo\ScssPhp\Compiler\Environment;
    1917use Leafo\ScssPhp\Exception\CompilerException;
    2018use Leafo\ScssPhp\Formatter\OutputBlock;
    21 use Leafo\ScssPhp\Node;
    2219use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
    23 use Leafo\ScssPhp\Type;
    24 use Leafo\ScssPhp\Parser;
    25 use Leafo\ScssPhp\Util;
    2620
    2721/**
     
    149143    protected $cache;
    150144
    151     private $indentLevel;
    152     private $commentsSeen;
    153     private $extends;
    154     private $extendsMap;
    155     private $parsedFiles;
    156     private $parser;
    157     private $sourceIndex;
    158     private $sourceLine;
    159     private $sourceColumn;
    160     private $stderr;
    161     private $shouldEvaluate;
    162     private $ignoreErrors;
     145    protected $indentLevel;
     146    protected $commentsSeen;
     147    protected $extends;
     148    protected $extendsMap;
     149    protected $parsedFiles;
     150    protected $parser;
     151    protected $sourceIndex;
     152    protected $sourceLine;
     153    protected $sourceColumn;
     154    protected $stderr;
     155    protected $shouldEvaluate;
     156    protected $ignoreErrors;
    163157
    164158    /**
     
    171165
    172166        if ($cache_options) {
    173           $this->cache = new Cache($cache_options);
    174         }
    175     }
    176 
    177     public function getCompileOptions() {
     167            $this->cache = new Cache($cache_options);
     168        }
     169    }
     170
     171    public function getCompileOptions()
     172    {
    178173        $options = array(
    179174            'importPaths' => $this->importPaths,
     
    207202                and isset($cache['dependencies'])
    208203                and isset($cache['out']) ) {
    209 
    210204                // check if any dependency file changed before accepting the cache
    211205                foreach ($cache['dependencies'] as $file => $mtime) {
     
    515509
    516510                    for ($l = count($tempReplacement) - 1; $l >= 0; $l--) {
    517                         $slice = $tempReplacement[$l];
     511                        $slice = [];
     512                        foreach ($tempReplacement[$l] as $chunk) {
     513                            if (!in_array($chunk, $slice)) {
     514                                $slice[] = $chunk;
     515                            }
     516                        }
    518517                        array_unshift($replacement, $slice);
    519518
     
    842841            $wrapped->parent       = $block;
    843842            $wrapped->children     = $block->children;
     843            $wrapped->selfParent   = $block->selfParent;
    844844
    845845            $block->children = [[Type::T_BLOCK, $wrapped]];
     
    848848        $this->env = $this->filterWithout($envs, $without);
    849849        $newBlock  = $this->spliceTree($envs, $block, $without);
    850         if (isset($block->atrootParent))
    851             $newBlock[1]->atrootParent = $block->atrootParent;
    852850
    853851        $saveScope   = $this->scope;
     
    871869     * @return array
    872870     */
    873     private function spliceTree($envs, Block $block, $without)
     871    protected function spliceTree($envs, Block $block, $without)
    874872    {
    875873        $newBlock = null;
     
    936934        }
    937935
     936        $newBlock->selfParent   = $block->selfParent;
    938937        $type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK;
    939938
     
    948947     * @return integer
    949948     */
    950     private function compileWith($with)
     949    protected function compileWith($with)
    951950    {
    952951        static $mapping = [
     
    999998     * @return \Leafo\ScssPhp\Compiler\Environment
    1000999     */
    1001     private function filterWithout($envs, $without)
     1000    protected function filterWithout($envs, $without)
    10021001    {
    10031002        $filtered = [];
     
    10221021     * @return boolean
    10231022     */
    1024     private function isWithout($without, Block $block)
     1023    protected function isWithout($without, Block $block)
    10251024    {
    10261025        if ((($without & static::WITH_RULE) && isset($block->selectors)) ||
     
    11371136
    11381137        if (count($block->children)) {
    1139             $out->selectors = $this->multiplySelectors($env);
     1138            $out->selectors = $this->multiplySelectors($env, $block->selfParent);
    11401139
    11411140            $this->compileChildrenNoReturn($block->children, $out);
     
    13471346        foreach ($selector as $parts) {
    13481347            foreach ($parts as $part) {
    1349                 if (is_array($part)) {
    1350                     return false;
    1351                 }
    13521348                if (strlen($part) && '%' === $part[0]) {
    13531349                    return true;
     
    13651361     * @param \Leafo\ScssPhp\Formatter\OutputBlock $out
    13661362     *
    1367      * @return array
     1363     * @return array|null
    13681364     */
    13691365    protected function compileChildren($stms, OutputBlock $out)
     
    13761372            }
    13771373        }
     1374        return null;
    13781375    }
    13791376
     
    16321629        switch ($child[0]) {
    16331630            case Type::T_SCSSPHP_IMPORT_ONCE:
    1634                 list(, $rawPath) = $child;
    1635 
    1636                 $rawPath = $this->reduce($rawPath);
     1631                $rawPath = $this->reduce($child[1]);
    16371632
    16381633                if (! $this->compileImport($rawPath, $out, true)) {
     
    16421637
    16431638            case Type::T_IMPORT:
    1644                 list(, $rawPath) = $child;
    1645 
    1646                 $rawPath = $this->reduce($rawPath);
     1639                $rawPath = $this->reduce($child[1]);
    16471640
    16481641                if (! $this->compileImport($rawPath, $out)) {
     
    16841677
    16851678                    if ($isGlobal) {
    1686                         $this->set($name[1], $this->reduce($value), false, $this->rootEnv);
     1679                        $this->set($name[1], $this->reduce($value), false, $this->rootEnv, $value);
    16871680                        break;
    16881681                    }
     
    16931686
    16941687                    if (! $isDefault || $shouldSet) {
    1695                         $this->set($name[1], $this->reduce($value));
     1688                        $this->set($name[1], $this->reduce($value), false, null, $value);
    16961689                    }
    16971690                    break;
     
    17021695                // handle shorthand syntax: size / line-height
    17031696                if ($compiledName === 'font') {
    1704                     if ($value[0] === Type::T_EXPRESSION && $value[1] === '/') {
    1705                         $value = $this->expToString($value);
    1706                     } elseif ($value[0] === Type::T_LIST) {
    1707                         foreach ($value[2] as &$item) {
     1697                    if ($value[0] === Type::T_VARIABLE) {
     1698                        // if the font value comes from variable, the content is already reduced (which means formulars where already calculated)
     1699                        // so we need the original unreduced value
     1700                        $value = $this->get($value[1], true, null, true);
     1701                    }
     1702
     1703                    $fontValue=&$value;
     1704                    if ($value[0] === Type::T_LIST && $value[1]==',') {
     1705                        // this is the case if more than one font is given: example: "font: 400 1em/1.3 arial,helvetica"
     1706                        // we need to handle the first list element
     1707                        $fontValue=&$value[2][0];
     1708                    }
     1709
     1710                    if ($fontValue[0] === Type::T_EXPRESSION && $fontValue[1] === '/') {
     1711                        $fontValue = $this->expToString($fontValue);
     1712                    } elseif ($fontValue[0] === Type::T_LIST) {
     1713                        foreach ($fontValue[2] as &$item) {
    17081714                            if ($item[0] === Type::T_EXPRESSION && $item[1] === '/') {
    17091715                                $item = $this->expToString($item);
     
    17481754
    17491755            case Type::T_EXTEND:
    1750                 list(, $selectors) = $child;
    1751 
    1752                 foreach ($selectors as $sel) {
     1756                foreach ($child[1] as $sel) {
    17531757                    $results = $this->evalSelectors([$sel]);
    17541758
     
    19351939                    $this->applyArguments($mixin->args, $argValues);
    19361940                }
    1937                 foreach ($mixin->children as $stm) {
    1938                     if ($stm[0] == Type::T_AT_ROOT) {
    1939                         $stm[1]->atrootParentSelectors = $callingScope->selectors;
    1940                     }
    1941                 }
     1941
    19421942                $this->env->marker = 'mixin';
    19431943
     
    19711971                list(, $value) = $child;
    19721972
     1973                $fname = $this->sourceNames[$this->sourceIndex];
    19731974                $line = $this->sourceLine;
    19741975                $value = $this->compileValue($this->reduce($value, true));
    1975                 fwrite($this->stderr, "Line $line DEBUG: $value\n");
     1976                fwrite($this->stderr, "File $fname on line $line DEBUG: $value\n");
    19761977                break;
    19771978
     
    19791980                list(, $value) = $child;
    19801981
     1982                $fname = $this->sourceNames[$this->sourceIndex];
    19811983                $line = $this->sourceLine;
    19821984                $value = $this->compileValue($this->reduce($value, true));
    1983                 fwrite($this->stderr, "Line $line WARN: $value\n");
     1985                fwrite($this->stderr, "File $fname on line $line WARN: $value\n");
    19841986                break;
    19851987
     
    19871989                list(, $value) = $child;
    19881990
     1991                $fname = $this->sourceNames[$this->sourceIndex];
    19891992                $line = $this->sourceLine;
    19901993                $value = $this->compileValue($this->reduce($value, true));
    1991                 $this->throwError("Line $line ERROR: $value\n");
     1994                $this->throwError("File $fname on line $line ERROR: $value\n");
    19921995                break;
    19931996
     
    20652068            case Type::T_EXPRESSION:
    20662069                if ($value[1] === '/') {
    2067                     return $this->shouldEval($value[2], $value[3]);
     2070                    return $this->shouldEval($value[2]);
    20682071                }
    20692072
     
    20872090    protected function reduce($value, $inExp = false)
    20882091    {
    2089         list($type) = $value;
    2090 
    2091         switch ($type) {
     2092
     2093        switch ($value[0]) {
    20922094            case Type::T_EXPRESSION:
    20932095                list(, $op, $left, $right, $inParens) = $value;
     
    22222224
    22232225            case Type::T_VARIABLE:
    2224                 list(, $name) = $value;
    2225 
    2226                 return $this->reduce($this->get($name));
     2226                return $this->reduce($this->get($value[1]));
    22272227
    22282228            case Type::T_LIST:
     
    22592259
    22602260            case Type::T_FUNCTION_CALL:
    2261                 list(, $name, $argValues) = $value;
    2262 
    2263                 return $this->fncall($name, $argValues);
     2261                return $this->fncall($value[1], $value[2]);
    22642262
    22652263            default:
     
    22762274     * @return array|null
    22772275     */
    2278     private function fncall($name, $argValues)
     2276    protected function fncall($name, $argValues)
    22792277    {
    22802278        // SCSS @function
     
    23222320    {
    23232321        $value = $this->coerceForExpression($this->reduce($value));
    2324         list($type) = $value;
    2325 
    2326         switch ($type) {
     2322
     2323        switch ($value[0]) {
    23272324            case Type::T_LIST:
    23282325                $value = $this->extractInterpolation($value);
     
    23392336
    23402337            case Type::T_STRING:
    2341                 return [$type, '"', [$this->compileStringContent($value)]];
     2338                return [$value[0], '"', [$this->compileStringContent($value)]];
    23422339
    23432340            case Type::T_NUMBER:
     
    24272424     * @param array $right
    24282425     *
    2429      * @return array
     2426     * @return array|null
    24302427     */
    24312428    protected function opAdd($left, $right)
     
    24502447            return $strRight;
    24512448        }
     2449        return null;
    24522450    }
    24532451
     
    24592457     * @param boolean $shouldEval
    24602458     *
    2461      * @return array
     2459     * @return array|null
    24622460     */
    24632461    protected function opAnd($left, $right, $shouldEval)
    24642462    {
    24652463        if (! $shouldEval) {
    2466             return;
     2464            return null;
    24672465        }
    24682466
     
    24812479     * @param boolean $shouldEval
    24822480     *
    2483      * @return array
     2481     * @return array|null
    24842482     */
    24852483    protected function opOr($left, $right, $shouldEval)
    24862484    {
    24872485        if (! $shouldEval) {
    2488             return;
     2486            return null;
    24892487        }
    24902488
     
    27442742        $value = $this->reduce($value);
    27452743
    2746         list($type) = $value;
    2747 
    2748         switch ($type) {
     2744        switch ($value[0]) {
    27492745            case Type::T_KEYWORD:
    27502746                return $value[1];
     
    28412837
    28422838            case Type::T_INTERPOLATE:
    2843                 // raw parse node
    2844                 list(, $exp) = $value;
    2845 
    28462839                // strip quotes if it's a string
    2847                 $reduced = $this->reduce($exp);
     2840                $reduced = $this->reduce($value[1]);
    28482841
    28492842                switch ($reduced[0]) {
     
    28952888
    28962889            default:
    2897                 $this->throwError("unknown value type: $type");
     2890                $this->throwError("unknown value type: $value[0]");
    28982891        }
    28992892    }
     
    29602953     *
    29612954     * @param \Leafo\ScssPhp\Compiler\Environment $env
     2955     * @param Leafo\ScssPhp\Block $selfParent
    29622956     *
    29632957     * @return array
    29642958     */
    2965     protected function multiplySelectors(Environment $env)
     2959    protected function multiplySelectors(Environment $env, $selfParent = null)
    29662960    {
    29672961        $envs            = $this->compactEnv($env);
     
    29692963        $parentSelectors = [[]];
    29702964
     2965        $selfParentSelectors = null;
     2966        if (!is_null($selfParent) and $selfParent->selectors) {
     2967            $selfParentSelectors = $this->evalSelectors($selfParent->selectors);
     2968        }
     2969
    29712970        while ($env = array_pop($envs)) {
    29722971            if (empty($env->selectors)) {
    29732972                continue;
    29742973            }
    2975             if ($env->block->type == Type::T_AT_ROOT) {
    2976                 break;
    2977             }
     2974
    29782975            $selectors = [];
    2979             if (!empty($env->block->parent->atrootParent) && !empty($env->block->parent->atrootParent->selectors)) {
    2980                 $parentSelectors = $env->block->parent->atrootParent->selectors;
    2981             }
    2982             if (!empty($env->parent->parent->block->atrootParentSelectors)) {
    2983                 $parentSelectors = $env->parent->parent->block->atrootParentSelectors;
    2984             }
    29852976
    29862977            foreach ($env->selectors as $selector) {
    29872978                foreach ($parentSelectors as $parent) {
    2988                     $selectors[] = $this->joinSelectors($parent, $selector);
     2979                    $selectors[] = $this->joinSelectors($parent, $selector, $selfParentSelectors);
    29892980                }
    29902981            }
     
    30012992     * @param array $parent
    30022993     * @param array $child
    3003      *
     2994     * @param array $selfParentSelectors
    30042995     * @return array
    30052996     */
    3006     protected function joinSelectors($parent, $child)
     2997    protected function joinSelectors($parent, $child, $selfParentSelectors = null)
    30072998    {
    30082999        $setSelf = false;
     
    30153006                if ($p === static::$selfSelector) {
    30163007                    $setSelf = true;
    3017 
    3018                     foreach ($parent as $i => $parentPart) {
     3008                    if (is_null($selfParentSelectors)) {
     3009                        $selfParentSelectors = $parent;
     3010                    }
     3011                    foreach ($selfParentSelectors as $i => $parentPart) {
    30193012                        if ($i > 0) {
    30203013                            $out[] = $newPart;
     
    30233016
    30243017                        foreach ($parentPart as $pp) {
    3025                             $newPart[] = $pp;
     3018                            $newPart[] = (is_array($pp) ? implode($pp) : $pp);
    30263019                        }
    30273020                    }
     
    30853078     * @return array
    30863079     */
    3087     private function compactEnv(Environment $env)
     3080    protected function compactEnv(Environment $env)
    30883081    {
    30893082        for ($envs = []; $env; $env = $env->parent) {
     
    31013094     * @return \Leafo\ScssPhp\Compiler\Environment
    31023095     */
    3103     private function extractEnv($envs)
     3096    protected function extractEnv($envs)
    31043097    {
    31053098        for ($env = null; $e = array_pop($envs);) {
     
    31563149     * @param boolean                             $shadow
    31573150     * @param \Leafo\ScssPhp\Compiler\Environment $env
    3158      */
    3159     protected function set($name, $value, $shadow = false, Environment $env = null)
     3151     * @param mixed                               $valueUnreduced
     3152     */
     3153    protected function set($name, $value, $shadow = false, Environment $env = null, $valueUnreduced = null)
    31603154    {
    31613155        $name = $this->normalizeName($name);
     
    31663160
    31673161        if ($shadow) {
    3168             $this->setRaw($name, $value, $env);
     3162            $this->setRaw($name, $value, $env, $valueUnreduced);
    31693163        } else {
    3170             $this->setExisting($name, $value, $env);
     3164            $this->setExisting($name, $value, $env, $valueUnreduced);
    31713165        }
    31723166    }
     
    31783172     * @param mixed                               $value
    31793173     * @param \Leafo\ScssPhp\Compiler\Environment $env
    3180      */
    3181     protected function setExisting($name, $value, Environment $env)
     3174     * @param mixed                               $valueUnreduced
     3175     */
     3176    protected function setExisting($name, $value, Environment $env, $valueUnreduced = null)
    31823177    {
    31833178        $storeEnv = $env;
     
    32043199
    32053200        $env->store[$name] = $value;
     3201        if ($valueUnreduced) {
     3202            $env->storeUnreduced[$name] = $valueUnreduced;
     3203        }
    32063204    }
    32073205
     
    32123210     * @param mixed                               $value
    32133211     * @param \Leafo\ScssPhp\Compiler\Environment $env
    3214      */
    3215     protected function setRaw($name, $value, Environment $env)
     3212     * @param mixed                               $valueUnreduced
     3213     */
     3214    protected function setRaw($name, $value, Environment $env, $valueUnreduced = null)
    32163215    {
    32173216        $env->store[$name] = $value;
     3217        if ($valueUnreduced) {
     3218            $env->storeUnreduced[$name] = $valueUnreduced;
     3219        }
    32183220    }
    32193221
     
    32263228     * @param boolean                             $shouldThrow
    32273229     * @param \Leafo\ScssPhp\Compiler\Environment $env
    3228      *
    3229      * @return mixed
    3230      */
    3231     public function get($name, $shouldThrow = true, Environment $env = null)
     3230     * @param boolean                             $unreduced
     3231     *
     3232     * @return mixed|null
     3233     */
     3234    public function get($name, $shouldThrow = true, Environment $env = null, $unreduced = false)
    32323235    {
    32333236        $normalizedName = $this->normalizeName($name);
     
    32433246        for (;;) {
    32443247            if (array_key_exists($normalizedName, $env->store)) {
     3248                if ($unreduced && isset($env->storeUnreduced[$normalizedName])) {
     3249                    return $env->storeUnreduced[$normalizedName];
     3250                }
    32453251                return $env->store[$normalizedName];
    32463252            }
     
    32693275
    32703276        // found nothing
     3277        return null;
    32713278    }
    32723279
     
    35503557                // check urls for normal import paths
    35513558                foreach ($urls as $full) {
    3552                     $full = $dir
    3553                         . (! empty($dir) && substr($dir, -1) !== '/' ? '/' : '')
    3554                         . $full;
     3559                    $separator = (
     3560                        !empty($dir) &&
     3561                        substr($dir, -1) !== '/' &&
     3562                        substr($full, 0, 1) !== '/'
     3563                    ) ? '/' : '';
     3564                    $full = $dir . $separator . $full;
    35553565
    35563566                    if ($this->fileExists($file = $full . '.scss') ||
     
    35973607    {
    35983608        $this->ignoreErrors = $ignoreErrors;
     3609        return $this;
    35993610    }
    36003611
     
    36193630
    36203631        $line = $this->sourceLine;
    3621         $file = $this->sourceNames[$this->sourceIndex];
    3622 
    3623         $msg = "$msg: line: $line file: $file";
     3632        $loc = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] . " on line $line" : "line: $line";
     3633        $msg = "$msg: $loc";
    36243634
    36253635        throw new CompilerException($msg);
     
    39353945     * @return array|\Leafo\ScssPhp\Node\Number
    39363946     */
    3937     private function coerceValue($value)
     3947    protected function coerceValue($value)
    39383948    {
    39393949        if (is_array($value) || $value instanceof \ArrayAccess) {
     
    41374147
    41384148        if ($value[0] !== Type::T_MAP) {
    4139             $this->throwError('expecting map');
     4149            $this->throwError('expecting map, %s received', $value[0]);
    41404150        }
    41414151
     
    41574167    {
    41584168        if ($value[0] !== Type::T_LIST) {
    4159             $this->throwError('expecting list');
     4169            $this->throwError('expecting list, %s received', $value[0]);
    41604170        }
    41614171
     
    41804190        }
    41814191
    4182         $this->throwError('expecting color');
     4192        $this->throwError('expecting color, %s received', $value[0]);
    41834193    }
    41844194
     
    41974207    {
    41984208        if ($value[0] !== Type::T_NUMBER) {
    4199             $this->throwError('expecting number');
     4209            $this->throwError('expecting number, %s received', $value[0]);
    42004210        }
    42014211
     
    42744284     * @return float
    42754285     */
    4276     private function hueToRGB($m1, $m2, $h)
     4286    protected function hueToRGB($m1, $m2, $h)
    42774287    {
    42784288        if ($h < 0) {
     
    49965006            $this->throwError('Invalid argument for "n"');
    49975007
    4998             return;
     5008            return null;
    49995009        }
    50005010
     
    52345244            $this->throwError('Invalid argument(s) for "comparable"');
    52355245
    5236             return;
     5246            return null;
    52375247        }
    52385248
     
    54145424                $this->throwError("limit must be greater than or equal to 1");
    54155425
    5416                 return;
     5426                return null;
    54175427            }
    54185428
  • _plugins_/scssphp/trunk/lib/scssphp/src/Compiler/Environment.php

    r108871 r115043  
    3535
    3636    /**
     37     * @var array
     38     */
     39    public $storeUnreduced;
     40
     41    /**
    3742     * @var integer
    3843     */
  • _plugins_/scssphp/trunk/lib/scssphp/src/Formatter/Compressed.php

    r108871 r115043  
    1313
    1414use Leafo\ScssPhp\Formatter;
    15 use Leafo\ScssPhp\Formatter\OutputBlock;
    1615
    1716/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/Formatter/Crunched.php

    r108871 r115043  
    1313
    1414use Leafo\ScssPhp\Formatter;
    15 use Leafo\ScssPhp\Formatter\OutputBlock;
    1615
    1716/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/Formatter/Debug.php

    r108871 r115043  
    1313
    1414use Leafo\ScssPhp\Formatter;
    15 use Leafo\ScssPhp\Formatter\OutputBlock;
    1615
    1716/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/Formatter/Expanded.php

    r108871 r115043  
    1313
    1414use Leafo\ScssPhp\Formatter;
    15 use Leafo\ScssPhp\Formatter\OutputBlock;
    1615
    1716/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/Formatter/Nested.php

    r108871 r115043  
    1313
    1414use Leafo\ScssPhp\Formatter;
    15 use Leafo\ScssPhp\Formatter\OutputBlock;
    1615
    1716/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/Parser.php

    r114936 r115043  
    1212namespace Leafo\ScssPhp;
    1313
    14 use Leafo\ScssPhp\Block;
    15 use Leafo\ScssPhp\Compiler;
    1614use Leafo\ScssPhp\Exception\ParserException;
    17 use Leafo\ScssPhp\Node;
    18 use Leafo\ScssPhp\Type;
    1915
    2016/**
     
    7975     * @param Cache $cache
    8076     */
    81     public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', $cache=null)
     77    public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', $cache = null)
    8278    {
    8379        $this->sourceName       = $sourceName ?: '(stdin)';
     
    296292     * avoid this, Compiler::seek() is used to remember and set buffer positions.
    297293     *
    298      * Before parsing a chain, use $s = $this->seek() to remember the current
     294     * Before parsing a chain, use $s = $this->count to remember the current
    299295     * position into $s. Then if a chain fails, use $this->seek($s) to
    300296     * go back where we started.
     
    304300    protected function parseChunk()
    305301    {
    306         $s = $this->seek();
     302        $s = $this->count;
    307303
    308304        // the directives
    309305        if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] === '@') {
    310             if ($this->literal('@at-root') &&
     306            if ($this->literal('@at-root', 8) &&
    311307                ($this->selectors($selector) || true) &&
    312308                ($this->map($with) || true) &&
    313                 $this->literal('{')
     309                $this->matchChar('{')
    314310            ) {
    315311                $atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
     
    322318            $this->seek($s);
    323319
    324             if ($this->literal('@media') && $this->mediaQueryList($mediaQueryList) && $this->literal('{')) {
     320            if ($this->literal('@media', 6) && $this->mediaQueryList($mediaQueryList) && $this->matchChar('{')) {
    325321                $media = $this->pushSpecialBlock(Type::T_MEDIA, $s);
    326322                $media->queryList = $mediaQueryList[2];
     
    331327            $this->seek($s);
    332328
    333             if ($this->literal('@mixin') &&
     329            if ($this->literal('@mixin', 6) &&
    334330                $this->keyword($mixinName) &&
    335331                ($this->argumentDef($args) || true) &&
    336                 $this->literal('{')
     332                $this->matchChar('{')
    337333            ) {
    338334                $mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s);
     
    345341            $this->seek($s);
    346342
    347             if ($this->literal('@include') &&
     343            if ($this->literal('@include', 8) &&
    348344                $this->keyword($mixinName) &&
    349                 ($this->literal('(') &&
     345                ($this->matchChar('(') &&
    350346                    ($this->argValues($argValues) || true) &&
    351                     $this->literal(')') || true) &&
     347                    $this->matchChar(')') || true) &&
    352348                ($this->end() ||
    353                     $this->literal('{') && $hasBlock = true)
     349                    $this->matchChar('{') && $hasBlock = true)
    354350            ) {
    355351                $child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null];
     
    367363            $this->seek($s);
    368364
    369             if ($this->literal('@scssphp-import-once') &&
     365            if ($this->literal('@scssphp-import-once', 20) &&
    370366                $this->valueList($importPath) &&
    371367                $this->end()
     
    378374            $this->seek($s);
    379375
    380             if ($this->literal('@import') &&
     376            if ($this->literal('@import', 7) &&
    381377                $this->valueList($importPath) &&
    382378                $this->end()
     
    389385            $this->seek($s);
    390386
    391             if ($this->literal('@import') &&
     387            if ($this->literal('@import', 7) &&
    392388                $this->url($importPath) &&
    393389                $this->end()
     
    400396            $this->seek($s);
    401397
    402             if ($this->literal('@extend') &&
     398            if ($this->literal('@extend', 7) &&
    403399                $this->selectors($selectors) &&
    404400                $this->end()
     
    413409            $this->seek($s);
    414410
    415             if ($this->literal('@function') &&
     411            if ($this->literal('@function', 9) &&
    416412                $this->keyword($fnName) &&
    417413                $this->argumentDef($args) &&
    418                 $this->literal('{')
     414                $this->matchChar('{')
    419415            ) {
    420416                $func = $this->pushSpecialBlock(Type::T_FUNCTION, $s);
     
    427423            $this->seek($s);
    428424
    429             if ($this->literal('@break') && $this->end()) {
     425            if ($this->literal('@break', 6) && $this->end()) {
    430426                $this->append([Type::T_BREAK], $s);
    431427
     
    435431            $this->seek($s);
    436432
    437             if ($this->literal('@continue') && $this->end()) {
     433            if ($this->literal('@continue', 9) && $this->end()) {
    438434                $this->append([Type::T_CONTINUE], $s);
    439435
     
    444440
    445441
    446             if ($this->literal('@return') && ($this->valueList($retVal) || true) && $this->end()) {
     442            if ($this->literal('@return', 7) && ($this->valueList($retVal) || true) && $this->end()) {
    447443                $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s);
    448444
     
    452448            $this->seek($s);
    453449
    454             if ($this->literal('@each') &&
     450            if ($this->literal('@each', 5) &&
    455451                $this->genericList($varNames, 'variable', ',', false) &&
    456                 $this->literal('in') &&
     452                $this->literal('in', 2) &&
    457453                $this->valueList($list) &&
    458                 $this->literal('{')
     454                $this->matchChar('{')
    459455            ) {
    460456                $each = $this->pushSpecialBlock(Type::T_EACH, $s);
     
    471467            $this->seek($s);
    472468
    473             if ($this->literal('@while') &&
     469            if ($this->literal('@while', 6) &&
    474470                $this->expression($cond) &&
    475                 $this->literal('{')
     471                $this->matchChar('{')
    476472            ) {
    477473                $while = $this->pushSpecialBlock(Type::T_WHILE, $s);
     
    483479            $this->seek($s);
    484480
    485             if ($this->literal('@for') &&
     481            if ($this->literal('@for', 4) &&
    486482                $this->variable($varName) &&
    487                 $this->literal('from') &&
     483                $this->literal('from', 4) &&
    488484                $this->expression($start) &&
    489                 ($this->literal('through') ||
    490                     ($forUntil = true && $this->literal('to'))) &&
     485                ($this->literal('through', 7) ||
     486                    ($forUntil = true && $this->literal('to', 2))) &&
    491487                $this->expression($end) &&
    492                 $this->literal('{')
     488                $this->matchChar('{')
    493489            ) {
    494490                $for = $this->pushSpecialBlock(Type::T_FOR, $s);
     
    503499            $this->seek($s);
    504500
    505             if ($this->literal('@if') && $this->valueList($cond) && $this->literal('{')) {
     501            if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{')) {
    506502                $if = $this->pushSpecialBlock(Type::T_IF, $s);
    507503                $if->cond = $cond;
     
    513509            $this->seek($s);
    514510
    515             if ($this->literal('@debug') &&
     511            if ($this->literal('@debug', 6) &&
    516512                $this->valueList($value) &&
    517513                $this->end()
     
    524520            $this->seek($s);
    525521
    526             if ($this->literal('@warn') &&
     522            if ($this->literal('@warn', 5) &&
    527523                $this->valueList($value) &&
    528524                $this->end()
     
    535531            $this->seek($s);
    536532
    537             if ($this->literal('@error') &&
     533            if ($this->literal('@error', 6) &&
    538534                $this->valueList($value) &&
    539535                $this->end()
     
    546542            $this->seek($s);
    547543
    548             if ($this->literal('@content') && $this->end()) {
     544            if ($this->literal('@content', 8) && $this->end()) {
    549545                $this->append([Type::T_MIXIN_CONTENT], $s);
    550546
     
    559555                list(, $if) = $last;
    560556
    561                 if ($this->literal('@else')) {
    562                     if ($this->literal('{')) {
     557                if ($this->literal('@else', 5)) {
     558                    if ($this->matchChar('{')) {
    563559                        $else = $this->pushSpecialBlock(Type::T_ELSE, $s);
    564                     } elseif ($this->literal('if') && $this->valueList($cond) && $this->literal('{')) {
     560                    } elseif ($this->literal('if', 2) && $this->valueList($cond) && $this->matchChar('{')) {
    565561                        $else = $this->pushSpecialBlock(Type::T_ELSEIF, $s);
    566562                        $else->cond = $cond;
     
    579575
    580576            // only retain the first @charset directive encountered
    581             if ($this->literal('@charset') &&
     577            if ($this->literal('@charset', 8) &&
    582578                $this->valueList($charset) &&
    583579                $this->end()
     
    601597
    602598            // doesn't match built in directive, do generic one
    603             if ($this->literal('@', false) &&
     599            if ($this->matchChar('@', false) &&
    604600                $this->keyword($dirName) &&
    605601                ($this->variable($dirValue) || $this->openString('{', $dirValue) || true) &&
    606                 $this->literal('{')
     602                $this->matchChar('{')
    607603            ) {
    608604                if ($dirName === 'media') {
     
    628624        // captures most properties before having to parse a selector
    629625        if ($this->keyword($name, false) &&
    630             $this->literal(': ') &&
     626            $this->literal(': ', 2) &&
    631627            $this->valueList($value) &&
    632628            $this->end()
     
    642638        // variable assigns
    643639        if ($this->variable($name) &&
    644             $this->literal(':') &&
     640            $this->matchChar(':') &&
    645641            $this->valueList($value) &&
    646642            $this->end()
     
    656652
    657653        // misc
    658         if ($this->literal('-->')) {
     654        if ($this->literal('-->', 3)) {
    659655            return true;
    660656        }
    661657
    662658        // opening css block
    663         if ($this->selectors($selectors) && $this->literal('{')) {
     659        if ($this->selectors($selectors) && $this->matchChar('{')) {
    664660            $this->pushBlock($selectors, $s);
    665661
     
    670666
    671667        // property assign, or nested assign
    672         if ($this->propertyName($name) && $this->literal(':')) {
     668        if ($this->propertyName($name) && $this->matchChar(':')) {
    673669            $foundSomething = false;
    674670
     
    678674            }
    679675
    680             if ($this->literal('{')) {
     676            if ($this->matchChar('{')) {
    681677                $propBlock = $this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s);
    682678                $propBlock->prefix = $name;
     
    694690
    695691        // closing a block
    696         if ($this->literal('}')) {
     692        if ($this->matchChar('}')) {
    697693            $block = $this->popBlock();
    698694
     
    711707
    712708        // extra stuff
    713         if ($this->literal(';') ||
    714             $this->literal('<!--')
     709        if ($this->matchChar(';') ||
     710            $this->literal('<!--', 4)
    715711        ) {
    716712            return true;
     
    740736        $b->comments     = [];
    741737        $b->parent       = $this->env;
    742         $b->atrootParent = $this->env;
    743738
    744739        if (! $this->env) {
     
    788783            $this->throwParseError('unexpected }');
    789784        }
    790 //        if ($block->type == Type::T_AT_ROOT || $block->type == Type::T_MIXIN || $block->type == Type::T_INCLUDE) {
    791 //            $block->atrootParent = $block->parent;
    792 //        }
     785
     786        if ($block->type == Type::T_AT_ROOT) {
     787            // keeps the parent in case of self selector &
     788            $block->selfParent = $block->parent;
     789        }
     790
    793791        $this->env = $block->parent;
    794792        unset($block->parent);
    795793
    796794        $comments = $block->comments;
    797         if (count($comments)) {
     795        if ($comments) {
    798796            $this->env->comments = $comments;
    799797            unset($block->comments);
     
    831829     * @return integer
    832830     */
    833     protected function seek($where = null)
    834     {
    835         if ($where === null) {
    836             return $this->count;
    837         }
    838 
     831    protected function seek($where)
     832    {
    839833        $this->count = $where;
    840 
    841         return true;
    842834    }
    843835
     
    894886    protected function match($regex, &$out, $eatWhitespace = null)
    895887    {
     888
     889        $r = '/' . $regex . '/' . $this->patternModifiers;
     890
     891        if (! preg_match($r, $this->buffer, $out, null, $this->count)) {
     892            return false;
     893        }
     894
     895        $this->count += strlen($out[0]);
     896
    896897        if (! isset($eatWhitespace)) {
    897898            $eatWhitespace = $this->eatWhiteDefault;
    898899        }
    899900
    900         $r = '/' . $regex . '/' . $this->patternModifiers;
    901 
    902         if (preg_match($r, $this->buffer, $out, null, $this->count)) {
    903             $this->count += strlen($out[0]);
    904 
    905             if ($eatWhitespace) {
    906                 $this->whitespace();
    907             }
    908 
    909             return true;
    910         }
    911 
    912         return false;
    913     }
    914 
    915     /**
    916      * Match literal string
    917      *
    918      * @param string  $what
     901        if ($eatWhitespace) {
     902            $this->whitespace();
     903        }
     904
     905        return true;
     906    }
     907
     908
     909    /**
     910     * Match a single string
     911     *
     912     * @param string  $char
    919913     * @param boolean $eatWhitespace
    920914     *
    921915     * @return boolean
    922916     */
    923     protected function literal($what, $eatWhitespace = null)
    924     {
     917    protected function matchChar($char, $eatWhitespace = null)
     918    {
     919
     920        if (! isset($this->buffer[$this->count]) || $this->buffer[$this->count] !== $char) {
     921            return false;
     922        }
     923
     924        $this->count++;
     925
    925926        if (! isset($eatWhitespace)) {
    926927            $eatWhitespace = $this->eatWhiteDefault;
    927928        }
    928929
    929         $len = strlen($what);
    930 
    931         if (strcasecmp(substr($this->buffer, $this->count, $len), $what) === 0) {
    932             $this->count += $len;
    933 
    934             if ($eatWhitespace) {
    935                 $this->whitespace();
    936             }
    937 
    938             return true;
    939         }
    940 
    941         return false;
    942     }
     930        if ($eatWhitespace) {
     931            $this->whitespace();
     932        }
     933        return true;
     934    }
     935
     936
     937    /**
     938     * Match literal string
     939     *
     940     * @param string  $what
     941     * @param integer $len
     942     * @param boolean $eatWhitespace
     943     *
     944     * @return boolean
     945     */
     946    protected function literal($what, $len, $eatWhitespace = null)
     947    {
     948
     949        if (strcasecmp(substr($this->buffer, $this->count, $len), $what) !== 0) {
     950            return false;
     951        }
     952
     953        $this->count += $len;
     954
     955        if (! isset($eatWhitespace)) {
     956            $eatWhitespace = $this->eatWhiteDefault;
     957        }
     958
     959        if ($eatWhitespace) {
     960            $this->whitespace();
     961        }
     962        return true;
     963    }
     964
    943965
    944966    /**
     
    9971019        $comments = $this->env->comments;
    9981020
    999         if (count($comments)) {
     1021        if ($comments) {
    10001022            $this->env->children = array_merge($this->env->children, $comments);
    10011023            $this->env->comments = [];
     
    10411063        $parts = [];
    10421064
    1043         if (($this->literal('only') && ($only = true) || $this->literal('not') && ($not = true) || true) &&
     1065        if (($this->literal('only', 4) && ($only = true) || $this->literal('not', 3) && ($not = true) || true) &&
    10441066            $this->mixedKeyword($mediaType)
    10451067        ) {
     
    10681090        }
    10691091
    1070         if (empty($parts) || $this->literal('and')) {
     1092        if (empty($parts) || $this->literal('and', 3)) {
    10711093            $this->genericList($expressions, 'mediaExpression', 'and', false);
    10721094
     
    10901112    protected function mediaExpression(&$out)
    10911113    {
    1092         $s = $this->seek();
     1114        $s = $this->count;
    10931115        $value = null;
    10941116
    1095         if ($this->literal('(') &&
     1117        if ($this->matchChar('(') &&
    10961118            $this->expression($feature) &&
    1097             ($this->literal(':') && $this->expression($value) || true) &&
    1098             $this->literal(')')
     1119            ($this->matchChar(':') && $this->expression($value) || true) &&
     1120            $this->matchChar(')')
    10991121        ) {
    11001122            $out = [Type::T_MEDIA_EXPRESSION, $feature];
     
    11391161    protected function argValue(&$out)
    11401162    {
    1141         $s = $this->seek();
     1163        $s = $this->count;
    11421164
    11431165        $keyword = null;
    11441166
    1145         if (! $this->variable($keyword) || ! $this->literal(':')) {
     1167        if (! $this->variable($keyword) || ! $this->matchChar(':')) {
    11461168            $this->seek($s);
    11471169            $keyword = null;
     
    11501172        if ($this->genericList($value, 'expression')) {
    11511173            $out = [$keyword, $value, false];
    1152             $s = $this->seek();
    1153 
    1154             if ($this->literal('...')) {
     1174            $s = $this->count;
     1175
     1176            if ($this->literal('...', 3)) {
    11551177                $out[2] = true;
    11561178            } else {
     
    12001222    protected function genericList(&$out, $parseItem, $delim = '', $flatten = true)
    12011223    {
    1202         $s = $this->seek();
     1224        $s = $this->count;
    12031225        $items = [];
    1204 
     1226        $value = null;
    12051227        while ($this->$parseItem($value)) {
    12061228            $items[] = $value;
    12071229
    12081230            if ($delim) {
    1209                 if (! $this->literal($delim)) {
     1231                if (! $this->literal($delim, strlen($delim))) {
    12101232                    break;
    12111233                }
     
    12131235        }
    12141236
    1215         if (count($items) === 0) {
     1237        if (!$items) {
    12161238            $this->seek($s);
    12171239
     
    12371259    protected function expression(&$out)
    12381260    {
    1239         $s = $this->seek();
    1240 
    1241         if ($this->literal('(')) {
    1242             if ($this->literal(')')) {
     1261        $s = $this->count;
     1262
     1263        if ($this->matchChar('(')) {
     1264            if ($this->matchChar(')')) {
    12431265                $out = [Type::T_LIST, '', []];
    12441266
     
    12461268            }
    12471269
    1248             if ($this->valueList($out) && $this->literal(')') && $out[0] === Type::T_LIST) {
     1270            if ($this->valueList($out) && $this->matchChar(')') && $out[0] === Type::T_LIST) {
    12491271                return true;
    12501272            }
     
    12801302        $operators = static::$operatorPattern;
    12811303
    1282         $ss = $this->seek();
     1304        $ss = $this->count;
    12831305        $whiteBefore = isset($this->buffer[$this->count - 1]) &&
    12841306            ctype_space($this->buffer[$this->count - 1]);
     
    13091331
    13101332            $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter];
    1311             $ss = $this->seek();
     1333            $ss = $this->count;
    13121334            $whiteBefore = isset($this->buffer[$this->count - 1]) &&
    13131335                ctype_space($this->buffer[$this->count - 1]);
     
    13281350    protected function value(&$out)
    13291351    {
    1330         $s = $this->seek();
    1331 
    1332         if ($this->literal('url(') && $this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m, false)) {
     1352
     1353        if (! isset($this->buffer[$this->count])) {
     1354            return false;
     1355        }
     1356
     1357        $s = $this->count;
     1358        $char = $this->buffer[$this->count];
     1359
     1360        if ($this->literal('url(', 4) && $this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m, false)) {
    13331361            $len = strspn($this->buffer, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=', $this->count);
    13341362
     
    13451373        $this->seek($s);
    13461374
    1347         if ($this->literal('not', false) && $this->whitespace() && $this->value($inner)) {
    1348             $out = [Type::T_UNARY, 'not', $inner, $this->inParens];
    1349 
     1375        // not
     1376        if ($char === 'n' && $this->literal('not', 3, false)) {
     1377            if ($this->whitespace() && $this->value($inner)) {
     1378                $out = [Type::T_UNARY, 'not', $inner, $this->inParens];
     1379                return true;
     1380            }
     1381
     1382            $this->seek($s);
     1383
     1384            if ($this->parenValue($inner)) {
     1385                $out = [Type::T_UNARY, 'not', $inner, $this->inParens];
     1386                return true;
     1387            }
     1388
     1389            $this->seek($s);
     1390        }
     1391
     1392        // addition
     1393        if ($char === '+') {
     1394            $this->count++;
     1395            if ($this->value($inner)) {
     1396                $out = [Type::T_UNARY, '+', $inner, $this->inParens];
     1397                return true;
     1398            }
     1399            $this->count--;
     1400            return false;
     1401        }
     1402
     1403
     1404        // negation
     1405        if ($char === '-') {
     1406            $this->count++;
     1407            if ($this->variable($inner) || $this->unit($inner) || $this->parenValue($inner)) {
     1408                $out = [Type::T_UNARY, '-', $inner, $this->inParens];
     1409                return true;
     1410            }
     1411            $this->count--;
     1412        }
     1413
     1414        // paren
     1415        if ($char === '(' && $this->parenValue($out)) {
    13501416            return true;
    13511417        }
    13521418
    1353         $this->seek($s);
    1354 
    1355         if ($this->literal('not', false) && $this->parenValue($inner)) {
    1356             $out = [Type::T_UNARY, 'not', $inner, $this->inParens];
    1357 
     1419        if ($char === '#') {
     1420            if ($this->interpolation($out) || $this->color($out)) {
     1421                return true;
     1422            }
     1423        }
     1424
     1425        if ($char === '$' && $this->variable($out)) {
    13581426            return true;
    13591427        }
    13601428
    1361         $this->seek($s);
    1362 
    1363         if ($this->literal('+') && $this->value($inner)) {
    1364             $out = [Type::T_UNARY, '+', $inner, $this->inParens];
    1365 
     1429        if ($char === 'p' && $this->progid($out)) {
    13661430            return true;
    13671431        }
    13681432
    1369         $this->seek($s);
    1370 
    1371         // negation
    1372         if ($this->literal('-', false) &&
    1373             ($this->variable($inner) ||
    1374             $this->unit($inner) ||
    1375             $this->parenValue($inner))
    1376         ) {
    1377             $out = [Type::T_UNARY, '-', $inner, $this->inParens];
    1378 
     1433        if (($char === '"' || $char === "'") && $this->string($out)) {
    13791434            return true;
    13801435        }
    13811436
    1382         $this->seek($s);
    1383 
    1384         if ($this->parenValue($out) ||
    1385             $this->interpolation($out) ||
    1386             $this->variable($out) ||
    1387             $this->color($out) ||
    1388             $this->unit($out) ||
    1389             $this->string($out) ||
    1390             $this->func($out) ||
    1391             $this->progid($out)
    1392         ) {
     1437
     1438        if ($this->unit($out)) {
    13931439            return true;
    13941440        }
    13951441
    1396         if ($this->keyword($keyword)) {
     1442        if ($this->keyword($keyword, false)) {
     1443            if ($this->func($keyword, $out)) {
     1444                return true;
     1445            }
     1446
     1447            $this->whitespace();
     1448
    13971449            if ($keyword === 'null') {
    13981450                $out = [Type::T_NULL];
     
    14161468    protected function parenValue(&$out)
    14171469    {
    1418         $s = $this->seek();
     1470        $s = $this->count;
    14191471
    14201472        $inParens = $this->inParens;
    14211473
    1422         if ($this->literal('(')) {
    1423             if ($this->literal(')')) {
     1474        if ($this->matchChar('(')) {
     1475            if ($this->matchChar(')')) {
    14241476                $out = [Type::T_LIST, '', []];
    14251477
     
    14291481            $this->inParens = true;
    14301482
    1431             if ($this->expression($exp) && $this->literal(')')) {
     1483            if ($this->expression($exp) && $this->matchChar(')')) {
    14321484                $out = $exp;
    14331485                $this->inParens = $inParens;
     
    14521504    protected function progid(&$out)
    14531505    {
    1454         $s = $this->seek();
    1455 
    1456         if ($this->literal('progid:', false) &&
     1506        $s = $this->count;
     1507
     1508        if ($this->literal('progid:', 7, false) &&
    14571509            $this->openString('(', $fn) &&
    1458             $this->literal('(')
     1510            $this->matchChar('(')
    14591511        ) {
    14601512            $this->openString(')', $args, '(');
    14611513
    1462             if ($this->literal(')')) {
     1514            if ($this->matchChar(')')) {
    14631515                $out = [Type::T_STRING, '', [
    14641516                    'progid:', $fn, '(', $args, ')'
     
    14771529     * Parse function call
    14781530     *
     1531     * @param string $name
    14791532     * @param array $out
    14801533     *
    14811534     * @return boolean
    14821535     */
    1483     protected function func(&$func)
    1484     {
    1485         $s = $this->seek();
    1486 
    1487         if ($this->keyword($name, false) &&
    1488             $this->literal('(')
    1489         ) {
     1536    protected function func($name, &$func)
     1537    {
     1538        $s = $this->count;
     1539
     1540        if ($this->matchChar('(')) {
    14901541            if ($name === 'alpha' && $this->argumentList($args)) {
    14911542                $func = [Type::T_FUNCTION, $name, [Type::T_STRING, '', $args]];
     
    14951546
    14961547            if ($name !== 'expression' && ! preg_match('/^(-[a-z]+-)?calc$/', $name)) {
    1497                 $ss = $this->seek();
    1498 
    1499                 if ($this->argValues($args) && $this->literal(')')) {
     1548                $ss = $this->count;
     1549
     1550                if ($this->argValues($args) && $this->matchChar(')')) {
    15001551                    $func = [Type::T_FUNCTION_CALL, $name, $args];
    15011552
     
    15071558
    15081559            if (($this->openString(')', $str, '(') || true) &&
    1509                 $this->literal(')')
     1560                $this->matchChar(')')
    15101561            ) {
    15111562                $args = [];
     
    15351586    protected function argumentList(&$out)
    15361587    {
    1537         $s = $this->seek();
    1538         $this->literal('(');
     1588        $s = $this->count;
     1589        $this->matchChar('(');
    15391590
    15401591        $args = [];
    15411592
    15421593        while ($this->keyword($var)) {
    1543             if ($this->literal('=') && $this->expression($exp)) {
     1594            if ($this->matchChar('=') && $this->expression($exp)) {
    15441595                $args[] = [Type::T_STRING, '', [$var . '=']];
    15451596                $arg = $exp;
     
    15501601            $args[] = $arg;
    15511602
    1552             if (! $this->literal(',')) {
     1603            if (! $this->matchChar(',')) {
    15531604                break;
    15541605            }
     
    15571608        }
    15581609
    1559         if (! $this->literal(')') || ! count($args)) {
     1610        if (! $this->matchChar(')') || !$args) {
    15601611            $this->seek($s);
    15611612
     
    15771628    protected function argumentDef(&$out)
    15781629    {
    1579         $s = $this->seek();
    1580         $this->literal('(');
     1630        $s = $this->count;
     1631        $this->matchChar('(');
    15811632
    15821633        $args = [];
     
    15851636            $arg = [$var[1], null, false];
    15861637
    1587             $ss = $this->seek();
    1588 
    1589             if ($this->literal(':') && $this->genericList($defaultVal, 'expression')) {
     1638            $ss = $this->count;
     1639
     1640            if ($this->matchChar(':') && $this->genericList($defaultVal, 'expression')) {
    15901641                $arg[1] = $defaultVal;
    15911642            } else {
     
    15931644            }
    15941645
    1595             $ss = $this->seek();
    1596 
    1597             if ($this->literal('...')) {
    1598                 $sss = $this->seek();
    1599 
    1600                 if (! $this->literal(')')) {
     1646            $ss = $this->count;
     1647
     1648            if ($this->literal('...', 3)) {
     1649                $sss = $this->count;
     1650
     1651                if (! $this->matchChar(')')) {
    16011652                    $this->throwParseError('... has to be after the final argument');
    16021653                }
     
    16101661            $args[] = $arg;
    16111662
    1612             if (! $this->literal(',')) {
     1663            if (! $this->matchChar(',')) {
    16131664                break;
    16141665            }
    16151666        }
    16161667
    1617         if (! $this->literal(')')) {
     1668        if (! $this->matchChar(')')) {
    16181669            $this->seek($s);
    16191670
     
    16351686    protected function map(&$out)
    16361687    {
    1637         $s = $this->seek();
    1638 
    1639         if (! $this->literal('(')) {
     1688        $s = $this->count;
     1689
     1690        if (! $this->matchChar('(')) {
    16401691            return false;
    16411692        }
     
    16441695        $values = [];
    16451696
    1646         while ($this->genericList($key, 'expression') && $this->literal(':') &&
     1697        while ($this->genericList($key, 'expression') && $this->matchChar(':') &&
    16471698            $this->genericList($value, 'expression')
    16481699        ) {
     
    16501701            $values[] = $value;
    16511702
    1652             if (! $this->literal(',')) {
     1703            if (! $this->matchChar(',')) {
    16531704                break;
    16541705            }
    16551706        }
    16561707
    1657         if (! count($keys) || ! $this->literal(')')) {
     1708        if (!$keys || ! $this->matchChar(')')) {
    16581709            $this->seek($s);
    16591710
     
    17301781    protected function string(&$out)
    17311782    {
    1732         $s = $this->seek();
    1733 
    1734         if ($this->literal('"', false)) {
     1783        $s = $this->count;
     1784
     1785        if ($this->matchChar('"', false)) {
    17351786            $delim = '"';
    1736         } elseif ($this->literal("'", false)) {
     1787        } elseif ($this->matchChar("'", false)) {
    17371788            $delim = "'";
    17381789        } else {
     
    17611812                }
    17621813            } elseif ($m[2] === '\\') {
    1763                 if ($this->literal('"', false)) {
     1814                if ($this->matchChar('"', false)) {
    17641815                    $content[] = $m[2] . '"';
    1765                 } elseif ($this->literal("'", false)) {
     1816                } elseif ($this->matchChar("'", false)) {
    17661817                    $content[] = $m[2] . "'";
    1767                 } elseif ($this->literal("\\", false)) {
     1818                } elseif ($this->literal("\\", 1, false)) {
    17681819                    $content[] = $m[2] . "\\";
    17691820                } else {
     
    17781829        $this->eatWhiteDefault = $oldWhite;
    17791830
    1780         if ($this->literal($delim)) {
     1831        if ($this->literal($delim, strlen($delim))) {
    17811832            if ($hasInterpolation) {
    17821833                $delim = '"';
     
    18331884        $this->eatWhiteDefault = $oldWhite;
    18341885
    1835         if (count($parts) === 0) {
     1886        if (!$parts) {
    18361887            return false;
    18371888        }
     
    18991950        $this->eatWhiteDefault = $oldWhite;
    19001951
    1901         if (count($content) === 0) {
     1952        if (!$content) {
    19021953            return false;
    19031954        }
     
    19251976        $oldWhite = $this->eatWhiteDefault;
    19261977        $this->eatWhiteDefault = true;
    1927         $selector = false;
    1928 
    1929         $s = $this->seek();
    1930 
    1931         if ($this->literal('#{') && $this->valueList($value) && $this->literal('}', false)) {
    1932 
     1978
     1979        $s = $this->count;
     1980
     1981        if ($this->literal('#{', 2) && $this->valueList($value) && $this->matchChar('}', false)) {
    19331982            if ($lookWhite) {
    19341983                $left = preg_match('/\s/', $this->buffer[$s - 1]) ? ' ' : '';
    1935                 $right = preg_match('/\s/', $this->buffer[$this->count]) ? ' ' : '';
     1984                $right = preg_match('/\s/', $this->buffer[$this->count]) ? ' ': '';
    19361985            } else {
    19371986                $left = $right = false;
    19381987            }
     1988
    19391989            $out = [Type::T_INTERPOLATE, $value, $left, $right];
    1940 
    19411990            $this->eatWhiteDefault = $oldWhite;
    19421991
     
    19501999        $this->seek($s);
    19512000
    1952         if ($this->literal('#{') && $selector = $this->selectorSingle($sel) && $this->literal('}', false)) {
    1953 
     2001        if ($this->literal('#{', 2) && $this->selectorSingle($sel) && $this->matchChar('}', false)) {
    19542002            $out = $sel[0];
    19552003
     
    19942042            }
    19952043
    1996             if (count($parts) === 0 && $this->match('[:.#]', $m, false)) {
     2044            if (!$parts && $this->match('[:.#]', $m, false)) {
    19972045                // css hacks
    19982046                $parts[] = $m[0];
     
    20052053        $this->eatWhiteDefault = $oldWhite;
    20062054
    2007         if (count($parts) === 0) {
     2055        if (!$parts) {
    20082056            return false;
    20092057        }
     
    20392087    protected function selectors(&$out)
    20402088    {
    2041         $s = $this->seek();
     2089        $s = $this->count;
    20422090        $selectors = [];
    20432091
     
    20452093            $selectors[] = $sel;
    20462094
    2047             if (! $this->literal(',')) {
     2095            if (! $this->matchChar(',')) {
    20482096                break;
    20492097            }
    20502098
    2051             while ($this->literal(',')) {
     2099            while ($this->matchChar(',')) {
    20522100                ; // ignore extra
    20532101            }
    20542102        }
    20552103
    2056         if (count($selectors) === 0) {
     2104        if (!$selectors) {
    20572105            $this->seek($s);
    20582106
     
    20962144        }
    20972145
    2098         if (count($selector) === 0) {
     2146        if (!$selector) {
    20992147            return false;
    21002148        }
     
    21222170        $parts = [];
    21232171
    2124         if ($this->literal('*', false)) {
     2172        if ($this->matchChar('*', false)) {
    21252173            $parts[] = '*';
    21262174        }
    21272175
    21282176        for (;;) {
     2177            if (! isset($this->buffer[$this->count])) {
     2178                break;
     2179            }
     2180
     2181            $s = $this->count;
     2182            $char = $this->buffer[$this->count];
     2183
    21292184            // see if we can stop early
    2130             if ($this->match('\s*[{,]', $m)) {
    2131                 $this->count--;
     2185            if ($char === '{' || $char === ',' || $char === ';' || $char === '}' || $char === '@') {
    21322186                break;
    21332187            }
    21342188
    2135             $s = $this->seek();
    2136 
    2137             // self
    2138             if ($this->literal('&', false)) {
    2139                 $parts[] = Compiler::$selfSelector;
    2140                 continue;
    2141             }
    2142             // self
    2143 //            if ($this->literal('#{&}', true)) {
    2144 //                $parts[] = Compiler::$selfSelector;
    2145 //                continue;
    2146 //            }
    2147 
    2148             if ($this->literal('.', false)) {
    2149                 $parts[] = '.';
    2150                 continue;
    2151             }
    2152 
    2153             if ($this->literal('|', false)) {
    2154                 $parts[] = '|';
    2155                 continue;
    2156             }
    2157 
    2158             if ($this->match('\\\\\S', $m)) {
     2189
     2190            //self
     2191            switch ($char) {
     2192                case '&':
     2193                    $parts[] = Compiler::$selfSelector;
     2194                    $this->count++;
     2195                    continue 2;
     2196                case '.':
     2197                    $parts[] = '.';
     2198                    $this->count++;
     2199                    continue 2;
     2200                case '|':
     2201                    $parts[] = '|';
     2202                    $this->count++;
     2203                    continue 2;
     2204            }
     2205
     2206
     2207            if ($char === '\\' && $this->match('\\\\\S', $m)) {
    21592208                $parts[] = $m[0];
    21602209                continue;
    21612210            }
     2211
     2212
     2213            if ($char === '%') {
     2214                $this->count++;
     2215                if ($this->placeholder($placeholder)) {
     2216                    $parts[] = '%';
     2217                    $parts[] = $placeholder;
     2218                    continue;
     2219                }
     2220                break;
     2221            }
     2222
     2223            if ($char === '#') {
     2224                if ($this->interpolation($inter)) {
     2225                    $parts[] = $inter;
     2226                    continue;
     2227                }
     2228
     2229                $parts[] = '#';
     2230                $this->count++;
     2231                continue;
     2232            }
     2233
     2234
     2235            // a pseudo selector
     2236            if ($char === ':') {
     2237                if ($this->buffer[$this->count + 1] === ':') {
     2238                    $this->count += 2;
     2239                    $part = '::';
     2240                } else {
     2241                    $this->count++;
     2242                    $part = ':';
     2243                }
     2244                if ($this->mixedKeyword($nameParts)) {
     2245                    $parts[] = $part;
     2246
     2247                    foreach ($nameParts as $sub) {
     2248                        $parts[] = $sub;
     2249                    }
     2250
     2251                    $ss = $this->count;
     2252
     2253                    if ($this->matchChar('(') &&
     2254                      ($this->openString(')', $str, '(') || true) &&
     2255                      $this->matchChar(')')
     2256                    ) {
     2257                        $parts[] = '(';
     2258
     2259                        if (! empty($str)) {
     2260                            $parts[] = $str;
     2261                        }
     2262
     2263                        $parts[] = ')';
     2264                    } else {
     2265                        $this->seek($ss);
     2266                    }
     2267
     2268                    continue;
     2269                }
     2270            }
     2271
     2272
     2273            $this->seek($s);
     2274
     2275
     2276            // attribute selector
     2277            if ($char === '[' &&
     2278              $this->matchChar('[') &&
     2279              ($this->openString(']', $str, '[') || true) &&
     2280              $this->matchChar(']')
     2281            ) {
     2282                $parts[] = '[';
     2283
     2284                if (! empty($str)) {
     2285                    $parts[] = $str;
     2286                }
     2287
     2288                $parts[] = ']';
     2289
     2290                continue;
     2291            }
     2292
     2293            $this->seek($s);
     2294
    21622295
    21632296            // for keyframes
     
    21722305            }
    21732306
    2174             if ($this->interpolation($inter)) {
    2175                 $parts[] = $inter;
    2176                 continue;
    2177             }
    2178 
    2179             if ($this->literal('%', false) && $this->placeholder($placeholder)) {
    2180                 $parts[] = '%';
    2181                 $parts[] = $placeholder;
    2182                 continue;
    2183             }
    2184 
    2185             if ($this->literal('#', false)) {
    2186                 $parts[] = '#';
    2187                 continue;
    2188             }
    2189 
    2190             // a pseudo selector
    2191             if ($this->match('::?', $m) && $this->mixedKeyword($nameParts)) {
    2192                 $parts[] = $m[0];
    2193 
    2194                 foreach ($nameParts as $sub) {
    2195                     $parts[] = $sub;
    2196                 }
    2197 
    2198                 $ss = $this->seek();
    2199 
    2200                 if ($this->literal('(') &&
    2201                     ($this->openString(')', $str, '(') || true) &&
    2202                     $this->literal(')')
    2203                 ) {
    2204                     $parts[] = '(';
    2205 
    2206                     if (! empty($str)) {
    2207                         $parts[] = $str;
    2208                     }
    2209 
    2210                     $parts[] = ')';
    2211                 } else {
    2212                     $this->seek($ss);
    2213                 }
    2214 
    2215                 continue;
    2216             }
    2217 
    2218             $this->seek($s);
    2219 
    2220             // attribute selector
    2221             if ($this->literal('[') &&
    2222                ($this->openString(']', $str, '[') || true) &&
    2223                $this->literal(']')
    2224             ) {
    2225                 $parts[] = '[';
    2226 
    2227                 if (! empty($str)) {
    2228                     $parts[] = $str;
    2229                 }
    2230 
    2231                 $parts[] = ']';
    2232 
    2233                 continue;
    2234             }
    2235 
    2236             $this->seek($s);
     2307
     2308
    22372309
    22382310            break;
     
    22412313        $this->eatWhiteDefault = $oldWhite;
    22422314
    2243         if (count($parts) === 0) {
     2315        if (!$parts) {
    22442316            return false;
    22452317        }
     
    22592331    protected function variable(&$out)
    22602332    {
    2261         $s = $this->seek();
    2262 
    2263         if ($this->literal('$', false) && $this->keyword($name)) {
     2333        $s = $this->count;
     2334
     2335        if ($this->matchChar('$', false) && $this->keyword($name)) {
    22642336            $out = [Type::T_VARIABLE, $name];
    22652337
     
    23452417    protected function end()
    23462418    {
    2347         if ($this->literal(';')) {
     2419        if ($this->matchChar(';')) {
    23482420            return true;
    23492421        }
  • _plugins_/scssphp/trunk/lib/scssphp/src/SourceMap/Base64.php

    r114927 r115043  
    2222     * @var array
    2323     */
    24     private static $encodingMap = array (
     24    private static $encodingMap = [
    2525        0 => 'A',
    2626        1 => 'B',
     
    8787        62 => '+',
    8888        63 => '/',
    89     );
     89    ];
    9090
    9191    /**
    9292     * @var array
    9393     */
    94     private static $decodingMap = array(
     94    private static $decodingMap = [
    9595        'A' => 0,
    9696        'B' => 1,
     
    157157        '+' => 62,
    158158        '/' => 63,
    159     );
     159    ];
    160160
    161161    /**
  • _plugins_/scssphp/trunk/lib/scssphp/src/SourceMap/Base64VLQ.php

    r114927 r115043  
    1111
    1212namespace Leafo\ScssPhp\SourceMap;
    13 
    14 use Leafo\ScssPhp\SourceMap\Base64;
    1513
    1614/**
  • _plugins_/scssphp/trunk/lib/scssphp/src/SourceMap/Base64VLQEncoder.php

    r108871 r115043  
    4848     * @var array
    4949     */
    50     private $charToIntMap = array(
     50    private $charToIntMap = [
    5151        'A' => 0,  'B' => 1,  'C' => 2,  'D' => 3,  'E' => 4,  'F' => 5,  'G' => 6,  'H' => 7,
    5252        'I' => 8,  'J' => 9,  'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15,
     
    5757        'w' => 48, 'x' => 49, 'y' => 50, 'z' => 51,   0 => 52,   1 => 53,   2 => 54,   3 => 55,
    5858          4 => 56,   5 => 57,   6 => 58,   7 => 59,   8 => 60,   9 => 61, '+' => 62, '/' => 63,
    59     );
     59    ];
    6060
    6161    /**
     
    6464     * @var array
    6565     */
    66     private $intToCharMap = array(
     66    private $intToCharMap = [
    6767         0 => 'A',  1 => 'B',  2 => 'C',  3 => 'D',  4 => 'E',  5 => 'F',  6 => 'G',  7 => 'H',
    6868         8 => 'I',  9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', 14 => 'O', 15 => 'P',
     
    7373        48 => 'w', 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3',
    7474        56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', 63 => '/',
    75     );
     75    ];
    7676
    7777    /**
  • _plugins_/scssphp/trunk/lib/scssphp/src/SourceMap/SourceMapGenerator.php

    r114927 r115043  
    3434     * @var array
    3535     */
    36     protected $defaultOptions = array(
     36    protected $defaultOptions = [
    3737        // an optional source root, useful for relocating source files
    3838        // on a server or removing repeated values in the 'sources' entry.
     
    5757        // base path for filename normalization
    5858        'sourceMapBasepath' => ''
    59     );
     59    ];
    6060
    6161    /**
     
    7171     * @var array
    7272     */
    73     protected $mappings = array();
     73    protected $mappings = [];
    7474
    7575    /**
     
    7878     * @var array
    7979     */
    80     protected $contentsMap = array();
     80    protected $contentsMap = [];
    8181
    8282    /**
     
    8585     * @var array
    8686     */
    87     protected $sources = array();
    88     protected $source_keys = array();
     87    protected $sources = [];
     88    protected $source_keys = [];
    8989
    9090    /**
     
    110110    public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile)
    111111    {
    112         $this->mappings[] = array(
     112        $this->mappings[] = [
    113113            'generated_line' => $generatedLine,
    114114            'generated_column' => $generatedColumn,
     
    116116            'original_column' => $originalColumn,
    117117            'source_file' => $sourceFile
    118         );
     118        ];
    119119
    120120        $this->sources[$sourceFile] = $sourceFile;
     
    157157    public function generateJson()
    158158    {
    159         $sourceMap = array();
     159        $sourceMap = [];
    160160        $mappings  = $this->generateMappings();
    161161
     
    179179
    180180        // A list of original sources used by the 'mappings' entry.
    181         $sourceMap['sources'] = array();
     181        $sourceMap['sources'] = [];
    182182
    183183        foreach ($this->sources as $source_uri => $source_filename) {
     
    186186
    187187        // A list of symbol names used by the 'mappings' entry.
    188         $sourceMap['names'] = array();
     188        $sourceMap['names'] = [];
    189189
    190190        // A string with the encoded mapping data.
     
    217217        }
    218218
    219         $content = array();
     219        $content = [];
    220220
    221221        foreach ($this->sources as $sourceFile) {
     
    240240
    241241        // group mappings by generated line number.
    242         $groupedMap = $groupedMapEncoded = array();
     242        $groupedMap = $groupedMapEncoded = [];
    243243
    244244        foreach ($this->mappings as $m) {
     
    254254            }
    255255
    256             $lineMapEncoded = array();
     256            $lineMapEncoded = [];
    257257            $lastGeneratedColumn = 0;
    258258
  • _plugins_/scssphp/trunk/lib/scssphp/src/Util.php

    r108871 r115043  
    6464    public static function encodeURIComponent($string)
    6565    {
    66         $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
     66        $revert = ['%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')'];
    6767
    6868        return strtr(rawurlencode($string), $revert);
  • _plugins_/scssphp/trunk/paquet.xml

    r114987 r115043  
    22        prefix="scssphp"
    33        categorie="outil"
    4         version="1.7.0"
     4        version="1.8.0"
    55        etat="test"
    66        compatibilite="[2.1.0;3.2.*]"
     
    2222        <pipeline nom="formulaire_admin"  inclure="scssphp_pipelines.php" />
    2323
    24         <procure nom="scssphp" version="0.7.8.1" />
     24        <procure nom="scssphp" version="0.7.8.2" />
    2525
    2626        <spip compatibilite="[3.1.0;[">
  • _plugins_/scssphp/trunk/plugin.xml

    r114987 r115043  
    66        <auteur>Jean-Baptiste Bourgoin</auteur>
    77        <licence>GPL 3</licence>
    8         <version>1.7.0</version>
     8        <version>1.8.0</version>
    99        <etat>test</etat>
    1010        <icon>scsscss.png</icon>
Note: See TracChangeset for help on using the changeset viewer.