/** * @param Expr\ClosureUse $node * * @return string */ public function convert(Expr\ClosureUse $node) { if ($node->byRef) { $this->logger->logNode('Zephir not support reference parameters for now. Stay tuned for https://github.com/phalcon/zephir/issues/203', $node, $this->dispatcher->getMetadata()->getClass()); } return $this->reservedWordReplacer->replace($node->var); }
/** * @param Stmt\ClassMethod $node * * @return string */ public function convert(Stmt\ClassMethod $node) { $types = $this->typeFinder->getTypes($node, $this->dispatcher->getMetadata()); foreach ($node->params as $param) { if ($param->byRef === true) { $this->logger->logIncompatibility('reference', sprintf('Reference not supported in parametter (var "%s")', $param->name), $param, $this->dispatcher->getMetadata()->getClass()); } } if ($node->byRef) { $this->logger->logIncompatibility('reference', 'Reference not supported', $node, $this->dispatcher->getMetadata()->getClass()); } $this->dispatcher->setLastMethod($node->name); $stmt = $this->dispatcher->pModifiers($node->type) . 'function ' . $node->name . '('; $varsInMethodSign = array(); if (isset($types['params']) === true) { $params = array(); foreach ($types['params'] as $type) { $varsInMethodSign[] = $type['name']; $stringType = $this->printType($type); $params[] = (!empty($stringType) ? $stringType . ' ' : '') . '' . $type['name'] . ($type['default'] === null ? '' : ' = ' . $this->dispatcher->p($type['default'])); } $stmt .= implode(', ', $params); } $stmt .= ')'; $stmt .= $this->printReturn($node, $types); $stmt .= (null !== $node->stmts ? "\n{" . $this->printVars($node, $varsInMethodSign) . $this->dispatcher->pStmts($node->stmts) . "\n}" : ';') . "\n"; return $stmt; }
/** * @param null|string $lastMethod * @param integer $number */ public function createClosureClass(Expr\Closure $node, $lastMethod, $number) { $this->logger->trace(__METHOD__ . ' ' . __LINE__, $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); $name = $this->dispatcher->getMetadata()->getClass() . $lastMethod . "Closure" . $this->N2L($number); $this->logger->logNode(sprintf('Closure does not exist in Zephir, class "%s" with __invoke is created', $name), $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); return array('name' => $name, 'code' => $this->createClass($name, $this->dispatcher->getMetadata()->getNamespace(), $node)); }
/** * Pretty prints a node. * * @param \PhpParser\Node $node Node to be pretty printed * * @return string Pretty printed node */ public function p($node) { if (null === $node) { return; } $this->logger->trace('p' . $node->getType(), $node, $this->getMetadata()->getFullQualifiedNameClass()); return $this->getClass('p' . $node->getType())->convert($node); }
/** * @param Stmt\If_ $node * * @return string */ public function convert(Stmt\If_ $node) { $collected = $this->assignManipulator->collectAssignInCondition($node->cond); $node->cond = $this->assignManipulator->transformAssignInConditionTest($node->cond); if (empty($node->stmts)) { $node->stmts = array(new Stmt\Echo_(array(new Scalar\String("not allowed")))); $this->logger->logNode('Empty if not allowed, add "echo not allowed"', $node, $this->dispatcher->getMetadata()->getClass()); } return implode(";\n", $collected['extracted']) . "\n" . 'if ' . $this->dispatcher->p($node->cond) . ' {' . $this->dispatcher->pStmts($node->stmts) . "\n" . '}' . $this->implodeElseIfs($node); }
/** * @param Stmt\If_ $node * * @return string */ public function convert(Stmt\If_ $node) { $collected = $this->assignManipulator->collectAssignInCondition($node->cond); $node->cond = $this->assignManipulator->transformAssignInConditionTest($node->cond); if (empty($node->stmts)) { $node->stmts = array(new Stmt\Echo_(array(new Scalar\String_('not allowed')))); $this->logger->logIncompatibility('Empty if', 'Empty if not allowed, add "echo not allowed"', $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); } return $collected->getCollected() . 'if ' . $this->dispatcher->p($node->cond) . ' {' . $this->dispatcher->pStmts($node->stmts) . "\n" . '}' . $this->implodeElseIfs($node); }
/** * Pretty prints a node. * * @param \PhpParser\Node $node Node to be pretty printed * * @return string Pretty printed node */ public function p() { $args = func_get_args(); $node = $args[0]; if (null === $node) { return; } $this->logger->trace('p' . $node->getType(), $node, $this->getMetadata()->getFullQualifiedNameClass()); $class = $this->getClass('p' . $node->getType()); return call_user_func_array(array($class, "convert"), $args); }
/** * @param Stmt\Property $node * * @return string */ public function convert(Stmt\Property $node) { foreach ($node->props as $key => $prop) { $prop->name = $this->reservedWordReplacer->replace($prop->name); $node->props[$key] = $prop; } if ($node->props[0]->default instanceof Expr\Array_ && $node->isStatic() === true) { $node->type = $node->type - Stmt\Class_::MODIFIER_STATIC; $this->dispatcher->moveToNonStaticVar($node->props[0]->name); $this->logger->logNode("Static attribute default array not supported in zephir, (see #188). Changed into non static. ", $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); } return $this->dispatcher->pModifiers($node->type) . $this->dispatcher->pCommaSeparated($node->props) . ';'; }
/** * @param string $dir * * @return array */ public function convertDirectory($dir, $recursive = true, $filterFileName = null) { $zephirCode = array(); $fileExtension = '.php'; $classes = array(); $files = $this->findFiles($dir); $count = iterator_count($files); $this->logger->log('Collect class names'); $progress = $this->logger->progress($count); foreach ($files as $filei) { $file = $filei[0]; try { $classes[$file] = $this->classCollector->collect($this->parser->parse(file_get_contents($file)), $file); } catch (\Exception $e) { $this->logger->log(sprintf('<error>Could not convert file' . "\n" . '"%s"' . "\n" . 'cause : %s %s %s</error>' . "\n", $file, $e->getMessage(), $e->getFile(), $e->getLine())); } $progress->advance(); } $progress->finish(); $this->logger->log("\nConvert php to zephir"); $progress = $this->logger->progress(count($classes)); foreach ($classes as $phpFile => $class) { if ($filterFileName !== null) { if (basename($phpFile, '.php') !== $filterFileName) { continue; } } $phpCode = file_get_contents($phpFile); $fileName = basename($phpFile, '.php'); try { $converted = $this->convertCode($phpCode, $phpFile, $classes); $converted['class'] = $class; } catch (\Exception $e) { $this->logger->log(sprintf('Could not convert file "%s" cause : %s %s %s' . "\n", $phpFile, $e->getMessage(), $e->getFile(), $e->getLine())); $progress->advance(); continue; } $zephirCode[$phpFile] = array_merge($converted, array('phpPath' => substr($phpFile, 0, strrpos($phpFile, '/')), 'fileName' => $fileName, 'fileDestination' => $converted['class'] . '.zep')); $zephirCode[$phpFile]['fileDestination'] = strtolower(str_replace('\\', '/', $zephirCode[$phpFile]['fileDestination'])); foreach ($converted['additionalClass'] as $aditionalClass) { $zephirCode[$phpFile . $aditionalClass['name']] = array_merge(array('fileName' => $aditionalClass['name'], 'zephir' => $aditionalClass['code'], 'fileDestination' => strtolower(str_replace('\\', '/', $converted['namespace']) . '/' . $aditionalClass['name']) . '.zep', 'destination' => strtolower(str_replace('\\', '/', $converted['namespace']) . '/'))); } $progress->advance(); } $progress->finish(); $this->logger->log("\n"); return $zephirCode; }
/** * @param string $actualNamespace * @param Tag $tag * * @return string */ private function findType(Tag $tag, $actualNamespace, array $use, array $classes) { $rawType = $tag->getType(); if ($rawType === 'integer') { $rawType = 'int'; } $primitiveTypes = array('string', 'int', 'integer', 'float', 'double', 'bool', 'boolean', 'array', 'null', 'callable', 'scalar', 'void', 'object'); $excludedType = array('mixed', 'callable', 'callable[]', 'scalar', 'scalar[]', 'void', 'object', 'self', 'resource', 'true'); if (in_array($rawType, $excludedType) === true || count(explode('|', $rawType)) !== 1) { return array('value' => '', 'isClass' => false); } $arrayOfPrimitiveTypes = array_map(function ($val) { return $val . '[]'; }, $primitiveTypes); if (preg_match("/^[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*\$/", $rawType) === 0) { // this is a typo $this->logger->log(sprintf('Type "%s" does not exist in docblock', $rawType)); $type = array('value' => '', 'isClass' => false); } elseif (in_array(strtolower($rawType), $primitiveTypes)) { $type = array('value' => strtolower($rawType), 'isClass' => false); } elseif (in_array(strtolower($rawType), $arrayOfPrimitiveTypes)) { $type = array('value' => strtolower($rawType), 'isClass' => false); } else { // considered as class $type = array('value' => $rawType, 'isClass' => true); } return $type; }
/** * @param Assign $node * @param Expr $leftNode * @param Expr $rightNode * @param string $operatorString */ private function arrayDimFetchCase($node, $leftNode, $rightNode, $operatorString, $precedence, $associativity) { $this->logger->trace(self::getType() . ' ' . __LINE__, $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); $head = ''; if ($leftNode instanceof ArrayDimFetch) { if (false === ($splitedArray = $this->arrayManipulator->arrayNeedToBeSplit($leftNode))) { $leftString = $this->dispatcher->pPrec($leftNode, $precedence, $associativity, 1); } else { $result = $this->dispatcher->pExpr_ArrayDimFetch($leftNode, true); $head .= $result['head']; $leftString = $result['lastExpr']; } } else { $leftString = $this->dispatcher->pPrec($leftNode, $precedence, $associativity, -1); } if ($rightNode instanceof ArrayDimFetch) { if (false === ($splitedArray = $this->arrayManipulator->arrayNeedToBeSplit($rightNode))) { $rightString = $this->dispatcher->pPrec($rightNode, $precedence, $associativity, 1); } else { $result = $this->dispatcher->pExpr_ArrayDimFetch($rightNode, true); $head .= $result['head']; $rightString = $result['lastExpr']; } } elseif ($this->isSomething($rightNode)) { $this->logger->trace(self::getType() . ' ' . __LINE__, $node, $this->dispatcher->getMetadata()->getFullQualifiedNameClass()); // @TODO add test case for each $rightString = $this->dispatcher->pPrec($rightNode, $precedence, $associativity, 1); } else { $head .= $this->dispatcher->pPrec($rightNode, $precedence, $associativity, 1) . ";\n"; $rightString = $this->dispatcher->p($rightNode->var); } return $head . 'let ' . $leftString . $operatorString . $rightString; }
public function convert(Expr\ArrayDimFetch $node, $returnAsArray = false) { $collected = $this->arrayManipulator->arrayNeedToBeSplit($node); if ($node->var instanceof Expr\StaticPropertyFetch) { if ($node->var->class->parts[0] === 'self') { $node->var = new Expr\PropertyFetch(new Expr\Variable('this'), $node->var->name); $this->logger->logNode("Change StaticProperty into PropertyFetch due to #188", $node); } else { $this->logger->logNode("StaticProperty on array not supported, see #188", $node); } } if ($collected !== false) { return $this->splitArray($collected, $returnAsArray); } else { $result = $this->dispatcher->pVarOrNewExpr($node->var) . '[' . (null !== $node->dim ? $this->dispatcher->p($node->dim) : '') . ']'; if ($returnAsArray === true) { return array('head' => '', 'lastExpr' => $result); } else { return $result; } } }
/** * @param Expr\ArrayDimFetch $node */ private function findComplexArrayDimFetch($node, $collected = array()) { if ($this->isInvalidInArrayDimFetch($node) === true) { if ($node->dim instanceof Expr\FuncCall) { $this->logger->trace(__METHOD__ . ' ' . __LINE__ . ' Non supported funccall in array', $node, $this->dispatcher->getMetadata()->getClass()); } else { $collected[] = array('expr' => $this->dispatcher->p($node->dim) . ";\n", 'splitTab' => true, 'var' => $this->dispatcher->p($node->dim->var)); } } else { if ($node->dim === null) { $collected[] = array('expr' => $this->dispatcher->p($node->var), 'splitTab' => false); } else { $collected[] = array('expr' => $this->dispatcher->p($node->dim), 'splitTab' => false); } } if ($node->var instanceof Expr\ArrayDimFetch) { $collected = $this->findComplexArrayDimFetch($node->var, $collected); } else { $collected[] = $node->var; } return $collected; }
/** * @param CodeCollectorInterface $codeCollector * @param Logger $logger * @param string $filterFileName * * @return array */ public function convert(CodeCollectorInterface $codeCollector, Logger $logger, $filterFileName = null) { $zephirCode = array(); $classes = array(); $files = $codeCollector->getCode(); $count = count($files); $codes = array(); $logger->log('Collect class names'); $progress = $logger->progress($count); foreach ($files as $fileName => $fileContent) { try { $codes[$fileName] = $this->parser->parse($fileContent); $classes[$fileName] = $this->classCollector->collect($codes[$fileName], $fileName); } catch (\Exception $e) { $logger->log(sprintf('<error>Could not convert file' . "\n" . '"%s"' . "\n" . 'cause : %s %s %s</error>' . "\n", $fileName, $e->getMessage(), $e->getFile(), $e->getLine())); } $progress->advance(); } $progress->finish(); $logger->log("\nConvert php to zephir"); $progress = $logger->progress(count($classes)); foreach ($classes as $phpFile => $class) { if ($filterFileName !== null) { if (basename($phpFile, '.php') !== $filterFileName) { continue; } } $phpCode = $codes[$phpFile]; $zephirFile = pathinfo($phpFile, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . pathinfo($phpFile, PATHINFO_FILENAME) . '.zep'; $fileName = basename($phpFile, '.php'); try { $converted = $this->convertCode($phpCode, $this->classCollector, $logger, $phpFile, $classes); $converted['class'] = $class; } catch (\Exception $e) { $logger->log(sprintf('Could not convert file "%s" cause : %s %s %s' . "\n", $phpFile, $e->getMessage(), $e->getFile(), $e->getLine())); $progress->advance(); continue; } $zephirCode[$phpFile] = array_merge($converted, array('phpPath' => substr($phpFile, 0, strrpos($phpFile, '/')), 'fileName' => $fileName, 'fileDestination' => $zephirFile)); $zephirCode[$phpFile]['fileDestination'] = str_replace('\\', '/', $zephirCode[$phpFile]['fileDestination']); foreach ($converted['additionalClass'] as $aditionalClass) { $zephirCode[$phpFile . $aditionalClass['name']] = array_merge(array('fileName' => $aditionalClass['name'], 'zephir' => $aditionalClass['code'], 'fileDestination' => str_replace('\\', '/', $converted['namespace']) . '/' . $aditionalClass['name'] . '.zep', 'destination' => str_replace('\\', '/', $converted['namespace']) . '/')); } $progress->advance(); } $progress->finish(); $logger->log("\n"); return $zephirCode; }