titanscssc::reduce PHP Method

reduce() protected method

protected reduce ( $value, $inExp = false )
    protected function reduce($value, $inExp = false)
    {
        list($type) = $value;
        switch ($type) {
            case "exp":
                list(, $op, $left, $right, $inParens) = $value;
                $opName = isset(self::$operatorNames[$op]) ? self::$operatorNames[$op] : $op;
                $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right);
                $left = $this->reduce($left, true);
                $right = $this->reduce($right, true);
                // only do division in special cases
                if ($opName == "div" && !$inParens && !$inExp) {
                    if ($left[0] != "color" && $right[0] != "color") {
                        return $this->expToString($value);
                    }
                }
                $left = $this->coerceForExpression($left);
                $right = $this->coerceForExpression($right);
                $ltype = $left[0];
                $rtype = $right[0];
                // 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_{$opName}_{$ltype}_{$rtype}";
                if (is_callable(array($this, $fn)) || ($fn = "op_{$ltype}_{$rtype}") && is_callable(array($this, $fn)) && ($passOp = true) || ($fn = "op_{$opName}") && is_callable(array($this, $fn)) && ($genOp = true)) {
                    $unitChange = false;
                    if (!isset($genOp) && $left[0] == "number" && $right[0] == "number") {
                        if ($opName == "mod" && $right[2] != "") {
                            $this->throwError("Cannot modulo by a number with units: {$right['1']}{$right['2']}.");
                        }
                        $unitChange = true;
                        $emptyUnit = $left[2] == "" || $right[2] == "";
                        $targetUnit = "" != $left[2] ? $left[2] : $right[2];
                        if ($opName != "mul") {
                            $left[2] = "" != $left[2] ? $left[2] : $targetUnit;
                            $right[2] = "" != $right[2] ? $right[2] : $targetUnit;
                        }
                        if ($opName != "mod") {
                            $left = $this->normalizeNumber($left);
                            $right = $this->normalizeNumber($right);
                        }
                        if ($opName == "div" && !$emptyUnit && $left[2] == $right[2]) {
                            $targetUnit = "";
                        }
                        if ($opName == "mul") {
                            $left[2] = "" != $left[2] ? $left[2] : $right[2];
                            $right[2] = "" != $right[2] ? $right[2] : $left[2];
                        } elseif ($opName == "div" && $left[2] == $right[2]) {
                            $left[2] = "";
                            $right[2] = "";
                        }
                    }
                    $shouldEval = $inParens || $inExp;
                    if (isset($passOp)) {
                        $out = $this->{$fn}($op, $left, $right, $shouldEval);
                    } else {
                        $out = $this->{$fn}($left, $right, $shouldEval);
                    }
                    if (!is_null($out)) {
                        if ($unitChange && $out[0] == "number") {
                            $out = $this->coerceUnit($out, $targetUnit);
                        }
                        return $out;
                    }
                }
                return $this->expToString($value);
            case "unary":
                list(, $op, $exp, $inParens) = $value;
                $inExp = $inExp || $this->shouldEval($exp);
                $exp = $this->reduce($exp);
                if ($exp[0] == "number") {
                    switch ($op) {
                        case "+":
                            return $exp;
                        case "-":
                            $exp[1] *= -1;
                            return $exp;
                    }
                }
                if ($op == "not") {
                    if ($inExp || $inParens) {
                        if ($exp == self::$false) {
                            return self::$true;
                        } else {
                            return self::$false;
                        }
                    } else {
                        $op = $op . " ";
                    }
                }
                return array("string", "", array($op, $exp));
            case "var":
                list(, $name) = $value;
                return $this->reduce($this->get($name));
            case "list":
                foreach ($value[2] as &$item) {
                    $item = $this->reduce($item);
                }
                return $value;
            case "string":
                foreach ($value[2] as &$item) {
                    if (is_array($item)) {
                        $item = $this->reduce($item);
                    }
                }
                return $value;
            case "interpolate":
                $value[1] = $this->reduce($value[1]);
                return $value;
            case "fncall":
                list(, $name, $argValues) = $value;
                // user defined function?
                $func = $this->get(self::$namespaces["function"] . $name, false);
                if ($func) {
                    $this->pushEnv();
                    // set the args
                    if (isset($func->args)) {
                        $this->applyArguments($func->args, $argValues);
                    }
                    // throw away lines and children
                    $tmp = (object) array("lines" => array(), "children" => array());
                    $ret = $this->compileChildren($func->children, $tmp);
                    $this->popEnv();
                    return is_null($ret) ? self::$defaultValue : $ret;
                }
                // built in function
                if ($this->callBuiltin($name, $argValues, $returnValue)) {
                    return $returnValue;
                }
                // need to flatten the arguments into a list
                $listArgs = array();
                foreach ((array) $argValues as $arg) {
                    if (empty($arg[0])) {
                        $listArgs[] = $this->reduce($arg[1]);
                    }
                }
                return array("function", $name, array("list", ",", $listArgs));
            default:
                return $value;
        }
    }
titanscssc