PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/generator.php

https://github.com/bjori/PHit
PHP | 368 lines | 336 code | 30 blank | 2 comment | 58 complexity | d83688eecce0170bbb72370864bf4fda MD5 | raw file
Possible License(s): BSD-2-Clause
  1. <?php
  2. function render($include, array $data = null) {
  3. if ($data) {
  4. extract($data);
  5. }
  6. ob_start();
  7. include $include;
  8. return ob_get_clean();
  9. }
  10. function untab($text) {
  11. $text = preg_replace("/^\t/m", "", $text);
  12. $text = preg_replace("/^ /m", "\t", $text);
  13. return $text;
  14. }
  15. function map_iface($i) {
  16. $map = [
  17. "IteratorAggregate" => "zend_ce_aggregate",
  18. "Iterator" => "spl_ce_Iterator",
  19. "Countable" => "spl_ce_Countable",
  20. ];
  21. $user = substr($i, strrpos($i, "\\")+1);
  22. $user = strtolower($user);
  23. return isset($map[$i]) ? $map[$i] : "php_phongo_{$user}_ce";
  24. }
  25. if ($_SERVER["argc"] !== 2 || !is_file($_SERVER["argv"][1])) {
  26. printf("Usage:\n\tphp -dauto_prepend_file=README.md %s php_phongo.c.in >php_phongo.c\n",
  27. basename($_SERVER["argv"][0]));
  28. var_dump($argc,$argv);
  29. exit(-1);
  30. }
  31. $interfaces = $classes = array();
  32. foreach(array(get_declared_interfaces(), get_declared_classes()) as $entry) {
  33. foreach ($entry as $iface) {
  34. $reflection = new ReflectionClass($iface);
  35. if ($reflection->isInternal()) {
  36. fprintf(STDERR, "Skipping $iface\n");
  37. continue;
  38. }
  39. if ($reflection->isInterface()) {
  40. $interfaces[$reflection->getShortName()] = $iface;
  41. } else {
  42. $classes[$reflection->getShortName()] = $iface;
  43. }
  44. }
  45. }
  46. foreach(array($interfaces, $classes) as $entry) {
  47. foreach ($entry as $iface) {
  48. $declarations = "";
  49. $registrations = "";
  50. $implementations = "";
  51. $reflection = new ReflectionClass($iface);
  52. $pos = strrpos($iface, "\\");
  53. $ns = substr($iface, 0, $pos);
  54. $class = substr($iface, $pos + 1);
  55. $ns = str_replace("\\", "\\\\", $ns);
  56. $config = isset($$class) ? $$class : array();
  57. $docblock = untab($reflection->getDocComment())."\n";
  58. if ($reflection->isInterface()) {
  59. $classorinterface = "interface";
  60. $config["generate_handlers"] = false;
  61. } else {
  62. $classorinterface = "class";
  63. }
  64. $isfinalclass = $reflection->isFinal();
  65. if ($parent = $reflection->getParentClass()) {
  66. $parent = $parent->getName();
  67. } else {
  68. $parent = "NULL";
  69. }
  70. $registrations .= render("generator/$classorinterface.php",
  71. compact("ns", "class", "docblock", "parent", "isfinalclass", "config"));
  72. $entries = "";
  73. $arginfos = "";
  74. if (($impl_ifaces = $reflection->getInterfaceNames())) {
  75. $faces = array();
  76. foreach($impl_ifaces as $face) {
  77. if ($face == "Traversable") {
  78. continue;
  79. }
  80. foreach($faces as $f) {
  81. $rf = null;
  82. try {
  83. $rf = new ReflectionClass($f);
  84. } catch(Exception $e) {
  85. }
  86. if (!$rf || $rf->implementsInterface($face)) {
  87. continue 2;
  88. }
  89. }
  90. $faces[] = map_iface($face);
  91. }
  92. $ni = count($faces);
  93. $impl_list = implode(", ", $faces);
  94. $registrations .= render("generator/implements.php",
  95. compact("class", "ni", "impl_list", "config"));
  96. }
  97. foreach ($reflection->getConstants() as $cname => $cvalue) {
  98. $registrations .= render("generator/constant.php",
  99. compact("class", "cname", "cvalue", "config"));
  100. }
  101. foreach ($reflection->getMethods() as $m) {
  102. $zpp = array();
  103. /* @var $m ReflectionMethod */
  104. if ($m->getDeclaringClass()->getName() !== $iface) {
  105. continue;
  106. }
  107. $method = $m->getName();
  108. $docblock = untab($m->getDocComment())."\n";
  109. $template = $reflection->isInterface() ? "abstract_me.php" : "me.php";
  110. $flags = "ZEND_ACC_PUBLIC";
  111. $flags .= $reflection->isFinal() ? "|ZEND_ACC_FINAL" : "";
  112. $entries .= render("generator/$template",
  113. compact("class", "method", "docblock", "flags", "config"));
  114. $args = "";
  115. $req_args = 0;
  116. $protoargs = "";
  117. $n = 0;
  118. foreach ($m->getParameters() as $n => $param) {
  119. if ($n > 0) {
  120. if ($param->isOptional()) {
  121. $protoargs .= "[, ";
  122. } else {
  123. $protoargs .= ", ";
  124. }
  125. }
  126. /* @var $param ReflectionParameter */
  127. $arg = $param->getName();
  128. $null = (int) $param->allowsNull();
  129. $by_ref = (int) $param->isPassedByReference();
  130. try {
  131. $param->getClass();
  132. } catch(Exception $e) {
  133. echo "Broken typehint:\n";
  134. echo $class, "::", $m->getName();
  135. exit;
  136. }
  137. list($type, $short, $argprotohint) = get_zpp_type($n+1, $m->getNumberOfParameters(), $param, $docblock);
  138. if ($param->isArray()) {
  139. $args .= render("generator/ai_arr.php",
  140. compact("class", "method", "arg", "null", "by_ref", "config"));
  141. $protoargs .= "array \$$arg";
  142. if ($param->isOptional()) {
  143. $protoargs .= " = array()";
  144. }
  145. } elseif (($arg_class = $param->getClass())) {
  146. $arg_class = $arg_class->getName();
  147. $protoargs .= "$arg_class \$$arg";
  148. $args .= render("generator/ai_obj.php",
  149. compact("class", "method", "arg", "null", "by_ref", "arg_class", "config"));
  150. if ($param->isOptional()) {
  151. $protoargs .= " = null";
  152. }
  153. } else {
  154. $callable = $param->isCallable();
  155. $protoargs .= $callable ? "callable \$$arg" : "$argprotohint \$$arg";
  156. $args .= render("generator/ai_std.php",
  157. compact("class", "method", "arg", "null", "by_ref", "callable", "config"));
  158. }
  159. if ($param->isDefaultValueAvailable()) {
  160. $default = $param->getDefaultValue();
  161. if ($default === NULL) {
  162. $default = "NULL";
  163. } elseif ($default === true) {
  164. $default = 1;
  165. } elseif ($default === false) {
  166. $default = 0;
  167. } elseif ($default === array()) {
  168. $default = "NULL";
  169. }
  170. } else {
  171. $default = "";
  172. }
  173. $zpp[] = array(
  174. "type" => $type,
  175. "short" => $short,
  176. "name" => $arg,
  177. "default" => $default,
  178. );
  179. $req_args += !$param->isOptional();
  180. }
  181. $classtype = "php_phongo_{$class}_t";
  182. $codes = get_code_from($m->getFilename(), $m->getStartLine(), $m->getEndLine());
  183. $code = render("generator/zpp.php",
  184. compact("zpp", "req_args", "classtype", "codes", "config"));
  185. if ($n>0) {
  186. $protoargs .= str_repeat("]", ($n+1)-$req_args);
  187. }
  188. $arginfos .= render("generator/arginfos.php",
  189. compact("class", "method", "args", "req_args", "docblock", "config"));
  190. $oneliner = explode("\n", $docblock)[1];
  191. $oneliner = " " . trim($oneliner, " *\t");
  192. $rettype = get_return_type($docblock);
  193. if ($method == "__construct") {
  194. $rettype = str_replace("\\\\", "\\", $ns) . "\\" . $class;
  195. }
  196. if (!$reflection->isInterface()) {
  197. $implementations .= render("generator/implementations.php",
  198. compact("class", "method", "oneliner", "protoargs", "code", "rettype", "config"));
  199. }
  200. }
  201. $docblock = untab($reflection->getDocComment())."\n";
  202. $declarations .= render("generator/declaration.php",
  203. compact("ns", "class", "entries", "docblock", "arginfos", "config"));
  204. $minitname = $class;
  205. $data = render($_SERVER["argv"][1], compact("declarations", "registrations", "implementations", "minitname", "class", "config"));
  206. $namespace = str_replace("\\", "/", $reflection->getNamespaceName());
  207. if (!is_dir("src/$namespace")) {
  208. mkdir("src/$namespace", 0777, true);
  209. }
  210. file_put_contents("src/$namespace/$class.c", $data);
  211. }
  212. }
  213. function get_return_type($docblock) {
  214. global $classes, $interfaces;
  215. $blocks = explode("\n", trim($docblock));
  216. foreach($blocks as $tmp) {
  217. if(strpos($tmp, "@return") !== false) {
  218. list($nada, $param, $type) = explode(" ", trim($tmp));
  219. if (isset($classes[$type])) {
  220. return $classes[$type];
  221. }
  222. if (isset($interfaces[$type])) {
  223. return $interfaces[$type];
  224. }
  225. return $type;
  226. }
  227. }
  228. return "void";
  229. }
  230. function get_zpp_type($current, $max, $param, $docblock) {
  231. if ($param->isArray()) {
  232. return array("zval", "a", "array");
  233. }
  234. $blocks = explode("\n", trim($docblock));
  235. $argn = 0;
  236. foreach($blocks as $argproto) {
  237. if(strpos($argproto, "@param") !== false) {
  238. if (++$argn == $current) {
  239. break;
  240. }
  241. }
  242. }
  243. if (strpos($argproto, $param->getName()) === false) {
  244. echo "Error - Not the argument name I expected in docblock\n";
  245. var_dump($param->getDeclaringClass()->getName(), $param->getName(), $argproto);
  246. exit;
  247. }
  248. list($nada, $param, $type, $name) = explode(" ", trim($argproto));
  249. switch($type) {
  250. case "bool":
  251. case "boolean":
  252. return array("zend_bool", "b", "boolean");
  253. case "integer|string":
  254. case "string":
  255. return array("char", "s", "string");
  256. case "integer":
  257. return array("long", "l", "integer");
  258. case "array|object":
  259. return array("zval", "A", "array|object");
  260. case "mixed":
  261. case "zval":
  262. return array("zval", "z", "mixed");
  263. default:
  264. if ($type == "callable") {
  265. return array("zval", "o", "callable");
  266. }
  267. return array($type, "O", $type);
  268. }
  269. }
  270. function getZPPType($type) {
  271. switch($type) {
  272. case "zval":
  273. case "char":
  274. case "long":
  275. case "zend_bool":
  276. return $type;
  277. default:
  278. return "zval";
  279. }
  280. }
  281. function get_code_from($filename, $start, $end)
  282. {
  283. $retval = array();
  284. if ($end > $start+1) {
  285. $file = file($filename, FILE_IGNORE_NEW_LINES);
  286. $content = array_slice($file, $start, $end-$start);
  287. $cef = 0;
  288. $cimpl = 0;
  289. $data = array();
  290. foreach($content as $locator) {
  291. switch(trim($locator)) {
  292. case "/*** CEF ***/":
  293. $cef++;
  294. break;
  295. case "/*** CIMPL ***/":
  296. $cimpl++;
  297. break;
  298. }
  299. if ($cef == 1) {
  300. $cef++;
  301. } else if ($cef == 2) {
  302. $ws = strspn($locator, " ");
  303. $tabs = $ws / 4;
  304. $data[] = str_repeat("\t", $tabs) . trim($locator, " ");
  305. } else if ($cef == 3) {
  306. $retval["cef"] = join("\n", array_slice($data, 1, -1));
  307. $data = array();
  308. $cef++;
  309. }
  310. if ($cimpl == 1) {
  311. $cimpl++;
  312. } else if ($cimpl == 2) {
  313. $ws = strspn($locator, " ");
  314. $tabs = $ws / 4;
  315. $data[] = str_repeat("\t", $tabs) . trim($locator, " ");
  316. } else if ($cimpl == 3) {
  317. $retval["cimpl"] = join("\n", array_slice($data, 1, -1));
  318. $cimpl++;
  319. }
  320. }
  321. }
  322. return $retval;
  323. }
  324. function getDefaultConfig($config) {
  325. $def = array(
  326. "free" => false,
  327. "funcs" => "",
  328. "internwrapper" => "",
  329. "ce" => array(),
  330. "headers" => array(),
  331. "handlers_callback" => "phongo_get_std_object_handlers",
  332. "handlers_init" => "",
  333. "forward_declarations" => "",
  334. "generate_handlers" => true,
  335. );
  336. $config = array_merge($def, $config);
  337. return $config;
  338. }