Source for file parser.php
Documentation is available at parser.php
-  * @package     FrameworkOnFramework 
-  * @copyright   Copyright (C) 2010 - 2012 Akeeba Ltd. All rights reserved. 
-  * @license     GNU General Public License version 2 or later; see LICENSE.txt 
- // Protect from unauthorized access 
-  * This class is taken verbatim from: 
-  * http://leafo.net/lessphp 
-  * LESS css compiler, adapted from http://lesscss.org 
-  * Copyright 2012, Leaf Corcoran <leafot@gmail.com> 
-  * Licensed under MIT or GPLv3, see LICENSE 
-  * Responsible for taking a string of LESS code and converting it into a syntax tree 
-     // Used to uniquely identify blocks 
-     protected static $nextBlockId - =  0;
 
-     protected static $precedence - =  array(
 
-     protected static $whitePattern; 
-     protected static $commentMulti; 
-     protected static $commentSingle - =  "//";
 
-     protected static $commentMultiLeft - =  "/*";
 
-     protected static $commentMultiRight - =  "*/";
 
-     // Regex string to match any of the operators 
-     protected static $operatorString; 
-     // These properties will supress division unless it's inside parenthases 
-     protected static $supressDivisionProps - =  array('/border-radius$/i', '/^font$/i');
 
-     protected $blockDirectives-  =  array("font-face", "keyframes", "page", "-moz-document");
 
-      * if we are in parens we can be more liberal with whitespace around 
-      * operators because it must evaluate to a single value and thus is less 
-      *     property1: 10 -5; // is two numbers, 10 and -5 
-      *     property2: (10 -5); // should evaluate to 5 
-     // Caches preg escaped literals 
-     protected static $literalCache - =  array();
 
-      * @param   [type]  $lessc       [description] 
-      * @param   string  $sourceName  [description] 
-     public function __construct($lessc, $sourceName - =  null)
 
-         $this->eatWhiteDefault - =  true;
 
-         // Reference to less needed for vPrefix, mPrefix, and parentSelector 
-         // Name used for error messages 
-         $this->sourceName - =  $sourceName;
 
-         $this->writeComments - =  false;
 
-         if (!self::$operatorString) 
-             self::$operatorString - =  '('- .  implode('|', array_map(array('FOFLess', 'preg_quote'), array_keys(self::$precedence)))- .  ')';
 
-             $commentSingle - =  FOFLess::preg_quote(self::$commentSingle);
 
-             $commentMultiLeft - =  FOFLess::preg_quote(self::$commentMultiLeft);
 
-             $commentMultiRight - =  FOFLess::preg_quote(self::$commentMultiRight);
 
-             self::$commentMulti - =  $commentMultiLeft- .  '.*?'- .  $commentMultiRight;
 
-             self::$whitePattern - =  '/'- .  $commentSingle- .  '[^\n]*\s*|('- .  self::$commentMulti- .  ')\s*|\s+/Ais';
 
-      * @param   string  $buffer  [description] 
-      * @return  [type]           [description] 
-     public function parse($buffer) 
-         $this->buffer - =  $this->writeComments- ?  $buffer- :  $this->removeComments($buffer);
 
-         $this->eatWhiteDefault - =  true;
 
-         $this->seenComments - =  array();
 
-          * trim whitespace on head 
-          * if (preg_match('/^\s+/', $this->buffer, $m)) { 
-          *     $this->line += substr_count($m[0], "\n"); 
-          *     $this->buffer = ltrim($this->buffer); 
-         $lastCount - =  $this->count;
 
-         if ($this->count - !=  strlen($this->buffer))
 
-         // TODO report where the block was opened 
-             throw  new exception('parse error: unclosed block');
-      * Parse a single chunk off the head of the buffer and append it to the 
-      * current parse environment. 
-      * Returns false when the buffer is empty, or when there is an error. 
-      * This function is called repeatedly until the entire document is 
-      * This parser is most similar to a recursive descent parser. Single 
-      * functions represent discrete grammatical rules for the language, and 
-      * they are able to capture the text that represents those rules. 
-      * Consider the function lessc::keyword(). (all parse functions are 
-      * The function takes a single reference argument. When calling the 
-      * function it will attempt to match a keyword on the head of the buffer. 
-      * If it is successful, it will place the keyword in the referenced 
-      * argument, advance the position in the buffer, and return true. If it 
-      * fails then it won't advance the buffer and it will return false. 
-      * All of these parse functions are powered by lessc::match(), which behaves 
-      * the same way, but takes a literal regular expression. Sometimes it is 
-      * more convenient to use match instead of creating a new function. 
-      * Because of the format of the functions, to parse an entire string of 
-      * grammatical rules, you can chain them together using &&. 
-      * But, if some of the rules in the chain succeed before one fails, then 
-      * the buffer position will be left at an invalid state. In order to 
-      * avoid this, lessc::seek() is used to remember and set buffer positions. 
-      * Before parsing a chain, use $s = $this->seek() to remember the current 
-      * position into $s. Then if a chain fails, use $this->seek($s) to 
-      * go back where we started. 
-         if (empty($this->buffer)) 
-             $this->append(array('assign', $key, $value), $s); 
-         // Look for special css blocks 
-                     $media->queries - =  is_null($mediaQueries)- ?  array()- :  $mediaQueries;
 
-                     if (($this->openString("{", $dirValue, null, array(";")) - ||  true)
 
-                         $this->append(array("directive", $dirName, $dirValue)); 
-             $this->append(array('assign', $var, $value), $s); 
-         if ($this->import($importValue)) 
-             $this->append($importValue, $s); 
-         // Opening parametric mixin 
-             &&  ($this->guards($guards)- ||  true)
-             $block->isVararg - =  $isVararg;
 
-                 $block->guards - =  $guards;
 
-         // Opening a simple block 
-                 if (!- isset ($block->args))
 
-                     foreach ($block->tags as $tag) 
-                         if (!is_string($tag) - ||  $tag{0}- !=  $this->lessc->mPrefix)
 
-                 foreach ($block->tags as $tag) 
-                         $this->env->children[$tag][] - =  $block;
 
-                 $this->append(array('block', $block), $s); 
-             // This is done here so comments aren't bundled into he block that was just closed 
-             &&  ($this->keyword($suffix)- ||  true)
-             $this->append(array('mixin', $tags, $argv, $suffix), $s); 
-         // Got nothing, throw error 
-      * [isDirective description] 
-      * @param   string  $dirname     [description] 
-      * @param   [type]  $directives  [description] 
-         // TODO: cache pattern in parser 
-         $pattern - =  implode("|", array_map(array("FOFLess", "preg_quote"), $directives));
 
-         $pattern - =  '/^(-[a-z-]+-)?('- .  $pattern- .  ')$/i';
 
-      * @param   [type]  $tags  [description] 
-      * @return  [type]         [description] 
-         // Move @ tags out of variable namespace 
-             if ($tag{0} - ==  $this->lessc->vPrefix)
 
-                 $tag[0] - =  $this->lessc->mPrefix;
 
-      * @param   [type]  &$exps  [description] 
-      * Attempt to consume an expression. 
-      * @param   string  &$out  [description] 
-      * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code 
-             if (!empty($this->env->supressedDivision)) 
-                 unset ($this->env->supressedDivision);
-                         array($out, array("keyword", "/"), $rhs)); 
-      * Recursively parse infix equation with $lhs at precedence $minP 
-      * @param   type  $lhs   [description] 
-      * @param   type  $minP  [description] 
-             $whiteBefore - = isset ($this->buffer[$this->count- -  1])- &&  ctype_space($this->buffer[$this->count- -  1]);
 
-             // If there is whitespace before the operator, then we require 
-             // whitespace after the operator for it to be an expression 
-             $needWhite - =  $whiteBefore- &&  !$this->inParens;
 
-             if ($this->match(self::$operatorString - .  ($needWhite- ?  '\s'- :  ''), $m)- &&  self::$precedence[$m[1]]- >=  $minP)
 
-                 if (!$this->inParens-  && isset ($this->env->currentProperty)- &&  $m[1]- ==  "/"- &&  empty($this->env->supressedDivision))
 
-                     foreach (self::$supressDivisionProps as $pattern) 
-                         if (preg_match($pattern, $this->env->currentProperty)) 
-                             $this->env->supressedDivision - =  true;
 
-                 $whiteAfter - = isset ($this->buffer[$this->count- -  1])- &&  ctype_space($this->buffer[$this->count- -  1]);
 
-                 // Peek for next operator to see what to do with rhs 
-                 if ($this->peek(self::$operatorString, $next) - &&  self::$precedence[$next[1]]- >  self::$precedence[$m[1]])
 
-                     $rhs - =  $this->expHelper($rhs, self::$precedence[$next[1]]);
 
-                 $lhs - =  array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
 
-      * Consume a list of values for a property 
-      * @param   [type]  &$value   [description] 
-      * @param   [type]  $keyName  [description] 
-             $this->env->currentProperty - =  $keyName;
 
-             unset ($this->env->currentProperty);
-      * [parenValue description] 
-      * @param   [type]  &$out  [description] 
-         if (- isset ($this->buffer[$this->count])- &&  $this->buffer[$this->count]- !=  "(")
 
-      * @param   [type]  &$value  [description] 
-     protected function value(&$value) 
-         if (- isset ($this->buffer[$this->count])- &&  $this->buffer[$this->count]- ==  "-")
 
-             if ($this->literal("-", false) - && (($this->variable($inner)- &&  $inner- =  array("variable", $inner))
 
-                 $value - =  array("unary", "-", $inner);
 
-         if ($this->color($value)) 
-             $value - =  array('keyword', $word);
 
-             $value - =  array('variable', $var);
 
-         // Unquote string (should this work on any type? 
-             $value - =  array("escape", $str);
 
-             $value - =  array('keyword', '\\'- .  $m[1]);
 
-      * @param   [type]  &$out  [description] 
-     protected function import(&$out) 
-          * @import "something.css" media; 
-          * @import url("something.css") media; 
-          * @import url(something.css) media; 
-             $out - =  array("import", $value);
 
-      * [mediaQueryList description] 
-      * @param   [type]  &$out  [description] 
-         if ($this->genericList($list, "mediaQuery", ",", false)) 
-      * [mediaQuery description] 
-      * @param   [type]  &$out  [description] 
-      * @return  [type]        [description] 
-         if (($this->literal("only") - &&  ($only- =  true)- ||  $this->literal("not")- &&  ($not- =  true)- ||  true)- &&  $this->keyword($mediaType))
 
-             $prop - =  array("mediaType");
 
-         if (!empty($mediaType) - &&  !$this->literal("and"))
 
-             $this->genericList($expressions, "mediaExpression", "and", false); 
-      * [mediaExpression description] 
-      * @param   [type]  &$out  [description] 
-             $out - =  array("mediaExp", $feature);
 
-             $out - =  array('variable', $variable);
 
-      * An unbounded string stopped by $end 
-      * @param   [type]  $end          [description] 
-      * @param   [type]  &$out         [description] 
-      * @param   [type]  $nestingOpen  [description] 
-      * @param   [type]  $rejectStrs   [description] 
-     protected function openString($end, &$out, $nestingOpen - =  null, $rejectStrs- =  null)
 
-         $oldWhite - =  $this->eatWhiteDefault;
 
-         $this->eatWhiteDefault - =  false;
 
-         $stop - =  array("'", '"', "@{", $end);
 
-         $stop - =  array_map(array("FOFLess", "preg_quote"), $stop);
 
-         // $stop[] = self::$commentMulti; 
-         $patt - =  '(.*?)('- .  implode("|", $stop)- .  ')';
 
-         while ($this->match($patt, $m, false)) 
-             if (($tok - ==  "'"- ||  $tok- ==  '"')- &&  $this->string($str))
 
-         $this->eatWhiteDefault - =  $oldWhite;
 
-         if (count($content) - ==  0)
 
-         $out - =  array("string", "", $content);
 
-      * @param   [type]  &$out  [description] 
-     protected function string(&$out) 
-         elseif ($this->literal("'", false)) 
-         // Look for either ending delim , escape, or string interpolation 
-         $oldWhite - =  $this->eatWhiteDefault;
 
-         $this->eatWhiteDefault - =  false;
 
-         while ($this->match($patt, $m, false)) 
-                 $this->count - -=  strlen($m[2]);
 
-                     $this->count - +=  strlen($m[2]);
 
-                 $this->count - -=  strlen($delim);
 
-         $this->eatWhiteDefault - =  $oldWhite;
 
-             $out - =  array("string", $delim, $content);
 
-      * [interpolation description] 
-      * @param   [type]  &$out  [description] 
-         $oldWhite - =  $this->eatWhiteDefault;
 
-         $this->eatWhiteDefault - =  true;
 
-             $out - =  array("interpolate", $interp);
 
-             $this->eatWhiteDefault - =  $oldWhite;
 
-             if ($this->eatWhiteDefault) 
-         $this->eatWhiteDefault - =  $oldWhite;
 
-      * @param   [type]  &$unit  [description] 
-     protected function unit(&$unit) 
-         if (- isset ($this->buffer[$this->count]))
 
-             $char - =  $this->buffer[$this->count];
 
-         if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) 
-             $unit - =  array("number", $m[1], empty($m[2])- ?  ""- :  $m[2]);
 
-      * @param   [type]  &$out  [description] 
-     protected function color(&$out) 
-         if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) 
-                 $out - =  array("string", "", array($m[1]));
 
-                 $out - =  array("raw_color", $m[1]);
 
-      * Consume a list of property values delimited by ; and wrapped in () 
-      * @param   [type]  &$args  [description] 
-      * @param   [type]  $delim  [description] 
-      * Consume an argument definition list surrounded by () 
-      * each argument is a variable name with optional value 
-      * or at the end a ... or a variable named followed by ... 
-      * @param   [type]  &$args      [description] 
-      * @param   [type]  &$isVararg  [description] 
-      * @param   [type]  $delim      [description] 
-     protected function argumentDef(&$args, &$isVararg, $delim - =  ',')
 
-                 $arg - =  array("arg", $vname);
 
-             if ($this->value($literal)) 
-                 $values[] - =  array("lit", $literal);
 
-      * This accepts a hanging delimiter 
-      * @param   [type]  &$tags   [description] 
-      * @param   [type]  $simple  [description] 
-      * @param   [type]  $delim   [description] 
-     protected function tags(&$tags, $simple - =  false, $delim- =  ',')
 
-         while ($this->tag($tt, $simple)) 
-      * List of tags of specifying mixin path 
-      * Optionally separated by > (lazy, accepts extra >) 
-      * @param   [type]  &$tags  [description] 
-         while ($this->tag($tt, true)) 
-      * A bracketed value (contained within in a tag definition) 
-      * @param   [type]  &$value  [description] 
-         if (- isset ($this->buffer[$this->count])- &&  $this->buffer[$this->count]- !=  "[")
 
-         if ($this->literal('[') - &&  $this->to(']', $c, true)- &&  $this->literal(']', false))
 
-             // Escape parent selector, (yuck) 
-             $value - =  str_replace($this->lessc->parentSelector, "$&$", $value);
 
-      * [tagExpression description] 
-      * @param   [type]  &$value  [description] 
-             $value - =  array('exp', $exp);
 
-      * @param   [type]   &$tag    [description] 
-      * @param   boolean  $simple  [description] 
-     protected function tag(&$tag, $simple - =  false)
 
-             $chars - =  '^@,:;{}\][>\(\) "\'';
 
-         $oldWhite - =  $this->eatWhiteDefault;
 
-         $this->eatWhiteDefault - =  false;
 
-             if ($this->match('([' - .  $chars- .  '0-9]['- .  $chars- .  ']*)', $m))
 
-             if (- isset ($this->buffer[$this->count])- &&  $this->buffer[$this->count]- ==  "@")
 
-         $this->eatWhiteDefault - =  $oldWhite;
 
-             $tag - =  array("exp", array("string", "", $parts));
 
-      * @param   [type]  &$func  [description] 
-     protected function func(&$func) 
-         if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) - &&  $this->literal('('))
 
-             $sPreArgs - =  $this->seek();
 
-                 // This ugly nonsense is for ie filter properties 
-                     $args[] - =  array("string", "", array($name, "=", $value));
 
-             $args - =  array('list', ',', $args);
 
-                 $func - =  array('function', $fname, $args);
 
-                 // Couldn't parse and in url? treat as string 
-                     $func - =  array('function', $fname, $string);
 
-      * Consume a less variable 
-      * @param   [type]  &$name  [description] 
-                 $name - =  array('variable', $sub);
 
-                 $name - =  $this->lessc->vPrefix- .  $name;
 
-      * Consume an assignment operator 
-      * Can optionally take a name that will be set to the current property name 
-      * @param   string  $name  [description] 
-     protected function assign($name - =  null)
 
-             $this->currentProperty - =  $name;
 
-      * @param   [type]  &$word  [description] 
-         if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) 
-      * Consume an end of statement delimiter 
-         elseif ($this->count - ==  strlen($this->buffer)- ||  $this->buffer{$this->count}- ==  '}')
 
