Пример #1
0
 /**
  * Visit an element.
  *
  * @param   \Hoa\Visitor\Element  $element    Element to visit.
  * @param   mixed                 &$handle    Handle (reference).
  * @param   mixed                 $eldnah     Handle (not reference).
  * @return  mixed
  */
 public function visit(Visitor\Element $element, &$handle = null, $eldnah = null)
 {
     $out = null;
     // Hoa\Praspel.
     if ($element instanceof Praspel\Model\Specification) {
         $variable = '$' . $element->getId();
         $out = $variable . ' = new \\Hoa\\Praspel\\Model\\Specification();' . "\n";
         foreach ($element::getAllowedClauses() as $clause) {
             if (true === $element->clauseExists($clause)) {
                 $out .= $element->getClause($clause)->accept($this, $handle, $eldnah);
             }
         }
     } elseif ($element instanceof Praspel\Model\Is) {
         $variable = '$' . $element->getParent()->getId();
         $out = "\n" . $variable . '->getClause(\'is\')->setProperty(' . $element->getProperty() . ');' . "\n";
     } elseif ($element instanceof Praspel\Model\Declaration) {
         $variable = '$' . ($eldnah ?: $element->getId());
         $out = "\n" . $variable . ' = $' . $element->getParent()->getId() . '->getClause(\'' . $element->getName() . '\');' . "\n";
         foreach ($element->getLocalVariables() as $var) {
             $out .= $var->accept($this, $handle, $eldnah);
         }
         foreach ($element->getPredicates() as $predicate) {
             $out .= $variable . '->predicate(\'' . $predicate . '\');' . "\n";
         }
     } elseif ($element instanceof Praspel\Model\Variable) {
         $variable = '$' . ($eldnah ?: $element->getClause()->getId());
         $name = $element->getName();
         $start = $variable . '[\'' . $name . '\']';
         if (true === $element->isLocal()) {
             $out .= $variable . '->let[\'' . $name . '\']';
         } else {
             $out .= $start;
         }
         if (null !== ($alias = $element->getAlias())) {
             $out .= '->domainof(\'' . $alias . '\');' . "\n";
         } else {
             $out .= '->in = ' . $element->getDomains()->accept($this, $handle, $eldnah) . ';' . "\n";
         }
         $constraints = $element->getConstraints();
         if (isset($constraints['is'])) {
             $out .= $start . '->is(\'' . implode('\', \'', $constraints['is']) . '\');' . "\n";
         }
         if (isset($constraints['contains'])) {
             foreach ($constraints['contains'] as $contains) {
                 $out .= $start . '->contains(' . $contains . ');' . "\n";
             }
         }
         if (isset($constraints['key'])) {
             foreach ($constraints['key'] as $pairs) {
                 $out .= $start . '->key(' . $pairs[0] . ')->in = ' . $pairs[1] . ';' . "\n";
             }
         }
     } elseif ($element instanceof Praspel\Model\Throwable) {
         $parent = '$' . $element->getParent()->getId();
         $_variable = $element->getId();
         $variable = '$' . $_variable;
         $out = "\n" . $variable . ' = ' . $parent . '->getClause(\'throwable\');' . "\n";
         foreach ($element as $identifier) {
             $exception = $element[$identifier];
             $start = $variable . '[\'' . $identifier . '\']';
             $out .= $start . ' = \'' . $exception->getInstanceName() . '\';' . "\n";
             if (false === $element->isDisjointed()) {
                 if (null !== ($with = $element->getWith())) {
                     $temp = $_variable . '_' . $identifier . '_with';
                     $out .= '$' . $temp . ' = ' . $variable . '->newWith();' . "\n";
                     foreach ($with->getLocalVariables() as $var) {
                         $out .= $var->accept($this, $handle, $temp);
                     }
                     foreach ($with->getPredicates() as $predicate) {
                         $out .= '$' . $temp . '->predicate(\'' . $predicate . '\');' . "\n";
                     }
                     $out .= $start . '->setWith($' . $temp . ');' . "\n";
                 }
             } else {
                 $out .= $start . '->disjunctionWith(\'' . $exception->getDisjunction() . '\');' . "\n";
             }
         }
     } elseif ($element instanceof Praspel\Model\DefaultBehavior) {
         $out = "\n" . '$' . $element->getId() . ' = $' . $element->getParent()->getId() . '->getClause(\'default\')' . "\n";
         foreach ($element::getAllowedClauses() as $clause) {
             if (true === $element->clauseExists($clause)) {
                 $out .= $element->getClause($clause)->accept($this, $handle, $eldnah);
             }
         }
     } elseif ($element instanceof Praspel\Model\Behavior) {
         $out = "\n" . '$' . $element->getId() . ' = $' . $element->getParent()->getId() . '->getClause(\'behavior\')' . '->get(\'' . $element->getIdentifier() . '\');' . "\n";
         foreach ($element::getAllowedClauses() as $clause) {
             if (true === $element->clauseExists($clause)) {
                 $out .= $element->getClause($clause)->accept($this, $handle, $eldnah);
             }
         }
     } elseif ($element instanceof Praspel\Model\Description) {
         $parent = '$' . $element->getParent()->getId();
         $variable = '$' . $element->getId();
         $out = "\n" . $variable . ' = ' . $parent . '->getClause(\'description\');' . "\n";
         foreach ($element as $example) {
             $out .= $variable . '[] = \'' . preg_replace('#(?<!\\\\)\'#', '\\\'', $example) . '\';' . "\n";
         }
     } elseif ($element instanceof Praspel\Model\Collection) {
         foreach ($element as $el) {
             $out .= $el->accept($this, $handle, $eldnah);
         }
     } elseif ($element instanceof Realdom\Disjunction) {
         $realdoms = $element->getUnflattenedRealdoms();
         if (!empty($realdoms)) {
             $oout = [];
             foreach ($realdoms as $realdom) {
                 if ($realdom instanceof Realdom\IRealdom\Constant) {
                     $oout[] = 'const(' . $realdom->accept($this, $handle, $eldnah) . ')';
                 } else {
                     $oout[] = $realdom->accept($this, $handle, $eldnah);
                 }
             }
             $out .= 'realdom()->' . implode('->or->', $oout);
         }
     } elseif ($element instanceof Realdom) {
         if ($element instanceof Realdom\IRealdom\Constant) {
             if ($element instanceof Realdom\_Array) {
                 $oout = [];
                 foreach ($element['pairs'] as $pair) {
                     $_oout = null;
                     foreach ($pair as $_pair) {
                         if (null !== $_oout) {
                             $_oout .= ', ';
                         }
                         $_oout .= $_pair->accept($this, $handle, $eldnah);
                     }
                     $oout[] = 'array(' . $_oout . ')';
                 }
                 $out .= 'array(' . implode(', ', $oout) . ')';
             } else {
                 $out .= $element->getConstantRepresentation();
             }
         } else {
             $oout = [];
             foreach ($element->getArguments() as $argument) {
                 $oout[] = $argument->accept($this, $handle, $eldnah);
             }
             $out .= $element->getName() . '(' . implode(', ', $oout) . ')';
         }
     } elseif ($element instanceof Realdom\Crate\Constant) {
         $holder = $element->getHolder();
         $praspel = $element->getPraspelRepresentation();
         $out .= '$' . $element->getDeclaration()->getId() . '[\'' . $praspel() . '\']';
     } elseif ($element instanceof Realdom\Crate\Variable) {
         $holder = $element->getVariable();
         if ($holder instanceof Praspel\Model\Variable\Implicit) {
             $out .= 'variable($' . $holder->getClause()->getId() . '->getImplicitVariable(\'' . $holder->getName() . '\'))';
         } else {
             $out .= 'variable($' . $holder->getClause()->getId() . '->getVariable(\'' . $holder->getName() . '\', true))';
         }
     } else {
         throw new Praspel\Exception\Compiler('%s is not yet implemented.', 0, get_class($element));
     }
     return $out;
 }
