You are here

public function SassScriptParser::parse in Sassy 7.3

Same name and namespace in other branches
  1. 7 phamlp/sass/script/SassScriptParser.php \SassScriptParser::parse()

Parse SassScript to a set of tokens in RPN using the Shunting Yard Algorithm.

Parameters

string expression to parse:

SassContext the context in which the expression is parsed:

integer the environment in which the expression is parsed:

Return value

array tokens in RPN

1 call to SassScriptParser::parse()
SassScriptParser::evaluate in phpsass/script/SassScriptParser.php
Evaluate a SassScript.

File

phpsass/script/SassScriptParser.php, line 121

Class

SassScriptParser
SassScriptParser class. Parses SassScript. SassScript is lexed into {@link http://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish notation} by the SassScriptLexer and the calculated result returned. @package PHamlP @subpackage …

Code

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) {
          throw new SassScriptParserException('Unmatched parentheses', $context->node);
        }
      }
      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;
}