-             // If there is end of file or a closing block next then we don't need a ; 
-      * @param   [type]  &$guards  [description] 
-     protected function guards(&$guards) 
-      * A bunch of guards that are and'd together 
-      * @param   [type]  &$guardGroup  [description] 
-      * @todo rename to guardGroup 
-         while ($this->guard($guard)) 
-         if (count($guardGroup) - ==  0)
 
-      * @param   [type]  &$guard  [description] 
-     protected function guard(&$guard) 
-                 $guard - =  array("negate", $guard);
 
-     /* raw parsing functions */ 
-      * @param   [type]  $what           [description] 
-      * @param   [type]  $eatWhitespace  [description] 
-     protected function literal($what, $eatWhitespace - =  null)
 
-         if ($eatWhitespace - ===  null)
 
-             $eatWhitespace - =  $this->eatWhiteDefault;
 
-         // Shortcut on single letter 
-         if (!- isset ($what[1])- && isset ($this->buffer[$this->count]))
 
-             if ($this->buffer[$this->count] - ==  $what)
 
-         if (!- isset (self::$literalCache[$what]))
 
-             self::$literalCache[$what] - =  FOFLess::preg_quote($what);
 
-         return $this->match(self::$literalCache[$what], $m, $eatWhitespace); 
-      * [genericList description] 
-      * @param   [type]   &$out       [description] 
-      * @param   [type]   $parseItem  [description] 
-      * @param   string   $delim      [description] 
-      * @param   boolean  $flatten    [description] 
-     protected function genericList(&$out, $parseItem, $delim - =  "", $flatten- =  true)
 
