/** * Visit an element. * * @access public * @param \Hoa\Visitor\Element $element Element to visit. * @param mixed &$handle Handle (reference). * @param mixed $eldnah Handle (not reference). * * @return \Hoa\Ruler\Model * * @throw \Hoa\Ruler\Exception\Interpreter */ public function visit(Visitor\Element $element, &$handle = null, $eldnah = null) { $id = $element->getId(); $variable = false !== $eldnah; switch ($id) { case '#expression': $this->root = new Ruler\Model(); $this->root->expression = $element->getChild(0)->accept($this, $handle, $eldnah); return $this->root; case '#operation': $children = $element->getChildren(); $left = $children[0]->accept($this, $handle, $eldnah); $right = $children[2]->accept($this, $handle, $eldnah); $name = $children[1]->accept($this, $handle, false); return $this->root->_operator($name, [$left, $right], false); case '#variable_access': $children = $element->getChildren(); $name = $children[0]->accept($this, $handle, $eldnah); array_shift($children); foreach ($children as $child) { $_child = $child->accept($this, $handle, $eldnah); switch ($child->getId()) { case '#attribute_access': $name->attribute($_child); break; } } return $name; case '#attribute_access': return $element->getChild(0)->accept($this, $handle, false); case '#array_declaration': $out = []; foreach ($element->getChildren() as $child) { $out[] = $child->accept($this, $handle, $eldnah); } return $out; case '#function_call': $children = $element->getChildren(); $name = $children[0]->accept($this, $handle, false); array_shift($children); $arguments = []; foreach ($children as $child) { $arguments[] = $child->accept($this, $handle, $eldnah); } return $this->root->_operator($name, $arguments, true); case '#and': case '#or': case '#xor': $name = substr($id, 1); $children = $element->getChildren(); $left = $children[0]->accept($this, $handle, $eldnah); $right = $children[1]->accept($this, $handle, $eldnah); return $this->root->operation($name, array($left, $right)); case '#not': return $this->root->operation('not', array($element->getChild(0)->accept($this, $handle, $eldnah))); case 'token': $token = $element->getValueToken(); $value = $element->getValueValue(); switch ($token) { case 'identifier': return true === $variable ? $this->root->variable($value) : $value; case 'named_parameter': return new Parameter(substr($value, 1)); case 'positional_parameter': $index = $this->nextParameterIndex++; return new Parameter($index); case 'true': return true; case 'false': return false; case 'null': return null; case 'float': return floatval($value); case 'integer': return intval($value); case 'string': return str_replace('\\' . $value[0], $value[0], substr($value, 1, -1)); default: throw new Ruler\Exception\Interpreter('Token %s is unknown.', 0, $token); } default: throw new Ruler\Exception\Interpreter('Element %s is unknown.', 1, $id); } }
/** * Visit an element. * * @param \Hoa\Visitor\Element $element Element to visit. * @param mixed &$handle Handle (reference). * @param mixed $eldnah Handle (not reference). * @return mixed * @throws \Hoa\Regex\Exception */ public function visit(Visitor\Element $element, &$handle = null, $eldnah = null) { switch ($element->getId()) { case '#expression': case '#capturing': case '#noncapturing': case '#namedcapturing': return $element->getChild(0)->accept($this, $handle, $eldnah); case '#alternation': case '#class': return $element->getChild($this->_sampler->getInteger(0, $element->getChildrenNumber() - 1))->accept($this, $handle, $eldnah); case '#concatenation': $out = null; foreach ($element->getChildren() as $child) { $out .= $child->accept($this, $handle, $eldnah); } return $out; case '#quantification': $out = null; $xy = $element->getChild(1)->getValueValue(); $x = 0; $y = 0; switch ($element->getChild(1)->getValueToken()) { case 'zero_or_one': $y = 1; break; case 'zero_or_more': $y = mt_rand(5, 8); // why not? break; case 'one_or_more': $x = 1; $y = mt_rand(5, 8); // why not? break; case 'exactly_n': $x = $y = (int) substr($xy, 1, -1); break; case 'n_to_m': $xy = explode(',', substr($xy, 1, -1)); $x = (int) trim($xy[0]); $y = (int) trim($xy[1]); break; case 'n_or_more': $xy = explode(',', substr($xy, 1, -1)); $x = (int) trim($xy[0]); $y = mt_rand($x + 5, $x + 8); // why not? break; } for ($i = 0, $max = $this->_sampler->getInteger($x, $y); $i < $max; ++$i) { $out .= $element->getChild(0)->accept($this, $handle, $eldnah); } return $out; case '#negativeclass': $c = []; foreach ($element->getChildren() as $child) { $c[Ustring::toCode($child->accept($this, $handle, $eldnah))] = true; } do { // all printable ASCII. $i = $this->_sampler->getInteger(32, 126); } while (isset($c[$i])); return Ustring::fromCode($i); case '#range': $out = null; $left = $element->getChild(0)->accept($this, $handle, $eldnah); $right = $element->getChild(1)->accept($this, $handle, $eldnah); return Ustring::fromCode($this->_sampler->getInteger(Ustring::toCode($left), Ustring::toCode($right))); case 'token': $value = $element->getValueValue(); switch ($element->getValueToken()) { case 'character': $value = ltrim($value, '\\'); switch ($value) { case 'a': return "\\a"; case 'e': return ""; case 'f': return "\f"; case 'n': return "\n"; case 'r': return "\r"; case 't': return "\t"; default: return Ustring::fromCode(intval(substr($value, 1))); } break; case 'dynamic_character': $value = ltrim($value, '\\'); switch ($value[0]) { case 'x': $value = trim($value, 'x{}'); return Ustring::fromCode(hexdec($value)); default: return Ustring::fromCode(octdec($value)); } break; case 'character_type': $value = ltrim($value, '\\'); if ('s' === $value) { $value = $this->_sampler->getInteger(0, 1) ? 'h' : 'v'; } switch ($value) { case 'C': return $this->_sampler->getInteger(0, 127); case 'd': return $this->_sampler->getInteger(0, 9); case 'h': $h = [Ustring::fromCode(0x9), Ustring::fromCode(0x20), Ustring::fromCode(0xa0)]; return $h[$this->_sampler->getInteger(0, count($h) - 1)]; case 'v': $v = [Ustring::fromCode(0xa), Ustring::fromCode(0xb), Ustring::fromCode(0xc), Ustring::fromCode(0xd)]; return $v[$this->_sampler->getInteger(0, count($v) - 1)]; case 'w': $w = array_merge(range(0x41, 0x5a), range(0x61, 0x7a), [0x5f]); return Ustring::fromCode($w[$this->_sampler->getInteger(0, count($w) - 1)]); default: return '?'; } break; case 'literal': if ('.' === $value) { $w = array_merge(range(0x41, 0x5a), range(0x61, 0x7a), [0x5f]); return Ustring::fromCode($w[$this->_sampler->getInteger(0, count($w) - 1)]); } return str_replace('\\\\', '\\', preg_replace('#\\\\(?!\\\\)#', '', $value)); } break; case '#internal_options': break; default: throw new Regex\Exception('Unsupported node: %s.', 0, $element->getId()); } return; }
/** * Visit an element. * * @param \Hoa\Visitor\Element $element Element to visit. * @param mixed &$handle Handle (reference). * @param mixed $eldnah Handle (not reference). * @return mixed * @throws \Hoa\Praspel\Exception\Interpreter */ public function visit(Visitor\Element $element, &$handle = null, $eldnah = null) { $id = $element->getId(); switch ($id) { case '#specification': $this->_clause = $this->_current = $this->_root = new Praspel\Model\Specification(); if (null !== ($classname = $this->getBindedClass())) { $this->_root->bindToClass($classname); } foreach ($element->getChildren() as $child) { $child->accept($this, $handle, $eldnah); } return $this->_root; case '#is': $this->_clause = $this->_root->getClause('is'); foreach ($element->getChildren() as $child) { $this->_clause->addProperty($this->_clause->getPropertyValue($child->accept($this, $handle, $eldnah))); } break; case '#requires': case '#ensures': case '#invariant': $this->_clause = $this->_current->getClause(substr($id, 1)); foreach ($element->getChildren() as $child) { $child->accept($this, $handle, $eldnah); } break; case '#behavior': $children = $element->getChildren(); $child0 = array_shift($children); $identifier = $child0->accept($this, $handle, false); $previous = $this->_current; $this->_clause = $this->_current = $this->_current->getClause('behavior')->get($identifier); foreach ($children as $child) { $child->accept($this, $handle, $eldnah); } $this->_current = $previous; break; case '#default': $children = $element->getChildren(); $previous = $this->_current; $this->_clause = $this->_current = $this->_current->getClause('default'); foreach ($children as $child) { $child->accept($this, $handle, $eldnah); } $this->_current = $previous; break; case '#throwable': $this->_clause = $this->_current->getClause('throwable'); $identifier = null; foreach ($element->getChildren() as $child) { switch ($child->getId()) { case '#exception_identifier': $_identifier = $child->getChild(1)->accept($this, $handle, false); $_instanceof = $child->getChild(0)->accept($this, $handle, false); $this->_clause[$_identifier] = $_instanceof; if (null === $identifier) { $identifier = $_identifier; } else { $this->_clause[$_identifier]->disjunctionWith($identifier); } break; case '#exception_with': $old = $this->_clause; $this->_clause = $old->newWith(); foreach ($child->getChildren() as $_child) { $_child->accept($this, $handle, $eldnah); } $old[$identifier]->setWith($this->_clause); $this->_clause = $old; break; } } break; case '#description': $this->_clause = $this->_root->getClause('description'); $this->_clause[] = $element->getChild(0)->accept($this, $handle, $eldnah); break; case '#declaration': $left = $element->getChild(0)->accept($this, $handle, false); $right = $element->getChild(1)->accept($this, $handle, $eldnah); $variable = $left; if ($right instanceof Praspel\Model\Variable) { $right = realdom()->variable($right); } $this->_clause[$variable]->in = $right; break; case '#local_declaration': $left = $element->getChild(0)->accept($this, $handle, false); $right = $element->getChild(1)->accept($this, $handle, $eldnah); $variable = $left; if ($right instanceof Praspel\Model\Variable) { $right = realdom()->variable($right); } $this->_clause->let[$variable]->in = $right; break; case '#qualification': $children = $element->getChildren(); $variable = $this->_clause[array_shift($children)->accept($this, $handle, false)]; foreach ($children as $child) { $variable->is($child->accept($this, $handle, false)); } break; case '#contains': $variable = $element->getChild(0)->accept($this, $handle, false); $value = $element->getChild(1)->accept($this, $handle, false); $this->_clause[$variable]->contains($value); break; case '#domainof': $left = $element->getChild(0)->accept($this, $handle, false); $right = $element->getChild(1)->accept($this, $handle, false); $this->_clause[$left]->domainof($right); break; case '#predicate': $this->_clause->predicate($element->getChild(0)->accept($this, $handle, $eldnah)); break; case '#disjunction': $disjunction = realdom(); foreach ($element->getChildren() as $child) { $value = $child->accept($this, $handle, $eldnah); if ($value instanceof Realdom\Disjunction) { $disjunction[] = $value; } elseif ($value instanceof Praspel\Model\Variable) { $disjunction->variable($value); } else { $disjunction->const($value); } } return $disjunction; case '#realdom': $children = $element->getChildren(); $child0 = array_shift($children); $name = $child0->accept($this, $handle, false); $arguments = []; foreach ($children as $child) { $argument = $child->accept($this, $handle, $eldnah); if ($argument instanceof Realdom\Disjunction) { $realdoms = $argument->getRealdoms(); $argument = $realdoms[0]; } $arguments[] = $argument; } return realdom()->_call($name, $arguments); case '#concatenation': $string = null; foreach ($element->getChildren() as $child) { $string .= $child->accept($this, $handle, $eldnah); } return $string; case '#array': $array = []; foreach ($element->getChildren() as $child) { if ('#pair' === $child->getId()) { $key = $child->getChild(0)->accept($this, $handle, $eldnah); $value = $child->getChild(1)->accept($this, $handle, $eldnah); $array[] = [$key, $value]; continue; } $key = realdom()->natural(0, 1); $value = $child->accept($this, $handle, $eldnah); $array[] = [$key, $value]; } return $array; case '#range': $left = $element->getChild(0)->accept($this, $handle, $eldnah); $right = $element->getChild(1)->accept($this, $handle, $eldnah); if (is_float($left) || is_float($right)) { return realdom()->boundfloat(floatval($left), floatval($right)); } return realdom()->boundinteger(intval($left), intval($right)); case '#left_range': $left = $element->getChild(0)->accept($this, $handle, $eldnah); if (is_float($left)) { return realdom()->boundfloat($left); } return realdom()->boundinteger($left); case '#right_range': $right = $element->getChild(0)->accept($this, $handle, $eldnah); if (is_float($right)) { return realdom()->boundfloat(null, $right); } return realdom()->boundinteger(null, $right); case '#arrayaccessbykey': $variable = $element->getChild(0)->accept($this, $handle, $eldnah); $key = $element->getChild(1)->accept($this, $handle, $eldnah); $this->_clause[$variable]->key($key); return $variable; case '#dynamic_resolution': $value = null; foreach ($element->getChildren() as $child) { if (null !== $value) { $value .= '->'; } $value .= $child->accept($this, $handle, false); } if (false !== $eldnah) { return $this->_clause->getVariable($value, true); } return $value; case '#self_identifier': case '#static_identifier': case '#parent_identifier': $identifier = substr($id, 1, strpos($id, '_', 1) - 1); foreach ($element->getChildren() as $child) { $identifier .= '::' . $child->accept($this, $handle, $eldnah); } return $identifier; case '#old': $value = '\\old(' . $element->getChild(0)->accept($this, $handle, false) . ')'; if (false !== $eldnah) { return $this->_clause->getVariable($value); } return $value; case '#result': return '\\result'; case '#classname': $classname = []; foreach ($element->getChildren() as $child) { $classname[] = $child->accept($this, $handle, $eldnah); } return implode('\\', $classname); case '#nowdoc': case '#heredoc': return $element->getChild(1)->accept($this, $handle, $eldnah); case '#regex': $regex = $element->getChild(0)->accept($this, $handle, $eldnah); if (true === $element->childExists(1)) { $length = $element->getChild(1)->accept($this, $handle, $eldnah); } return realdom()->regex($regex); case '#class': $classname = $element->getChild(0)->accept($this, $handle, false); return realdom()->class($classname); case 'token': $tId = $element->getValueToken(); $value = $element->getValueValue(); switch ($tId) { case 'identifier': if (false !== $eldnah) { return $this->getIdentifier($value); } return $value; case 'this': if (false !== $eldnah) { return $this->_root->getImplicitVariable($value); } return $value; case 'content': case 'pure': case 'result': return $value; case 'default': return …; case 'null': return null; case 'true': return true; case 'false': return false; case 'binary': $int = intval(substr($value, strpos($value, 'b') + 1), 2); if ('-' === $value[0]) { return -$int; } return $int; case 'octal': $int = intval(substr($value, strpos($value, '0') + 1), 8); if ('-' === $value[0]) { return -$int; } return $int; case 'hexa': $value = strtolower($value); $int = intval(substr($value, strpos($value, 'x') + 1), 16); if ('-' === $value[0]) { return -$int; } return $int; case 'decimal': if (true === ctype_digit(ltrim($value, '+-'))) { return intval($value); } return floatval($value); case 'escaped': switch ($value[1]) { case 'n': return "\n"; case 'r': return "\r"; case 't': return "\t"; case 'v': return "\v"; case 'e': return ""; case 'f': return "\f"; case 'b': return "[D"; case 'x': return Ustring::fromCode(hexdec($value)); case '\\': return $value[1]; default: return Ustring::fromCode(octdec($value)); } case 'accepted': case 'string': case 'regex': return $value; default: throw new Praspel\Exception\Interpreter('Token %s is not yet implemented.', 1, $tId); } break; default: throw new Praspel\Exception\Interpreter('Element %s is unknown.', 2, $id); } }