AutorÃa | Ultima modificación | Ver Log |
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Configurable Reports
* A Moodle block for creating customizable reports
* @package blocks
* @author: Juan leyva <http://www.twitter.com/jleyvadelgado>
* @date: 2009
*/
/*
evaluate postfix notation
modified to perform bitwise-like operations in arrays
* => & => array_intersect
+ => | => array_merge
- => ^ => array_diff
*/
class EvalWise extends EvalMath {
public $data = array();
public $index = 0;
public function set_data($data) {
$this->data = $data;
$this->index = count($this->data);
}
public function pfx($tokens, $vars = array()) {
if ($tokens == false) {
return false;
}
$stack = new \EvalMathStack;
foreach ($tokens as $token) {
// If the token is a function, pop arguments off the stack, hand them to the function, and push the result back on.
if (is_array($token)) { // It's a function!
$fnn = $token['fnn'];
$count = $token['argcount'];
if (in_array($fnn, $this->fb)) { // Built-in function.
if (is_null($op1 = $stack->pop())) {
return $this->trigger("internal error");
}
$fnn = preg_replace("/^arc/", "a", $fnn); // For the 'arc' trig synonyms.
if ($fnn == 'ln') {
$fnn = 'log';
}
eval('$stack->push(' . $fnn . '($op1));'); // Perfectly safe eval().
} else if (array_key_exists($fnn, $this->fc)) { // Calc emulation function.
// Get args.
$args = array();
for ($i = $count - 1; $i >= 0; $i--) {
if (is_null($args[] = $stack->pop())) {
return $this->trigger('internal error');
}
}
$res = call_user_func(array('EvalMathCalcEmul', $fnn), $args);
if ($res === false) {
return $this->trigger("internal error");
}
$stack->push($res);
} else if (array_key_exists($fnn, $this->f)) { // User function.
// Get args.
$args = array();
for ($i = count($this->f[$fnn]['args']) - 1; $i >= 0; $i--) {
if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) {
return $this->trigger('internal error');
}
}
$stack->push($this->pfx($this->f[$fnn]['func'], $args)); // Yay... recursion!!!!
}
} else if (in_array($token, array('+', '-', '*', '/', '^'), true)) {
// If the token is a binary operator, pop two values off the stack, do the operation, and push the result back on.
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 '+':
$this->index += 1;
$stack->push($this->index);
$this->data[$this->index] = array_merge($this->data[$op1], $this->data[$op2]);
break;
case '-':
$this->index += 1;
$stack->push($this->index);
$this->data[$this->index] = array_diff($this->data[$op1], $this->data[$op2]);
break;
case '*':
$this->index += 1;
$stack->push($this->index);
$this->data[$this->index] = array_intersect($this->data[$op1], $this->data[$op2]);
break;
}
} else if ($token == "_") {
// If the token is a unary operator, pop one value off the stack, do the operation, and push it back on.
$stack->push(-1 * $stack->pop());
} else {
// If the token is a number or variable, push it on the stack.
if (is_numeric($token)) {
$stack->push($token);
} else if (array_key_exists($token, $this->v)) {
$stack->push($this->v[$token]);
} else if (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");
}
$last = $stack->pop();
if (isset($this->data[$last])) {
return $this->data[$last];
} else {
return false;
}
}
}