-         while ($this->$parseItem($value)) 
-         if ($flatten - &&  count($items)- ==  1)
 
-             $out - =  array("list", $delim, $items);
 
-      * Advance counter to next occurrence of $what 
-      * $until - don't include $what in advance 
-      * $allowNewline, if string, will be used as valid char set 
-      * @param   [type]   $what          [description] 
-      * @param   [type]   &$out          [description] 
-      * @param   boolean  $until         [description] 
-      * @param   boolean  $allowNewline  [description] 
-     protected function to($what, &$out, $until - =  false, $allowNewline- =  false)
 
-             $validChars - =  $allowNewline;
 
-             $validChars - =  $allowNewline- ?  "."- :  "[^\n]";
 
-             $this->count - -=  strlen($what);
 
-      * Try to match something on head of buffer 
-      * @param   [type]  $regex          [description] 
-      * @param   [type]  &$out           [description] 
-      * @param   [type]  $eatWhitespace  [description] 
-     protected function match($regex, &$out, $eatWhitespace - =  null)
 
-         if ($eatWhitespace - ===  null)
 
-             $eatWhitespace - =  $this->eatWhiteDefault;
 
-         $r - =  '/'- .  $regex- .  ($eatWhitespace- &&  !$this->writeComments- ?  '\s*'- :  '')- .  '/Ais';
 