Пример #2
0
 /**
  * Visit an element.
  *
  * @param   \Hoa\Visitor\Element  $element    Element to visit.
  * @param   mixed                 &$handle    Handle (reference).
  * @param   mixed                 $eldnah     Handle (not reference).
  * @return  float
  */
 public function visit(Visitor\Element $element, &$handle = null, $eldnah = null)
 {
     $type = $element->getId();
     $children = $element->getChildren();
     if (null === $handle) {
         $handle = function ($x) {
             return $x;
         };
     }
     $acc =& $handle;
     switch ($type) {
         case '#function':
             $name = array_shift($children)->accept($this, $_, $eldnah);
             $function = $this->getFunction($name);
             $arguments = [];
             foreach ($children as $child) {
                 $child->accept($this, $_, $eldnah);
                 $arguments[] = $_();
                 unset($_);
             }
             $acc = function () use($function, $arguments, $acc) {
                 return $acc($function->distributeArguments($arguments));
             };
             break;
         case '#negative':
             $children[0]->accept($this, $a, $eldnah);
             $acc = function () use($a, $acc) {
                 return $acc(-$a());
             };
             break;
         case '#addition':
             $children[0]->accept($this, $a, $eldnah);
             $acc = function ($b) use($a, $acc) {
                 return $acc($a() + $b);
             };
             $children[1]->accept($this, $acc, $eldnah);
             break;
         case '#substraction':
             $children[0]->accept($this, $a, $eldnah);
             $acc = function ($b) use($a, $acc) {
                 return $acc($a()) - $b;
             };
             $children[1]->accept($this, $acc, $eldnah);
             break;
         case '#multiplication':
             $children[0]->accept($this, $a, $eldnah);
             $acc = function ($b) use($a, $acc) {
                 return $acc($a() * $b);
             };
             $children[1]->accept($this, $acc, $eldnah);
             break;
         case '#division':
             $children[0]->accept($this, $a, $eldnah);
             $parent = $element->getParent();
             if (null === $parent || $type === $parent->getId()) {
                 $acc = function ($b) use($a, $acc) {
                     if (0 === $b) {
                         throw new \RuntimeException('Division by zero is not possible.');
                     }
                     return $acc($a()) / $b;
                 };
             } else {
                 if ('#fakegroup' !== $parent->getId()) {
                     $classname = get_class($element);
                     $group = new $classname('#fakegroup', null, [$element], $parent);
                     $element->setParent($group);
                     $this->visit($group, $acc, $eldnah);
                     break;
                 } else {
                     $acc = function ($b) use($a, $acc) {
                         if (0 === $b) {
                             throw new \RuntimeException('Division by zero is not possible.');
                         }
                         return $acc($a() / $b);
                     };
                 }
             }
             $children[1]->accept($this, $acc, $eldnah);
             break;
         case '#fakegroup':
         case '#group':
             $children[0]->accept($this, $a, $eldnah);
             $acc = function () use($a, $acc) {
                 return $acc($a());
             };
             break;
         case '#variable':
             $out = $this->getVariable($children[0]->getValueValue());
             $acc = function () use($out, $acc) {
                 return $acc($out);
             };
             break;
         case 'token':
             $value = $element->getValueValue();
             $out = null;
             if ('constant' === $element->getValueToken()) {
                 if (defined($value)) {
                     $out = constant($value);
                 } else {
                     $out = $this->getConstant($value);
                 }
             } elseif ('id' === $element->getValueToken()) {
                 return $value;
             } else {
                 $out = (double) $value;
             }
             $acc = function () use($out, $acc) {
                 return $acc($out);
             };
             break;
     }
     if (null === $element->getParent()) {
         return $acc();
     }
 }
