Leafo\ScssPhp\Compiler::reduce PHP Method

reduce() protected method

Reduce value
protected reduce ( array $value, boolean $inExp = false ) : array
$value array
$inExp boolean
return array
    protected function reduce($value, $inExp = false)
    {
        list($type) = $value;
        switch ($type) {
            case Type::T_EXPRESSION:
                list(, $op, $left, $right, $inParens) = $value;
                $opName = isset(static::$operatorNames[$op]) ? static::$operatorNames[$op] : $op;
                $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right);
                $left = $this->reduce($left, true);
                if ($op !== 'and' && $op !== 'or') {
                    $right = $this->reduce($right, true);
                }
                // special case: looks like css shorthand
                if ($opName == 'div' && !$inParens && !$inExp && isset($right[2]) && ($right[0] !== Type::T_NUMBER && $right[2] != '' || $right[0] === Type::T_NUMBER && !$right->unitless())) {
                    return $this->expToString($value);
                }
                $left = $this->coerceForExpression($left);
                $right = $this->coerceForExpression($right);
                $ltype = $left[0];
                $rtype = $right[0];
                $ucOpName = ucfirst($opName);
                $ucLType = ucfirst($ltype);
                $ucRType = ucfirst($rtype);
                // this tries:
                // 1. op[op name][left type][right type]
                // 2. op[left type][right type] (passing the op as first arg
                // 3. op[op name]
                $fn = "op{$ucOpName}{$ucLType}{$ucRType}";
                if (is_callable([$this, $fn]) || ($fn = "op{$ucLType}{$ucRType}") && is_callable([$this, $fn]) && ($passOp = true) || ($fn = "op{$ucOpName}") && is_callable([$this, $fn]) && ($genOp = true)) {
                    $coerceUnit = false;
                    if (!isset($genOp) && $left[0] === Type::T_NUMBER && $right[0] === Type::T_NUMBER) {
                        $coerceUnit = true;
                        switch ($opName) {
                            case 'mul':
                                $targetUnit = $left[2];
                                foreach ($right[2] as $unit => $exp) {
                                    $targetUnit[$unit] = (isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) + $exp;
                                }
                                break;
                            case 'div':
                                $targetUnit = $left[2];
                                foreach ($right[2] as $unit => $exp) {
                                    $targetUnit[$unit] = (isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) - $exp;
                                }
                                break;
                            case 'mod':
                                $targetUnit = $left[2];
                                break;
                            default:
                                $targetUnit = $left->unitless() ? $right[2] : $left[2];
                        }
                        if (!$left->unitless() && !$right->unitless()) {
                            $left = $left->normalize();
                            $right = $right->normalize();
                        }
                    }
                    $shouldEval = $inParens || $inExp;
                    if (isset($passOp)) {
                        $out = $this->{$fn}($op, $left, $right, $shouldEval);
                    } else {
                        $out = $this->{$fn}($left, $right, $shouldEval);
                    }
                    if (isset($out)) {
                        if ($coerceUnit && $out[0] === Type::T_NUMBER) {
                            $out = $out->coerce($targetUnit);
                        }
                        return $out;
                    }
                }
                return $this->expToString($value);
            case Type::T_UNARY:
                list(, $op, $exp, $inParens) = $value;
                $inExp = $inExp || $this->shouldEval($exp);
                $exp = $this->reduce($exp);
                if ($exp[0] === Type::T_NUMBER) {
                    switch ($op) {
                        case '+':
                            return new Node\Number($exp[1], $exp[2]);
                        case '-':
                            return new Node\Number(-$exp[1], $exp[2]);
                    }
                }
                if ($op === 'not') {
                    if ($inExp || $inParens) {
                        if ($exp === static::$false || $exp === static::$null) {
                            return static::$true;
                        }
                        return static::$false;
                    }
                    $op = $op . ' ';
                }
                return [Type::T_STRING, '', [$op, $exp]];
            case Type::T_VARIABLE:
                list(, $name) = $value;
                return $this->reduce($this->get($name));
            case Type::T_LIST:
                foreach ($value[2] as &$item) {
                    $item = $this->reduce($item);
                }
                return $value;
            case Type::T_MAP:
                foreach ($value[1] as &$item) {
                    $item = $this->reduce($item);
                }
                foreach ($value[2] as &$item) {
                    $item = $this->reduce($item);
                }
                return $value;
            case Type::T_STRING:
                foreach ($value[2] as &$item) {
                    if (is_array($item) || $item instanceof \ArrayAccess) {
                        $item = $this->reduce($item);
                    }
                }
                return $value;
            case Type::T_INTERPOLATE:
                $value[1] = $this->reduce($value[1]);
                return $value;
            case Type::T_FUNCTION_CALL:
                list(, $name, $argValues) = $value;
                return $this->fncall($name, $argValues);
            default:
                return $value;
        }
    }
Compiler