-         if (preg_match($r, $this->buffer, $out, null, $this->count)) 
-             $this->count - +=  strlen($out[0]);
 
-             if ($eatWhitespace - &&  $this->writeComments)
 
-         if ($this->writeComments) 
-             while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) 
-                 if (- isset ($m[1])- &&  empty($this->commentsSeen[$this->count]))
 
-                     $this->append(array("comment", $m[1])); 
-                     $this->commentsSeen[$this->count] - =  true;
 
-                 $this->count - +=  strlen($m[0]);
 
-      * Match something without consuming it 
-      * @param   [type]  $regex  [description] 
-      * @param   [type]  &$out   [description] 
-      * @param   [type]  $from   [description] 
-     protected function peek($regex, &$out - =  null, $from- =  null)
 
-         $r - =  '/'- .  $regex- .  '/Ais';
 
-         $result - =  preg_match($r, $this->buffer, $out, null, $from);
 
-      * Seek to a spot in the buffer or return where we are on no argument 
-      * @param   [type]  $where  [description] 
-     protected function seek($where - =  null)
 
-      * [throwError description] 
-      * @param   string  $msg    [description] 
-      * @param   [type]  $count  [description] 
-     public function throwError($msg - =  "parse error", $count- =  null)
 
-         $count - =  is_null($count)- ?  $this->count- :  $count;
 
