Hoa central
Isotropic.php
Go to the documentation of this file.
1 <?php
2 
38 
39 use Hoa\Math;
40 use Hoa\Regex;
41 use Hoa\Ustring;
42 use Hoa\Visitor;
43 
52 class Isotropic implements Visitor\Visit
53 {
59  protected $_sampler = null;
60 
61 
62 
69  public function __construct(Math\Sampler $sampler)
70  {
71  $this->_sampler = $sampler;
72 
73  return;
74  }
75 
84  public function visit(
85  Visitor\Element $element,
86  &$handle = null,
87  $eldnah = null
88  ) {
89  switch ($element->getId()) {
90  case '#expression':
91  case '#capturing':
92  case '#noncapturing':
93  case '#namedcapturing':
94  return $element->getChild(0)->accept($this, $handle, $eldnah);
95 
96  case '#alternation':
97  case '#class':
98  return $element->getChild($this->_sampler->getInteger(
99  0,
100  $element->getChildrenNumber() - 1
101  ))->accept($this, $handle, $eldnah);
102 
103  case '#concatenation':
104  $out = null;
105 
106  foreach ($element->getChildren() as $child) {
107  $out .= $child->accept($this, $handle, $eldnah);
108  }
109 
110  return $out;
111 
112  case '#quantification':
113  $out = null;
114  $xy = $element->getChild(1)->getValueValue();
115  $x = 0;
116  $y = 0;
117 
118  switch ($element->getChild(1)->getValueToken()) {
119  case 'zero_or_one':
120  $y = 1;
121 
122  break;
123 
124  case 'zero_or_more':
125  $y = mt_rand(5, 8); // why not?
126 
127  break;
128 
129  case 'one_or_more':
130  $x = 1;
131  $y = mt_rand(5, 8); // why not?
132 
133  break;
134 
135  case 'exactly_n':
136  $x = $y = (int) substr($xy, 1, -1);
137 
138  break;
139 
140  case 'n_to_m':
141  $xy = explode(',', substr($xy, 1, -1));
142  $x = (int) trim($xy[0]);
143  $y = (int) trim($xy[1]);
144 
145  break;
146 
147  case 'n_or_more':
148  $xy = explode(',', substr($xy, 1, -1));
149  $x = (int) trim($xy[0]);
150  $y = mt_rand($x + 5, $x + 8); // why not?
151 
152  break;
153  }
154 
155  for (
156  $i = 0, $max = $this->_sampler->getInteger($x, $y);
157  $i < $max;
158  ++$i
159  ) {
160  $out .= $element->getChild(0)->accept(
161  $this,
162  $handle,
163  $eldnah
164  );
165  }
166 
167  return $out;
168 
169  case '#negativeclass':
170  $c = [];
171 
172  foreach ($element->getChildren() as $child) {
173  $c[Ustring::toCode(
174  $child->accept($this, $handle, $eldnah)
175  )] = true;
176  }
177 
178  do {
179  // all printable ASCII.
180  $i = $this->_sampler->getInteger(32, 126);
181  } while (isset($c[$i]));
182 
183  return Ustring::fromCode($i);
184 
185  case '#range':
186  $out = null;
187  $left = $element->getChild(0)->accept($this, $handle, $eldnah);
188  $right = $element->getChild(1)->accept($this, $handle, $eldnah);
189 
190  return
192  $this->_sampler->getInteger(
193  Ustring::toCode($left),
194  Ustring::toCode($right)
195  )
196  );
197 
198  case 'token':
199  $value = $element->getValueValue();
200 
201  switch ($element->getValueToken()) {
202  case 'character':
203  $value = ltrim($value, '\\');
204 
205  switch ($value) {
206  case 'a':
207  return "\a";
208 
209  case 'e':
210  return "\e";
211 
212  case 'f':
213  return "\f";
214 
215  case 'n':
216  return "\n";
217 
218  case 'r':
219  return "\r";
220 
221  case 't':
222  return "\t";
223 
224  default:
225  return
227  intval(
228  substr($value, 1)
229  )
230  );
231  }
232 
233  break;
234 
235  case 'dynamic_character':
236  $value = ltrim($value, '\\');
237 
238  switch ($value[0]) {
239  case 'x':
240  $value = trim($value, 'x{}');
241 
242  return Ustring::fromCode(
243  hexdec($value)
244  );
245 
246  default:
247  return Ustring::fromCode(octdec($value));
248  }
249 
250  break;
251 
252  case 'character_type':
253  $value = ltrim($value, '\\');
254 
255  switch ($value) {
256  case 'C':
257  return $this->_sampler->getInteger(0, 127);
258 
259  case 'd':
260  return $this->_sampler->getInteger(0, 9);
261 
262  case 's':
263  $value = $this->_sampler->getInteger(0, 1) ? 'h' : 'v';
264 
265  case 'h':
266  $h = [
267  chr(0x0009),
268  chr(0x0020),
269  chr(0x00a0)
270  ];
271 
272  return $h[$this->_sampler->getInteger(0, count($h) -1)];
273 
274  case 'v':
275  $v = [
276  chr(0x000a),
277  chr(0x000b),
278  chr(0x000c),
279  chr(0x000d)
280  ];
281 
282  return $v[$this->_sampler->getInteger(0, count($v) -1)];
283 
284  case 'w':
285  $w = array_merge(
286  range(0x41, 0x5a),
287  range(0x61, 0x7a),
288  [0x5f]
289  );
290 
291  return chr($w[$this->_sampler->getInteger(0, count($w) - 1)]);
292 
293  default:
294  return '?';
295  }
296 
297  break;
298 
299  case 'literal':
300  if ('.' === $value) {
301  $w = array_merge(
302  range(0x41, 0x5a),
303  range(0x61, 0x7a),
304  [0x5f]
305  );
306 
307  return chr($w[$this->_sampler->getInteger(0, count($w) - 1)]);
308  }
309 
310  return
311  str_replace(
312  '\\\\',
313  '\\',
314  preg_replace(
315  '#\\\(?!\\\)#',
316  '',
317  $value
318  )
319  );
320  }
321 
322  break;
323 
324  case '#internal_options':
325  break;
326 
327  default:
328  throw new Regex\Exception(
329  'Unsupported node: %s.',
330  0,
331  $element->getId()
332  );
333  }
334 
335  return;
336  }
337 }
static toCode($char)
Definition: Ustring.php:943
static fromCode($code)
Definition: Ustring.php:928
visit(Visitor\Element $element, &$handle=null, $eldnah=null)
Definition: Isotropic.php:84
__construct(Math\Sampler $sampler)
Definition: Isotropic.php:69