PluginProbe
Media Cloud Sync / 1.2.12
Media Cloud Sync v1.2.12
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / s3 / JmesPath / TreeCompiler.php

TreeCompiler.php in Media Cloud Sync 1.2.12, at includes/sdk/s3/JmesPath/TreeCompiler.php

226 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\JmesPath;
4
5 /**
6 * Tree visitor used to compile JMESPath expressions into native PHP code.
7 */
8 class TreeCompiler
9 {
10 private $indentation;
11 private $source;
12 private $vars;
13 /**
14 * @param array $ast AST to compile.
15 * @param string $fnName The name of the function to generate.
16 * @param string $expr Expression being compiled.
17 *
18 * @return string
19 */
20 public function visit(array $ast, $fnName, $expr)
21 {
22 $this->vars = [];
23 $this->source = $this->indentation = '';
24 $this->write("<?php\n")->write('use JmesPath\\TreeInterpreter as Ti;')->write('use JmesPath\\FnDispatcher as Fd;')->write('use JmesPath\\Utils;')->write('')->write('function %s(Ti $interpreter, $value) {', $fnName)->indent()->dispatch($ast)->write('')->write('return $value;')->outdent()->write('}');
25 return $this->source;
26 }
27 /**
28 * @param array $node
29 * @return mixed
30 */
31 private function dispatch(array $node)
32 {
33 return $this->{"visit_{$node['type']}"}($node);
34 }
35 /**
36 * Creates a monotonically incrementing unique variable name by prefix.
37 *
38 * @param string $prefix Variable name prefix
39 *
40 * @return string
41 */
42 private function makeVar($prefix)
43 {
44 if (!isset($this->vars[$prefix])) {
45 $this->vars[$prefix] = 0;
46 return '$' . $prefix;
47 }
48 return '$' . $prefix . ++$this->vars[$prefix];
49 }
50 /**
51 * Writes the given line of source code. Pass positional arguments to write
52 * that match the format of sprintf.
53 *
54 * @param string $str String to write
55 * @return $this
56 */
57 private function write($str)
58 {
59 $this->source .= $this->indentation;
60 if (\func_num_args() == 1) {
61 $this->source .= $str . "\n";
62 return $this;
63 }
64 $this->source .= \vsprintf($str, \array_slice(\func_get_args(), 1)) . "\n";
65 return $this;
66 }
67 /**
68 * Decreases the indentation level of code being written
69 * @return $this
70 */
71 private function outdent()
72 {
73 $this->indentation = \substr($this->indentation, 0, -4);
74 return $this;
75 }
76 /**
77 * Increases the indentation level of code being written
78 * @return $this
79 */
80 private function indent()
81 {
82 $this->indentation .= ' ';
83 return $this;
84 }
85 private function visit_or(array $node)
86 {
87 $a = $this->makeVar('beforeOr');
88 return $this->write('%s = $value;', $a)->dispatch($node['children'][0])->write('if (!$value && $value !== "0" && $value !== 0) {')->indent()->write('$value = %s;', $a)->dispatch($node['children'][1])->outdent()->write('}');
89 }
90 private function visit_and(array $node)
91 {
92 $a = $this->makeVar('beforeAnd');
93 return $this->write('%s = $value;', $a)->dispatch($node['children'][0])->write('if ($value || $value === "0" || $value === 0) {')->indent()->write('$value = %s;', $a)->dispatch($node['children'][1])->outdent()->write('}');
94 }
95 private function visit_not(array $node)
96 {
97 return $this->write('// Visiting not node')->dispatch($node['children'][0])->write('// Applying boolean not to result of not node')->write('$value = !Utils::isTruthy($value);');
98 }
99 private function visit_subexpression(array $node)
100 {
101 return $this->dispatch($node['children'][0])->write('if ($value !== null) {')->indent()->dispatch($node['children'][1])->outdent()->write('}');
102 }
103 private function visit_field(array $node)
104 {
105 $arr = '$value[' . \var_export($node['value'], \true) . ']';
106 $obj = '$value->{' . \var_export($node['value'], \true) . '}';
107 $this->write('if (is_array($value) || $value instanceof \\ArrayAccess) {')->indent()->write('$value = isset(%s) ? %s : null;', $arr, $arr)->outdent()->write('} elseif ($value instanceof \\stdClass) {')->indent()->write('$value = isset(%s) ? %s : null;', $obj, $obj)->outdent()->write("} else {")->indent()->write('$value = null;')->outdent()->write("}");
108 return $this;
109 }
110 private function visit_index(array $node)
111 {
112 if ($node['value'] >= 0) {
113 $check = '$value[' . $node['value'] . ']';
114 return $this->write('$value = (is_array($value) || $value instanceof \\ArrayAccess)' . ' && isset(%s) ? %s : null;', $check, $check);
115 }
116 $a = $this->makeVar('count');
117 return $this->write('if (is_array($value) || ($value instanceof \\ArrayAccess && $value instanceof \\Countable)) {')->indent()->write('%s = count($value) + %s;', $a, $node['value'])->write('$value = isset($value[%s]) ? $value[%s] : null;', $a, $a)->outdent()->write('} else {')->indent()->write('$value = null;')->outdent()->write('}');
118 }
119 private function visit_literal(array $node)
120 {
121 return $this->write('$value = %s;', \var_export($node['value'], \true));
122 }
123 private function visit_pipe(array $node)
124 {
125 return $this->dispatch($node['children'][0])->dispatch($node['children'][1]);
126 }
127 private function visit_multi_select_list(array $node)
128 {
129 return $this->visit_multi_select_hash($node);
130 }
131 private function visit_multi_select_hash(array $node)
132 {
133 $listVal = $this->makeVar('list');
134 $value = $this->makeVar('prev');
135 $this->write('if ($value !== null) {')->indent()->write('%s = [];', $listVal)->write('%s = $value;', $value);
136 $first = \true;
137 foreach ($node['children'] as $child) {
138 if (!$first) {
139 $this->write('$value = %s;', $value);
140 }
141 $first = \false;
142 if ($node['type'] == 'multi_select_hash') {
143 $this->dispatch($child['children'][0]);
144 $key = \var_export($child['value'], \true);
145 $this->write('%s[%s] = $value;', $listVal, $key);
146 } else {
147 $this->dispatch($child);
148 $this->write('%s[] = $value;', $listVal);
149 }
150 }
151 return $this->write('$value = %s;', $listVal)->outdent()->write('}');
152 }
153 private function visit_function(array $node)
154 {
155 $value = $this->makeVar('val');
156 $args = $this->makeVar('args');
157 $this->write('%s = $value;', $value)->write('%s = [];', $args);
158 foreach ($node['children'] as $arg) {
159 $this->dispatch($arg);
160 $this->write('%s[] = $value;', $args)->write('$value = %s;', $value);
161 }
162 return $this->write('$value = Fd::getInstance()->__invoke("%s", %s);', $node['value'], $args);
163 }
164 private function visit_slice(array $node)
165 {
166 return $this->write('$value = !is_string($value) && !Utils::isArray($value)')->write(' ? null : Utils::slice($value, %s, %s, %s);', \var_export($node['value'][0], \true), \var_export($node['value'][1], \true), \var_export($node['value'][2], \true));
167 }
168 private function visit_current(array $node)
169 {
170 return $this->write('// Visiting current node (no-op)');
171 }
172 private function visit_expref(array $node)
173 {
174 $child = \var_export($node['children'][0], \true);
175 return $this->write('$value = function ($value) use ($interpreter) {')->indent()->write('return $interpreter->visit(%s, $value);', $child)->outdent()->write('};');
176 }
177 private function visit_flatten(array $node)
178 {
179 $this->dispatch($node['children'][0]);
180 $merged = $this->makeVar('merged');
181 $val = $this->makeVar('val');
182 $this->write('// Visiting merge node')->write('if (!Utils::isArray($value)) {')->indent()->write('$value = null;')->outdent()->write('} else {')->indent()->write('%s = [];', $merged)->write('foreach ($value as %s) {', $val)->indent()->write('if (is_array(%s) && isset(%s[0])) {', $val, $val)->indent()->write('%s = array_merge(%s, %s);', $merged, $merged, $val)->outdent()->write('} elseif (%s !== []) {', $val)->indent()->write('%s[] = %s;', $merged, $val)->outdent()->write('}')->outdent()->write('}')->write('$value = %s;', $merged)->outdent()->write('}');
183 return $this;
184 }
185 private function visit_projection(array $node)
186 {
187 $val = $this->makeVar('val');
188 $collected = $this->makeVar('collected');
189 $this->write('// Visiting projection node')->dispatch($node['children'][0])->write('');
190 if (!isset($node['from'])) {
191 $this->write('if (!is_array($value) || !($value instanceof \\stdClass)) { $value = null; }');
192 } elseif ($node['from'] == 'object') {
193 $this->write('if (!Utils::isObject($value)) { $value = null; }');
194 } elseif ($node['from'] == 'array') {
195 $this->write('if (!Utils::isArray($value)) { $value = null; }');
196 }
197 $this->write('if ($value !== null) {')->indent()->write('%s = [];', $collected)->write('foreach ((array) $value as %s) {', $val)->indent()->write('$value = %s;', $val)->dispatch($node['children'][1])->write('if ($value !== null) {')->indent()->write('%s[] = $value;', $collected)->outdent()->write('}')->outdent()->write('}')->write('$value = %s;', $collected)->outdent()->write('}');
198 return $this;
199 }
200 private function visit_condition(array $node)
201 {
202 $value = $this->makeVar('beforeCondition');
203 return $this->write('%s = $value;', $value)->write('// Visiting condition node')->dispatch($node['children'][0])->write('// Checking result of condition node')->write('if (Utils::isTruthy($value)) {')->indent()->write('$value = %s;', $value)->dispatch($node['children'][1])->outdent()->write('} else {')->indent()->write('$value = null;')->outdent()->write('}');
204 }
205 private function visit_comparator(array $node)
206 {
207 $value = $this->makeVar('val');
208 $a = $this->makeVar('left');
209 $b = $this->makeVar('right');
210 $this->write('// Visiting comparator node')->write('%s = $value;', $value)->dispatch($node['children'][0])->write('%s = $value;', $a)->write('$value = %s;', $value)->dispatch($node['children'][1])->write('%s = $value;', $b);
211 if ($node['value'] == '==') {
212 $this->write('$value = Utils::isEqual(%s, %s);', $a, $b);
213 } elseif ($node['value'] == '!=') {
214 $this->write('$value = !Utils::isEqual(%s, %s);', $a, $b);
215 } else {
216 $this->write('$value = (is_int(%s) || is_float(%s)) && (is_int(%s) || is_float(%s)) && %s %s %s;', $a, $a, $b, $b, $a, $node['value'], $b);
217 }
218 return $this;
219 }
220 /** @internal */
221 public function __call($method, $args)
222 {
223 throw new \RuntimeException(\sprintf('Invalid node encountered: %s', \json_encode($args[0])));
224 }
225 }
226