-         if (!empty($this->sourceName)) 
-             $loc - =  "$this->sourceName on line $line";
 
-         // TODO this depends on $this->count 
-         if ($this->peek("(.*?)(\n|$)", $m, $count)) 
-             throw  new exception("$msg: failed at `$m[1]` $loc");
-             throw  new exception("$msg: $loc");
-      * [pushBlock description] 
-      * @param   [type]  $selectors  [description] 
-      * @param   [type]  $type       [description] 
-     protected function pushBlock($selectors - =  null, $type- =  null)
 
-         $b->id - =  self::$nextBlockId- ++ ;
 
-         // TODO: kill me from here 
-      * Push a block that doesn't multiply tags 
-      * @param   [type]  $type  [description] 
-      * Append a property to the current block 
-      * @param   [type]  $prop  [description] 
-      * @param   [type]  $pos   [description] 
-     protected function append($prop, $pos - =  null)
 
-         $this->env->props[] - =  $prop;
 
-      * Pop something off the stack 
-      * @return  [type]  [description] 
-         $this->env - =  $this->env->parent;
 
-      * Remove comments from $text 
-      * @param   [type]  $text  [description] 
-      * @todo: make it work for all functions, not just url 
-      * @return  [type]         [description] 
-             'url(', '//', '/*', '"', "'" 
-             foreach ($look as $token) 
-                     if (!- isset ($min)- ||  $pos- <  $min[1])
 
-                         $min - =  array($token, $pos);
 
-                     if (preg_match('/url\(.*?\)/', $text, $m, 0, $count)) 
-                     if (preg_match('/' - .  $min[0]- .  '.*?'- .  $min[0]- .  '/', $text, $m, 0, $count))
 
-                     $skip - =  strpos($text, "\n", $count);
 
-                         $skip - =  strlen($text)- -  $count;
 
-                     if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) 
-             $text - =  substr($text, $count- +  $skip);
 
 
	
		Documentation generated on Tue, 19 Nov 2013 15:10:16 +0100 by phpDocumentor 1.4.3