protected function reduce($value, $forExpression = false)
{
switch ($value[0]) {
case "interpolate":
$reduced = $this->reduce($value[1]);
$var = $this->compileValue($reduced);
$res = $this->reduce(array("variable", $this->vPrefix . $var));
if ($res[0] == "raw_color") {
$res = $this->coerceColor($res);
}
if (empty($value[2])) {
$res = $this->lib_unquote($res);
}
return $res;
case "variable":
$key = $value[1];
if (is_array($key)) {
$key = $this->reduce($key);
$key = $this->vPrefix . $this->compileValue($this->lib_unquote($key));
}
$seen =& $this->env->seenNames;
if (!empty($seen[$key])) {
$this->throwError("infinite loop detected: {$key}");
}
$seen[$key] = true;
$out = $this->reduce($this->get($key, self::$defaultValue));
$seen[$key] = false;
return $out;
case "list":
foreach ($value[2] as &$item) {
$item = $this->reduce($item, $forExpression);
}
return $value;
case "expression":
return $this->evaluate($value);
case "string":
foreach ($value[2] as &$part) {
if (is_array($part)) {
$strip = $part[0] == "variable";
$part = $this->reduce($part);
if ($strip) {
$part = $this->lib_unquote($part);
}
}
}
return $value;
case "escape":
list(, $inner) = $value;
return $this->lib_unquote($this->reduce($inner));
case "function":
$color = $this->funcToColor($value);
if ($color) {
return $color;
}
list(, $name, $args) = $value;
if ($name == "%") {
$name = "_sprintf";
}
$f = isset($this->libFunctions[$name]) ? $this->libFunctions[$name] : array($this, 'lib_' . $name);
if (is_callable($f)) {
if ($args[0] == 'list') {
$args = self::compressList($args[2], $args[1]);
}
$ret = call_user_func($f, $this->reduce($args, true), $this);
if (is_null($ret)) {
return array("string", "", array($name, "(", $args, ")"));
}
// convert to a typed value if the result is a php primitive
if (is_numeric($ret)) {
$ret = array('number', $ret, "");
} elseif (!is_array($ret)) {
$ret = array('keyword', $ret);
}
return $ret;
}
// plain function, reduce args
$value[2] = $this->reduce($value[2]);
return $value;
case "unary":
list(, $op, $exp) = $value;
$exp = $this->reduce($exp);
if ($exp[0] == "number") {
switch ($op) {
case "+":
return $exp;
case "-":
$exp[1] *= -1;
return $exp;
}
}
return array("string", "", array($op, $exp));
}
if ($forExpression) {
switch ($value[0]) {
case "keyword":
if ($color = $this->coerceColor($value)) {
return $color;
}
break;
case "raw_color":
return $this->coerceColor($value);
}
}
return $value;
}