SassScriptParser::parse PHP Method

parse() public method

Parse SassScript to a set of tokens in RPN using the Shunting Yard Algorithm.
public parse ( string $expression, SassContext $context, integer $environment = self::DEFAULT_ENV ) : array
$expression string expression to parse
$context SassContext the context in which the expression is parsed
$environment integer the environment in which the expression is parsed
return array tokens in RPN
    public function parse($expression, $context, $environment = self::DEFAULT_ENV)
    {
        $outputQueue = array();
        $operatorStack = array();
        $parenthesis = 0;
        $tokens = $this->lexer->lex($expression, $context);
        foreach ($tokens as $i => $token) {
            // If two literals/expessions are seperated by whitespace use the concat operator
            if (empty($token)) {
                if (isset($tokens[$i + 1])) {
                    if ($i > 0 && (!$tokens[$i - 1] instanceof SassScriptOperation || $tokens[$i - 1]->operator === SassScriptOperation::$operators[')'][0]) && (!$tokens[$i + 1] instanceof SassScriptOperation || $tokens[$i + 1]->operator === SassScriptOperation::$operators['('][0])) {
                        $token = new SassScriptOperation(SassScriptOperation::$defaultOperator, $context);
                    } else {
                        continue;
                    }
                }
            } elseif ($token instanceof SassScriptVariable) {
                $token = $token->evaluate($context);
                $environment = self::DEFAULT_ENV;
            }
            // If the token is a number or function add it to the output queue.
            if ($token instanceof SassLiteral || $token instanceof SassScriptFunction) {
                if ($environment === self::CSS_PROPERTY && $token instanceof SassNumber && !$parenthesis) {
                    $token->inExpression = false;
                }
                array_push($outputQueue, $token);
            } elseif ($token instanceof SassScriptOperation) {
                // If the token is a left parenthesis push it onto the stack.
                if ($token->operator == SassScriptOperation::$operators['('][0]) {
                    array_push($operatorStack, $token);
                    $parenthesis++;
                } elseif ($token->operator == SassScriptOperation::$operators[')'][0]) {
                    $parenthesis--;
                    while ($c = count($operatorStack)) {
                        // If the token at the top of the stack is a left parenthesis
                        if ($operatorStack[$c - 1]->operator == SassScriptOperation::$operators['('][0]) {
                            // Pop the left parenthesis from the stack, but not onto the output queue.
                            array_pop($operatorStack);
                            break;
                        }
                        // else pop the operator off the stack onto the output queue.
                        array_push($outputQueue, array_pop($operatorStack));
                    }
                    // If the stack runs out without finding a left parenthesis
                    // there are mismatched parentheses.
                    if ($c <= 0) {
                        array_push($outputQueue, new SassString(')'));
                        break;
                    }
                } else {
                    // while there is an operator, o2, at the top of the stack
                    while ($c = count($operatorStack)) {
                        $operation = $operatorStack[$c - 1];
                        // if o2 is left parenthesis, or
                        // the o1 has left associativty and greater precedence than o2, or
                        // the o1 has right associativity and lower or equal precedence than o2
                        if ($operation->operator == SassScriptOperation::$operators['('][0] || $token->associativity == 'l' && $token->precedence > $operation->precedence || $token->associativity == 'r' && $token->precedence <= $operation->precedence) {
                            break;
                            // stop checking operators
                        }
                        //pop o2 off the stack and onto the output queue
                        array_push($outputQueue, array_pop($operatorStack));
                    }
                    // push o1 onto the stack
                    array_push($operatorStack, $token);
                }
            }
        }
        // When there are no more tokens
        while ($c = count($operatorStack)) {
            // While there are operators on the stack:
            if ($operatorStack[$c - 1]->operator !== SassScriptOperation::$operators['('][0]) {
                array_push($outputQueue, array_pop($operatorStack));
            } else {
                throw new SassScriptParserException('Unmatched parentheses', $context->node);
            }
        }
        return $outputQueue;
    }

Usage Example

Beispiel #1
0
 public static function colour_stops()
 {
     $args = func_get_args();
     $list = array();
     foreach ($args as $arg) {
         if ($arg instanceof SassColour) {
             $list[] = new CompassColourStop($arg);
         } elseif ($arg instanceof SassString) {
             # We get a string as the result of concatenation
             # So we have to reparse the expression
             $colour = $stop = null;
             if (empty($parser)) {
                 $parser = new SassScriptParser();
             }
             $expr = $parser->parse($arg->value, SassScriptParser::$context);
             $x = array_pop($expr);
             if ($x instanceof SassColour) {
                 $colour = $x;
             } elseif ($x instanceof SassScriptOperation) {
                 if ($x->operator != 'concat') {
                     # This should never happen.
                     throw new SassScriptFunctionException("Couldn't parse a colour stop from: {value}", array('{value}' => $arg->value), SassScriptParser::$context->node);
                 }
                 $colour = $expr[0];
                 $stop = $expr[1];
             } else {
                 throw new SassScriptFunctionException("Couldn't parse a colour stop from: {value}", array('{value}' => $arg->value), SassScriptParser::$context->node);
             }
             $list[] = new CompassColourStop($colour, $stop);
         } else {
             throw new SassScriptFunctionException('Not a valid color stop: {arg}', array('{arg}' => $arg->value), SassScriptParser::$context->node);
         }
     }
     return new CompassList($list);
 }