function ctools_math_expr::pfx

Evaluate a prefix-operator stack expression.

Parameters

array $tokens: The array of token values to evaluate. A token is a string value representing either an operation to perform, a variable, or a value. Literal values are checked using is_numeric(), or a value that starts with a double-quote; functions and variables by existence in the appropriate tables. If FALSE is passed in the function terminates immediately, returning FALSE.

array $vars: Additional variable values to use when evaluating the expression. These variables do not override internal variables with the same name.

Return value

bool|mixed The expression's value, otherwise FALSE is returned if there is an error detected unless php error handling intervenes: see suppress_error.

1 call to ctools_math_expr::pfx()
ctools_math_expr::evaluate in includes/math-expr.inc
Evaluate the expression.

File

includes/math-expr.inc, line 652

Class

ctools_math_expr
ctools_math_expr Class.

Code

public function pfx(array $tokens, array $vars = array()) {
    if ($tokens == FALSE) {
        return FALSE;
    }
    $stack = new ctools_math_expr_stack();
    foreach ($tokens as $token) {
        // If the token is a binary operator, pop two values off the stack, do
        // the operation, and push the result back on again.
        if (in_array($token, $this->binaryops)) {
            if (is_null($op2 = $stack->pop())) {
                return $this->trigger('internal error');
            }
            if (is_null($op1 = $stack->pop())) {
                return $this->trigger('internal error');
            }
            switch ($token) {
                case '+':
                    $stack->push($op1 + $op2);
                    break;
                case '-':
                    $stack->push($op1 - $op2);
                    break;
                case '*':
                    $stack->push($op1 * $op2);
                    break;
                case '/':
                    if ($op2 == 0) {
                        return $this->trigger('division by zero');
                    }
                    $stack->push($op1 / $op2);
                    break;
                case '^':
                    $stack->push(pow($op1, $op2));
                    break;
                case '==':
                    $stack->push((int) ($op1 == $op2));
                    break;
                case '!=':
                    $stack->push((int) ($op1 != $op2));
                    break;
                case '<=':
                    $stack->push((int) ($op1 <= $op2));
                    break;
                case '<':
                    $stack->push((int) ($op1 < $op2));
                    break;
                case '>=':
                    $stack->push((int) ($op1 >= $op2));
                    break;
                case '>':
                    $stack->push((int) ($op1 > $op2));
                    break;
            }
        }
        elseif ($token === "_") {
            $stack->push(-1 * $stack->pop());
        }
        elseif (preg_match("/^([a-z]\\w*)\\(\$/", (string) $token, $matches)) {
            $fnn = $matches[1];
            // Check for a built-in function.
            if (isset($this->funcs[$fnn])) {
                $args = array();
                // Collect all required args from the stack.
                for ($i = 0; $i < $this->funcs[$fnn]['arguments']; $i++) {
                    if (is_null($op1 = $stack->pop())) {
                        return $this->trigger("function {$fnn} missing argument {$i}");
                    }
                    $args[] = $op1;
                }
                // If func allows additional args, collect them too, stopping on a
                // NULL arg.
                if (!empty($this->funcs[$fnn]['max arguments'])) {
                    for (; $i < $this->funcs[$fnn]['max arguments']; $i++) {
                        $arg = $stack->pop();
                        if (!isset($arg)) {
                            break;
                        }
                        $args[] = $arg;
                    }
                }
                $stack->push(call_user_func_array($this->funcs[$fnn]['function'], array_reverse($args)));
            }
            elseif (isset($fnn, $this->userfuncs)) {
                $args = array();
                for ($i = count($this->userfuncs[$fnn]['args']) - 1; $i >= 0; $i--) {
                    $value = $stack->pop();
                    $args[$this->userfuncs[$fnn]['args'][$i]] = $value;
                    if (is_null($value)) {
                        return $this->trigger('internal error');
                    }
                }
                // yay... recursion!!!!
                $stack->push($this->pfx($this->userfuncs[$fnn]['func'], $args));
            }
        }
        else {
            if (is_numeric($token) || $token[0] == '"') {
                $stack->push($token);
            }
            elseif (array_key_exists($token, $this->vars)) {
                $stack->push($this->vars[$token]);
            }
            elseif (array_key_exists($token, $vars)) {
                $stack->push($vars[$token]);
            }
            else {
                return $this->trigger("undefined variable '{$token}'");
            }
        }
    }
    // When we're out of tokens, the stack should have a single element, the
    // final result:
    if ($stack->count() !== 1) {
        return $this->trigger('internal error');
    }
    return $stack->pop();
}