PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/tools/docskel/docskel.php

http://github.com/facebook/hiphop-php
PHP | 307 lines | 265 code | 33 blank | 9 comment | 46 complexity | 86d2a947fb51b0a67115c11960b23fce MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. <?hh
  2. include(__DIR__ . '/base.php');
  3. // see hphp/runtime/vm/bytecode.h:kMaxBuiltinArgs
  4. const MAX_BUILTIN_ARGS = 5;
  5. function generateDocComment(string $doccomment, ?array $func = null,
  6. string $indent = ''): string {
  7. if ($func === null) {
  8. $func = [];
  9. }
  10. $str = $doccomment . "\n";
  11. if (!empty($func['args'])) {
  12. $str .= "\n";
  13. foreach ($func['args'] as $arg) {
  14. $desc = isset($arg['desc']) ? $arg['desc'] : '';
  15. $v = "@param {$arg['type']} \${$arg['name']} - " .
  16. str_replace("\n", " ", $desc);
  17. $str .= implode("\n ", explode("\n",
  18. wordwrap($v, 70 - strlen($indent)))) . "\n";
  19. }
  20. }
  21. if (!empty($func['return'])) {
  22. $str .= "\n";
  23. $v = "@return {$func['return']['type']} - ";
  24. $v .= isset($func['return']['desc'])
  25. ? str_replace("\n", " ", $func['return']['desc']) . "\n"
  26. : '';
  27. $str .= implode("\n ", explode("\n",
  28. wordwrap($v, 70 - strlen($indent)))) . "\n";
  29. }
  30. $str = trim($str);
  31. if (empty($str)) return '';
  32. $block = wordwrap(trim($str), 75 - strlen($indent));
  33. return "$indent/**\n".
  34. "$indent * ".
  35. str_replace(["\n"," \n"], ["\n$indent * ","\n"], $block).
  36. "\n$indent */\n";
  37. }
  38. function generateFunctionSignature(array $func, string $indent = ''): string {
  39. $modifiers = empty($func['modifiers'])
  40. ? '' : (implode(' ', $func['modifiers']) . ' ');
  41. $ret = "$indent{$modifiers}function {$func['name']}(";
  42. $argspace = ",\n" . str_repeat(' ', strlen($ret));
  43. $notfirst = false;
  44. foreach ($func['args'] as $arg) {
  45. if ($notfirst) $ret .= $argspace;
  46. $notfirst = true;
  47. if (empty($arg['type'])) {
  48. $ret .= "mixed";
  49. } else {
  50. $ret .= $arg['type'];
  51. }
  52. $ret .= ' ';
  53. if ($arg['reference']) {
  54. $ret .= '&';
  55. }
  56. $ret .= "\${$arg['name']}";
  57. if (!empty($arg['default'])) {
  58. $ret .= " = {$arg['default']}";
  59. }
  60. }
  61. $ret .= '): ' . (empty($func['return']['type']) ? 'void'
  62. : $func['return']['type']);
  63. $annotation = count($func['args']) > MAX_BUILTIN_ARGS
  64. ? '<<__Native("ActRec")>>' : '<<__Native>>';
  65. return "$indent$annotation\n$ret;\n\n";
  66. }
  67. function outputSystemlib(string $dest, array $funcs, array $classes):void {
  68. $fp = fopen($dest, 'w');
  69. fwrite($fp, "<?hh\n");
  70. fwrite($fp, "// @"."generated by docskel.php\n\n");
  71. foreach($classes as $class) {
  72. if (!empty($class['intro'])) {
  73. fwrite($fp, generateDocComment($class['intro']));
  74. }
  75. fwrite($fp, "class {$class['name']}");
  76. if (!empty($class['extends'])) {
  77. fwrite($fp, " extends {$class['extends']}");
  78. }
  79. if (!empty($class['implements'])) {
  80. fwrite($fp, " implements " . implode(', ', $class['implements']));
  81. }
  82. fwrite($fp, " {\n");
  83. if (!empty($class['functions'])) {
  84. foreach($class['functions'] as $func) {
  85. fwrite($fp, generateDocComment($func['desc'], $func, ' '));
  86. fwrite($fp, generateFunctionSignature($func, ' '));
  87. }
  88. }
  89. fwrite($fp, "}\n\n");
  90. }
  91. foreach($funcs as $func) {
  92. fwrite($fp, generateDocComment($func['desc'], $func));
  93. fwrite($fp, generateFunctionSignature($func));
  94. }
  95. }
  96. function getMethod(string $name, array $classes): array {
  97. $colon = strpos($name, '::');
  98. if ($colon === false) {
  99. return array();
  100. }
  101. $cname = strtolower(substr($name, 0, $colon));
  102. $mname = strtolower(substr($name, $colon + 2));
  103. if (isset($classes[$cname]['functions'][$mname])) {
  104. return $classes[$cname]['functions'][$mname];
  105. }
  106. return array();
  107. }
  108. function generateCPPStub(array $func, array $classes): string {
  109. static $typemap = [
  110. // type => [return, param, actrec]
  111. 'bool' => ['bool', 'bool', 'KindOfBoolean'],
  112. 'int' => ['int64_t', 'int64_t', 'KindOfInt64'],
  113. 'float' => ['double', 'double', 'KindOfDouble'],
  114. 'string' => ['String', 'const String&', 'KindOfString'],
  115. 'array' => ['Array', 'const Array&', 'KindOfArray'],
  116. 'object' => ['Object', 'const Object&', 'KindOfObject'],
  117. 'resource' => ['Resource', 'const Resource&', 'KindOfResource'],
  118. 'mixed' => ['Variant', 'const Variant&', 'KindOfAny'],
  119. 'void' => ['void'],
  120. 'reference' => ['Variant', 'VRefParam', 'KindOfRef'],
  121. ];
  122. $actrec = count($func['args']) > MAX_BUILTIN_ARGS;
  123. $alias = !empty($func['class']) || empty($func['alias'])
  124. ? null : getMethod($func['alias'], $classes);
  125. // return type
  126. $ret = 'static ';
  127. if ($actrec) {
  128. $ret .= 'TypedValue*';
  129. } else if (empty($func['return']['type'])) {
  130. $ret .= 'void';
  131. } else if (isset($typemap[$func['return']['type']])) {
  132. $ret .= $typemap[$func['return']['type']][0];
  133. } else {
  134. $ret .= 'Object';
  135. }
  136. // function name
  137. if (empty($func['class'])) {
  138. $type = $actrec ? 'HHVM_FN' : 'HHVM_FUNCTION';
  139. $ret .= " $type({$func['name']}";
  140. } else {
  141. if ($actrec) {
  142. $type = in_array('static', $func['modifiers'])
  143. ? 'HHVM_STATIC_MN' : 'HHVM_MN';
  144. } else {
  145. $type = in_array('static', $func['modifiers'])
  146. ? 'HHVM_STATIC_METHOD' : 'HHVM_METHOD';
  147. }
  148. $ret .= " $type({$func['class']}, {$func['name']}";
  149. }
  150. // arguments
  151. $args = $actrec ? " auto this_ = ar_->m_this;\n" : '';
  152. foreach(array_values($func['args']) as $index => $arg) {
  153. if ($arg['reference']) {
  154. $type = $typemap['reference'];
  155. } else {
  156. $type = idx($typemap, $arg['type'], $typemap['object']);
  157. }
  158. if ($actrec) {
  159. $args .= " auto {$arg['name']} = getArg<{$type[2]}>(ar_, $index);\n";
  160. } else {
  161. $args .= ", {$type[1]} {$arg['name']}";
  162. }
  163. }
  164. if (!$actrec) {
  165. $ret .= "$args) {\n";
  166. } else if (!$alias) {
  167. $ret .= ')(ActRec* ar_) {'."\n$args\n";
  168. } else {
  169. $type = in_array('static', $alias['modifiers'])
  170. ? 'HHVM_STATIC_MN' : 'HHVM_MN';
  171. $ret .= <<<CPP
  172. )(ActRec* ar_) {
  173. return $type({$alias['class']}, {$alias['name']})(ar_);
  174. }
  175. CPP;
  176. return $ret;
  177. }
  178. // body
  179. if (!$alias) {
  180. $qualified_name = empty($func['class']) ? '' : "{$func['class']}::";
  181. $qualified_name .= $func['name'];
  182. $ret .= <<<CPP
  183. throw_not_implemented("$qualified_name");
  184. }
  185. CPP;
  186. return $ret;
  187. }
  188. // alias
  189. $ret .= " ";
  190. if (!empty($func['return']['type']) &&
  191. ($func['return']['type'] != 'void')) {
  192. $ret .= 'return ';
  193. }
  194. $comma = false;
  195. if (in_array('static', $alias['modifiers'])) {
  196. $ret .= "HHVM_STATIC_MN({$alias['class']}, {$alias['name']})".
  197. "(Unit::lookupClass(s_{$alias['class']}.get())";
  198. $comma = true;
  199. } else {
  200. $ret .= "HHVM_MN({$alias['class']}, {$alias['name']})(";
  201. }
  202. foreach($func['args'] as $arg) {
  203. if ($comma) $ret .= ', ';
  204. $comma = true;
  205. $ret .= $arg['name'];
  206. }
  207. return "$ret);\n}\n\n";
  208. }
  209. function outputExtensionCPP(string $dest, string $extname,
  210. array $funcs, array $classes): void {
  211. $fp = fopen($dest, 'w');
  212. fwrite($fp, "#include \"hphp/runtime/ext/extension.h\"\n");
  213. fwrite($fp, "namespace HPHP {\n");
  214. foreach($classes as $class) {
  215. fwrite($fp, "const StaticString s_{$class['name']}".
  216. "(\"{$class['name']}\");\n");
  217. if (empty($class['functions'])) continue;
  218. fwrite($fp, str_repeat('/', 78) . "\n// class {$class['name']}\n\n");
  219. foreach($class['functions'] as $func) {
  220. fwrite($fp, generateCPPStub($func, $classes));
  221. }
  222. }
  223. if (!empty($funcs)) {
  224. fwrite($fp, str_repeat('/', 78) . "\n// functions\n\n");
  225. foreach($funcs as $func) {
  226. fwrite($fp, generateCPPStub($func, $classes));
  227. }
  228. }
  229. fwrite($fp, str_repeat('/', 78) . "\n\n");
  230. fwrite($fp, "static class {$extname}Extension final : public Extension {\n");
  231. fwrite($fp, " public:\n");
  232. fwrite($fp, " {$extname}Extension() : Extension(\"{$extname}\") {}\n");
  233. fwrite($fp, " void moduleInit() override {\n");
  234. foreach($classes as $class) {
  235. if (empty($class['functions'])) continue;
  236. foreach($class['functions'] as $func) {
  237. $type = in_array('static', $func['modifiers'])
  238. ? 'HHVM_STATIC_ME' : 'HHVM_ME';
  239. fwrite($fp, " $type({$func['class']}, {$func['name']});\n");
  240. }
  241. }
  242. foreach($funcs as $func) {
  243. if (empty($func['name'])) continue;
  244. fwrite($fp, " HHVM_FE({$func['name']});\n");
  245. }
  246. fwrite($fp, " loadSystemlib();\n");
  247. fwrite($fp, " }\n");
  248. fwrite($fp, "} s_{$extname}_extension;\n\n");
  249. fwrite($fp, "// Uncomment for non-bundled module\n");
  250. fwrite($fp, "//HHVM_GET_MODULE(${extname});\n\n");
  251. fwrite($fp, str_repeat('/', 78) . "\n");
  252. fwrite($fp, "} // namespace HPHP\n");
  253. }
  254. if (empty($_SERVER['argv'][2])) {
  255. fwrite(STDERR, "Usage: {$_SERVER['argv'][0]} <phpdoc-root> <extname> ".
  256. "[ exname.cpp [ extname.php ] ]\n");
  257. exit;
  258. }
  259. $extname = $_SERVER['argv'][2];
  260. $ext = new HHVMDocExtension($extname, $_SERVER['argv'][1]);
  261. $cppfile = empty($_SERVER['argv'][3])
  262. ? "$extname.cpp" : $_SERVER['argv'][3];
  263. $phpfile = empty($_SERVER['argv'][4])
  264. ? "$extname.php" : $_SERVER['argv'][4];
  265. if (!preg_match('@^[a-zA-Z0-9_\.-]+$@', $extname)) {
  266. die("Invalid extension name: $extname\n");
  267. }
  268. $ext->setVerbose(true);
  269. outputSystemlib($phpfile,
  270. $ext->getFunctions(),
  271. $ext->getClasses());
  272. outputExtensionCPP($cppfile, $extname,
  273. $ext->getFunctions(),
  274. $ext->getClasses());