Пример #3
0
 /**
  * Evaluate given AST as CollectiveAccess expression
  *
  * @param Visitor\Element $po_element
  * @param Hoa\Core\Consistency\Xcallable $f_handle
  * @param Hoa\Core\Consistency\Xcallable $f_eldnah
  * @return mixed
  */
 public function visit(Visitor\Element $po_element, &$f_handle = null, $f_eldnah = null)
 {
     $vs_type = $po_element->getId();
     $va_children = $po_element->getChildren();
     // if no handle passed, use identity
     if ($f_handle === null) {
         $f_handle = function ($x) {
             return $x;
         };
     }
     $f_acc =& $f_handle;
     switch ($vs_type) {
         case '#function':
             $vs_name = array_shift($va_children)->accept($this, $_, $f_eldnah);
             $f_function = $this->getFunction($vs_name);
             $va_args = array();
             foreach ($va_children as $o_child) {
                 $o_child->accept($this, $_, $f_eldnah);
                 $va_args[] = $_();
                 unset($_);
             }
             $f_acc = function () use($f_function, $va_args, $f_acc) {
                 return $f_acc($f_function->distributeArguments($va_args));
             };
             break;
         case '#bool_and':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() && $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#bool_or':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() || $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#regex_match':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc((bool) @preg_match($b, $a()));
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#regex_nomatch':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc(!(bool) @preg_match($b, $a()));
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_gt':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() > $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_gte':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() >= $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_lt':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() < $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_lte':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() <= $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_neq':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() != $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#comp_eq':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() == $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#in_op':
             $vs_needle = array_shift($va_children)->accept($this, $in, $f_eldnah);
             $va_haystack = array();
             $in = $f_handle;
             $o_op = array_shift($va_children);
             if ($o_op->getValueToken() !== 'in_op') {
                 throw new Exception('invalid syntax');
             }
             foreach ($va_children as $o_child) {
                 $o_child->accept($this, $in, $f_eldnah);
                 $va_haystack[] = $in();
                 unset($in);
             }
             $f_acc = function () use($vs_needle, $va_haystack, $f_acc) {
                 return $f_acc(in_array($vs_needle, $va_haystack));
             };
             break;
         case '#notin_op':
             $vs_needle = array_shift($va_children)->accept($this, $in, $f_eldnah);
             $va_haystack = array();
             $in = $f_handle;
             $o_op = array_shift($va_children);
             if ($o_op->getValueToken() !== 'notin_op') {
                 throw new Exception('invalid syntax');
             }
             foreach ($va_children as $o_child) {
                 $o_child->accept($this, $in, $f_eldnah);
                 $va_haystack[] = $in();
                 unset($in);
             }
             $f_acc = function () use($vs_needle, $va_haystack, $f_acc) {
                 return $f_acc(!in_array($vs_needle, $va_haystack));
             };
             break;
         case '#stradd':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() . $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#negative':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function () use($a, $f_acc) {
                 return $f_acc(-$a());
             };
             break;
         case '#addition':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() + $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#substraction':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a()) - $b;
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#multiplication':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function ($b) use($a, $f_acc) {
                 return $f_acc($a() * $b);
             };
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#division':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $parent = $po_element->getParent();
             if (null === $parent || $type === $parent->getId()) {
                 $f_acc = function ($b) use($a, $f_acc) {
                     if (0 === $b) {
                         throw new \RuntimeException('Division by zero is not possible.');
                     }
                     return $f_acc($a()) / $b;
                 };
             } else {
                 if ('#fakegroup' !== $parent->getId()) {
                     $classname = get_class($po_element);
                     $group = new $classname('#fakegroup', null, [$po_element], $parent);
                     $po_element->setParent($group);
                     $this->visit($group, $f_acc, $f_eldnah);
                     break;
                 } else {
                     $f_acc = function ($b) use($a, $f_acc) {
                         if (0 === $b) {
                             throw new \RuntimeException('Division by zero is not possible.');
                         }
                         return $f_acc($a() / $b);
                     };
                 }
             }
             $va_children[1]->accept($this, $f_acc, $f_eldnah);
             break;
         case '#fakegroup':
         case '#group':
             $va_children[0]->accept($this, $a, $f_eldnah);
             $f_acc = function () use($a, $f_acc) {
                 return $f_acc($a());
             };
             break;
         case 'token':
             $value = $po_element->getValueValue();
             $token = $po_element->getValueToken();
             $out = null;
             switch ($token) {
                 case 'id':
                     return $value;
                 case 'string':
                     $out = preg_replace('/(^"|"$)/', '', $value);
                     break;
                 case 'regex':
                     // @todo maybe mangle regex?
                     $out = (string) $value;
                     break;
                 case 'variable':
                     $vs_var = mb_substr((string) $value, 1);
                     // get rid of caret ^
                     $out = $this->getVariable($vs_var);
                     if (is_array($out)) {
                         $out = join("", $out);
                     }
                     // we need to join multiple values
                     break;
                 default:
                     $out = (double) $value;
                     break;
             }
             $f_acc = function () use($out, $f_acc) {
                 return $f_acc($out);
             };
             break;
     }
     return $f_acc();
 }