Frame::get()   A
last analyzed

Complexity

Conditions 3
Paths 1

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 1
nop 1
dl 0
loc 14
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 $table
150
     * @return Frame
151
     */
152
    public function extend(array $table = []): Frame
153
    {
154
        return new self($this->evaluator, $table, $this);
155
    }
156
157
    /**
158
     * @param array $table
159
     * @return Frame
160
     */
161
    public function replace(array $table = []): Frame
162
    {
163
        $this->table = array_merge($this->table, $table);
164
        return $this;
165
    }
166
167
    /**
168
     * @return string
169
     */
170
    public function __toString()
171
    {
172
        return toString(array_keys($this->table));
173
    }
174
175
    /**
176
     * @return Evaluator
177
     */
178
    public function getEvaluator(): Evaluator
179
    {
180
        return $this->evaluator;
181
    }
182
183
    /**
184
     * @param $name
185
     * @param null|string $alias
186
     */
187
    public function useModule(string $name, string $alias = null)
188
    {
189
        $module = $this->getEvaluator()->getModule($name);
190
        $this->modules[$alias ?? $name] = $module;
191
    }
192
193
    /**
194
     * @param string $name
195
     * @param array|null $functions
196
     */
197
    public function importModule(string $name, array $functions = null)
198
    {
199
        $module = $this->getEvaluator()->getModule($name);
200
201
        $importFunctions = $functions ?? array_keys($module);
202
203
        array_walk($importFunctions, function ($fn) use (&$module) {
204
            $this->set($fn, $module[$fn]);
205
        });
206
    }
207
}
208