Passed
Push — master ( 766df6...286284 )
by Roman
55s
created

Frame::valueOf()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace PeacefulBit\Slate\Core;
4
5
use function Nerd\Common\Arrays\toString;
6
use function Nerd\Common\Functional\tail;
7
8
use PeacefulBit\Slate\Exceptions\EvaluatorException;
9
10
class Frame
11
{
12
    /**
13
     * @var Evaluator
14
     */
15
    private $evaluator;
16
17
    /**
18
     * @var self
19
     */
20
    private $parent = null;
21
22
    /**
23
     * @var array
24
     */
25
    private $table = [];
26
27
    /**
28
     * @var array
29
     */
30
    private $modules = [];
31
32
    /**
33
     * @param Evaluator $evaluator
34
     * @param array $table
35
     * @param Frame|null $parent
36
     */
37
    public function __construct(Evaluator $evaluator, array $table = [], Frame $parent = null)
38
    {
39
        $this->evaluator = $evaluator;
40
        $this->table = $table;
41
        $this->parent = $parent;
42
    }
43
44
    /**
45
     * @param mixed $node
46
     * @return mixed
47
     */
48
    public function evaluate($node)
49
    {
50
//        if (!$node instanceof Nodes\NodeInterface) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
51
//            return $node;
52
//        }
53
54
//        $iter = tail(function ($node) use (&$iter) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
55
//            if ($node instanceof Nodes\CallExpression) {
56
//                return $iter($node->evaluate($this));
57
//            }
58
//            return $node;
59
//        });
60
//
61
//        return $iter($node->evaluate($this));
62
        return $node->evaluate($this);
63
    }
64
65
    /**
66
     * @param mixed $node
67
     * @return mixed
68
     */
69
    public function valueOf($node)
70
    {
71
//        $iter = tail(function ($node) use (&$iter) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
72
//            if ($node instanceof Nodes\Node) {
73
//                return $iter($this->evaluate($node));
74
//            }
75
//            return $node;
76
//        });
77
//
78
//        return $iter($node);
79
        return $this->evaluate($node);
80
    }
81
82
    /**
83
     * @param mixed $node
84
     * @return mixed
85
     */
86
    public function __invoke($node)
87
    {
88
        return $this->evaluate($node);
89
    }
90
91
    /**
92
     * @return bool
93
     */
94
    public function isRoot(): bool
95
    {
96
        return is_null($this->parent);
97
    }
98
99
    /**
100
     * @param string $key
101
     * @return bool
102
     */
103
    public function has(string $key): bool
104
    {
105
        $iter = tail(function ($key, Frame $frame) use (&$iter) {
106
            if (array_key_exists($key, $frame->table)) {
107
                return true;
108
            }
109
            if ($frame->isRoot()) {
110
                return false;
111
            }
112
            return $iter($key, $frame->parent);
113
        });
114
115
        return $iter($key, $this);
116
    }
117
118
    /**
119
     * @param string $key
120
     * @return mixed|null
121
     * @throws EvaluatorException
122
     */
123
    public function get(string $key)
124
    {
125
        $iter = tail(function ($key, Frame $frame) use (&$iter) {
126
            if (array_key_exists($key, $frame->table)) {
127
                return $frame->table[$key];
128
            }
129
            if ($frame->isRoot()) {
130
                throw new EvaluatorException("Symbol \"$key\" not defined");
131
            }
132
            return $iter($key, $frame->parent);
133
        });
134
135
        return $iter($key, $this);
136
    }
137
138
    /**
139
     * @param string $key
140
     * @param mixed $value
141
     * @return void
142
     */
143
    public function set(string $key, $value)
144
    {
145
        $this->table[$key] = $value;
146
    }
147
148
    /**
149
     * @param array $path
150
     * @return mixed
151
     * @throws EvaluatorException
152
     */
153
    public function getFromModule(array $path)
154
    {
155
        $node = array_reduce($path, function ($acc, $item) {
156
            return (is_array($acc) && array_key_exists($item, $acc)) ? $acc[$item] : null;
157
        }, $this->modules);
158
159
        if (is_null($node)) {
160
            throw new EvaluatorException("Module not imported");
161
        }
162
163
        return $node;
164
    }
165
166
    /**
167
     * @param array $table
168
     * @return Frame
169
     */
170
    public function extend(array $table = []): Frame
171
    {
172
        return new self($this->evaluator, $table, $this);
173
    }
174
175
    /**
176
     * @param array $table
177
     * @return Frame
178
     */
179
    public function replace(array $table = []): Frame
180
    {
181
        $this->table = array_merge($this->table, $table);
182
        return $this;
183
    }
184
185
    /**
186
     * @return string
187
     */
188
    public function __toString()
189
    {
190
        return toString(array_keys($this->table));
191
    }
192
193
    /**
194
     * @return Evaluator
195
     */
196
    public function getEvaluator(): Evaluator
197
    {
198
        return $this->evaluator;
199
    }
200
201
    /**
202
     * @param string $name Module name to use
203
     * @param null|string $alias Module alias name
204
     */
205
    public function useModule(string $name, string $alias = null)
206
    {
207
        $module = $this->getEvaluator()->getModule($name);
208
        $this->modules[$alias ?? $name] = $module;
209
    }
210
211
    /**
212
     * @param string $name Module name to import
213
     * @param array|null $functions List of functions to import
214
     */
215
    public function importModule(string $name, array $functions = null)
216
    {
217
        $module = $this->getEvaluator()->getModule($name);
218
219
        $importFunctions = $functions ?? array_keys($module);
220
221
        array_walk($importFunctions, function ($fn) use (&$module) {
222
            $this->set($fn, $module[$fn]);
223
        });
224
    }
225
}
226