Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Configurable Reports
19
 * A Moodle block for creating customizable reports
20
 * @package blocks
21
 * @author: Juan leyva <http://www.twitter.com/jleyvadelgado>
22
 * @date: 2009
23
 */
24
 
25
/*
26
    evaluate postfix notation
27
    modified to perform bitwise-like operations in arrays
28
    * => & => array_intersect
29
    + => | => array_merge
30
    - => ^ => array_diff
31
 */
32
 
33
class EvalWise extends EvalMath {
34
 
35
    public $data = array();
36
    public $index = 0;
37
 
38
    public function set_data($data) {
39
        $this->data = $data;
40
        $this->index = count($this->data);
41
    }
42
 
43
    public function pfx($tokens, $vars = array()) {
44
 
45
        if ($tokens == false) {
46
            return false;
47
        }
48
 
49
        $stack = new \EvalMathStack;
50
 
51
        foreach ($tokens as $token) {
52
 
53
            // If the token is a function, pop arguments off the stack, hand them to the function, and push the result back on.
54
            if (is_array($token)) { // It's a function!
55
                $fnn = $token['fnn'];
56
                $count = $token['argcount'];
57
                if (in_array($fnn, $this->fb)) { // Built-in function.
58
                    if (is_null($op1 = $stack->pop())) {
59
                        return $this->trigger("internal error");
60
                    }
61
                    $fnn = preg_replace("/^arc/", "a", $fnn); // For the 'arc' trig synonyms.
62
                    if ($fnn == 'ln') {
63
                        $fnn = 'log';
64
                    }
65
                    eval('$stack->push(' . $fnn . '($op1));'); // Perfectly safe eval().
66
                } else if (array_key_exists($fnn, $this->fc)) { // Calc emulation function.
67
                    // Get args.
68
                    $args = array();
69
                    for ($i = $count - 1; $i >= 0; $i--) {
70
                        if (is_null($args[] = $stack->pop())) {
71
                            return $this->trigger('internal error');
72
                        }
73
                    }
74
                    $res = call_user_func(array('EvalMathCalcEmul', $fnn), $args);
75
                    if ($res === false) {
76
                        return $this->trigger("internal error");
77
                    }
78
                    $stack->push($res);
79
                } else if (array_key_exists($fnn, $this->f)) { // User function.
80
                    // Get args.
81
                    $args = array();
82
                    for ($i = count($this->f[$fnn]['args']) - 1; $i >= 0; $i--) {
83
                        if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) {
84
                            return $this->trigger('internal error');
85
                        }
86
                    }
87
                    $stack->push($this->pfx($this->f[$fnn]['func'], $args)); // Yay... recursion!!!!
88
                }
89
            } else if (in_array($token, array('+', '-', '*', '/', '^'), true)) {
90
                // If the token is a binary operator, pop two values off the stack, do the operation, and push the result back on.
91
                if (is_null($op2 = $stack->pop())) {
92
                    return $this->trigger('internal error');
93
                }
94
                if (is_null($op1 = $stack->pop())) {
95
                    return $this->trigger('internal error');
96
                }
97
 
98
                switch ($token) {
99
                    case '+':
100
                        $this->index += 1;
101
                        $stack->push($this->index);
102
                        $this->data[$this->index] = array_merge($this->data[$op1], $this->data[$op2]);
103
                        break;
104
                    case '-':
105
                        $this->index += 1;
106
                        $stack->push($this->index);
107
                        $this->data[$this->index] = array_diff($this->data[$op1], $this->data[$op2]);
108
                        break;
109
                    case '*':
110
                        $this->index += 1;
111
                        $stack->push($this->index);
112
                        $this->data[$this->index] = array_intersect($this->data[$op1], $this->data[$op2]);
113
                        break;
114
                }
115
 
116
            } else if ($token == "_") {
117
                // If the token is a unary operator, pop one value off the stack, do the operation, and push it back on.
118
                $stack->push(-1 * $stack->pop());
119
            } else {
120
                // If the token is a number or variable, push it on the stack.
121
                if (is_numeric($token)) {
122
                    $stack->push($token);
123
                } else if (array_key_exists($token, $this->v)) {
124
                    $stack->push($this->v[$token]);
125
                } else if (array_key_exists($token, $vars)) {
126
                    $stack->push($vars[$token]);
127
                } else {
128
                    return $this->trigger("undefined variable '$token'");
129
                }
130
            }
131
        }
132
        // When we're out of tokens, the stack should have a single element, the final result.
133
        if ($stack->count != 1) {
134
            return $this->trigger("internal error");
135
        }
136
        $last = $stack->pop();
137
        if (isset($this->data[$last])) {
138
            return $this->data[$last];
139
        } else {
140
            return false;
141
        }
142
    }
143
}