PageRenderTime 56ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/hphp/system/idl/base.php

https://gitlab.com/Blueprint-Marketing/hhvm
PHP | 1270 lines | 1121 code | 125 blank | 24 comment | 226 complexity | d30356aa4efc04ee59d1ffabed770b39 MD5 | raw file
  1. <?php
  2. ///////////////////////////////////////////////////////////////////////////////
  3. // types
  4. define('Boolean', 1);
  5. define('Int32', 4);
  6. define('Int64', 5);
  7. define('Double', 6);
  8. define('String', 7);
  9. define('Int64Vec', 8);
  10. define('StringVec', 9);
  11. define('VariantVec', 10);
  12. define('Int64Map', 11);
  13. define('StringMap', 12);
  14. define('VariantMap', 13);
  15. define('Object', 14);
  16. define('Resource', 15);
  17. define('Variant', 16);
  18. define('Numeric', 17);
  19. define('Primitive', 18);
  20. define('PlusOperand', 19);
  21. define('Sequence', 20);
  22. define('Any', 21);
  23. define('TypeMask', 0x00FF);
  24. define('Reference', 0x0100);
  25. $TYPENAMES = array
  26. (Boolean => array('name' => 'bool', 'enum' => 'Boolean',
  27. 'idlname' => 'Boolean', 'phpname' => 'bool'),
  28. Int32 => array('name' => 'int', 'enum' => 'Int32',
  29. 'idlname' => 'Int32', 'phpname' => 'int'),
  30. Int64 => array('name' => 'int64_t', 'enum' => 'Int64',
  31. 'idlname' => 'Int64', 'phpname' => 'int'),
  32. Double => array('name' => 'double', 'enum' => 'Double',
  33. 'idlname' => 'Double', 'phpname' => 'float'),
  34. String => array('name' => 'String', 'enum' => 'String',
  35. 'idlname' => 'String', 'phpname' => 'string'),
  36. Int64Vec => array('name' => 'Array', 'enum' => 'Array',
  37. 'idlname' => 'Int64Vec', 'phpname' => 'vector'),
  38. StringVec => array('name' => 'Array', 'enum' => 'Array',
  39. 'idlname' => 'StringVec', 'phpname' => 'vector'),
  40. VariantVec => array('name' => 'Array', 'enum' => 'Array',
  41. 'idlname' => 'VariantVec', 'phpname' => 'vector'),
  42. Int64Map => array('name' => 'Array', 'enum' => 'Array',
  43. 'idlname' => 'Int64Map', 'phpname' => 'map'),
  44. StringMap => array('name' => 'Array', 'enum' => 'Array',
  45. 'idlname' => 'StringMap', 'phpname' => 'map'),
  46. VariantMap => array('name' => 'Array', 'enum' => 'Array',
  47. 'idlname' => 'VariantMap', 'phpname' => 'map'),
  48. Object => array('name' => 'Object', 'enum' => 'Object',
  49. 'idlname' => 'Object', 'phpname' => 'object'),
  50. Resource => array('name' => 'Resource', 'enum' => 'Resource',
  51. 'idlname' => 'Resource', 'phpname' => 'resource'),
  52. Variant => array('name' => 'Variant', 'enum' => 'Variant',
  53. 'idlname' => 'Variant', 'phpname' => 'mixed'),
  54. Numeric => array('name' => 'Numeric', 'enum' => 'Numeric',
  55. 'idlname' => 'Numeric', 'phpname' => 'number'),
  56. Primitive => array('name' => 'Primitive', 'enum' => 'Primitive',
  57. 'idlname' => 'Primitive', 'phpname' => 'num|string'),
  58. PlusOperand => array('name' => 'PlusOperand', 'enum' => 'PlusOperand',
  59. 'idlname' => 'PlusOperand','phpname' => 'num|array'),
  60. Sequence => array('name' => 'Sequence', 'enum' => 'Sequence',
  61. 'idlname' => 'Sequence', 'phpname' => 'string|array'),
  62. Any => array('name' => 'Variant', 'enum' => 'Some',
  63. 'idlname' => 'Any', 'phpname' => 'mixed'),
  64. );
  65. $REFNAMES = array('String' => 'CStrRef',
  66. 'Array' => 'CArrRef',
  67. 'Object' => 'CObjRef',
  68. 'Resource' => 'CResRef',
  69. 'Variant' => 'CVarRef',
  70. 'Numeric' => 'CVarRef',
  71. 'Primitive' => 'CVarRef',
  72. 'PlusOperand' => 'CVarRef',
  73. 'Sequence' => 'CVarRef',
  74. );
  75. $MAGIC_METHODS = array('__get' => 'ObjectData::UseGet',
  76. '__set' => 'ObjectData::UseSet',
  77. '__isset' => 'ObjectData::UseIsset',
  78. '__unset' => 'ObjectData::UseUnset',
  79. '__call' => 'ObjectData::HasCall',
  80. '__clone' => 'ObjectData::HasClone',
  81. );
  82. function get_idl_name($type, $null = '') {
  83. global $TYPENAMES;
  84. if ($type === null) {
  85. return $null;
  86. }
  87. if (is_string($type)) {
  88. return "'$type'";
  89. }
  90. if ($type & Reference) {
  91. return $TYPENAMES[$type & ~Reference]['idlname'] . ' | Reference';
  92. }
  93. return $TYPENAMES[$type]['idlname'];
  94. }
  95. function get_php_name($type, $null = 'mixed') {
  96. global $TYPENAMES;
  97. if ($type === null) {
  98. return $null;
  99. }
  100. if (is_string($type)) {
  101. return $type;
  102. }
  103. if ($type & Reference) {
  104. return $TYPENAMES[$type & ~Reference]['phpname'];
  105. }
  106. return $TYPENAMES[$type]['phpname'];
  107. }
  108. ///////////////////////////////////////////////////////////////////////////////
  109. // flags
  110. // ClassInfo attributes, and these numbers need to be consistent with them!
  111. define('ParamCoerceModeNull', 1 << 0);
  112. define('IsAbstract', 1 << 4);
  113. define('IsFinal', 1 << 5);
  114. define('IsPublic', 1 << 6);
  115. define('IsProtected', 1 << 7);
  116. define('IsPrivate', 1 << 8);
  117. define('AllowOverride', 1 << 8);
  118. define('IsStatic', 1 << 9);
  119. define('IsCppAbstract', 1 << 10);
  120. define('IsReference', 1 << 11);
  121. define('IsNothing', 1 << 13);
  122. define('ZendCompat', 1 << 14);
  123. define('IsCppSerializable', 1 << 15);
  124. define('HipHopSpecific', 1 << 16);
  125. define('VariableArguments', 1 << 17);
  126. define('RefVariableArguments', 1 << 18);
  127. define('FunctionIsFoldable', 1 << 20);
  128. define('NoEffect', 1 << 21);
  129. define('NoInjection', 1 << 22);
  130. define('HasOptFunction', 1 << 23);
  131. define('AllowIntercept', 1 << 24);
  132. define('NoProfile', 1 << 25);
  133. define('NoDefaultSweep', 1 << 27);
  134. define('IsSystem', 1 << 28);
  135. define('IsTrait', 1 << 29);
  136. define('ParamCoerceModeFalse', 1 << 30);
  137. define('NoFCallBulitin', 1 << 31);
  138. // Mask for checking the flags related to variable arguments
  139. define('VarArgsMask', (VariableArguments | RefVariableArguments));
  140. function get_flag_names($arr, $name, $global_func) {
  141. $flag = 0;
  142. if (!empty($arr[$name])) {
  143. $flag |= $arr[$name];
  144. }
  145. if ($flag == 0) return '';
  146. $ret = '';
  147. if ($flag & IsAbstract ) $ret .= ' | IsAbstract' ;
  148. if ($flag & IsFinal ) $ret .= ' | IsFinal' ;
  149. if ($flag & IsPublic ) $ret .= ' | IsPublic' ;
  150. if ($flag & IsProtected ) $ret .= ' | IsProtected' ;
  151. if ($global_func) {
  152. if ($flag & AllowOverride ) $ret .= ' | AllowOverride' ;
  153. } else {
  154. if ($flag & IsPrivate ) $ret .= ' | IsPrivate' ;
  155. }
  156. if ($flag & IsStatic ) $ret .= ' | IsStatic' ;
  157. if ($flag & HipHopSpecific ) $ret .= ' | HipHopSpecific' ;
  158. if ($flag & VariableArguments ) $ret .= ' | VariableArguments' ;
  159. if ($flag & RefVariableArguments ) $ret .= ' | RefVariableArguments' ;
  160. if ($flag & FunctionIsFoldable ) $ret .= ' | FunctionIsFoldable' ;
  161. if ($flag & NoEffect ) $ret .= ' | NoEffect' ;
  162. if ($flag & NoInjection ) $ret .= ' | NoInjection' ;
  163. if ($flag & HasOptFunction ) $ret .= ' | HasOptFunction' ;
  164. if ($flag & AllowIntercept ) $ret .= ' | AllowIntercept' ;
  165. if ($flag & NoProfile ) $ret .= ' | NoProfile' ;
  166. if ($flag & NoDefaultSweep ) $ret .= ' | NoDefaultSweep' ;
  167. if ($flag & IsTrait ) $ret .= ' | IsTrait' ;
  168. if ($flag & NoFCallBuiltin ) $ret .= ' | NoFCallBuiltin' ;
  169. if ($ret == '') {
  170. throw new Exception("invalid flag $flag");
  171. }
  172. return substr($ret, 2);
  173. }
  174. function read_array_of_constant_names($flag_arr) {
  175. if (!is_array($flag_arr)) {
  176. return 0;
  177. }
  178. $flag = 0;
  179. foreach ($flag_arr as $constname) {
  180. $flag |= constant($constname);
  181. }
  182. return $flag;
  183. }
  184. ///////////////////////////////////////////////////////////////////////////////
  185. // schema functions that will be used (and only used) by schemas
  186. function ResetSchema() {
  187. global $current_class, $preamble, $funcs, $classes, $constants;
  188. $current_class = '';
  189. $preamble = '';
  190. $funcs = array();
  191. $classes = array();
  192. $constants = array();
  193. }
  194. ResetSchema();
  195. function BeginClass($class) {
  196. global $classes, $current_class;
  197. $current_class = $class['name'];
  198. if (!isset($class['parent'])) $class['parent'] = null;
  199. if (!isset($class['ifaces'])) $class['ifaces'] = array();
  200. if (!isset($class['bases'])) $class['bases'] = array();
  201. $class['methods'] = array();
  202. $class['properties'] = array();
  203. $class['consts'] = array();
  204. $class['flags'] = read_array_of_constant_names($class['flags']);
  205. $doc = get_class_doc_comments($class);
  206. if (!empty($doc)) {
  207. $class['doc'] = $doc;
  208. } else {
  209. $class['doc'] = null;
  210. }
  211. $classes[$current_class] = $class;
  212. }
  213. function EndClass() {
  214. global $classes, $current_class;
  215. $have_ctor = false;
  216. foreach ($classes[$current_class]['methods'] as $method) {
  217. if ($method['name'] == '__construct') $have_ctor = true;
  218. }
  219. // We don't have the information to autogenerate a ctor def,
  220. // so make the user do it.
  221. if (!$have_ctor) {
  222. throw new Exception("No constructor defined for class $current_class");
  223. }
  224. $current_class = '';
  225. }
  226. function idl_parse_type($t) {
  227. if (defined($t) && ($v = constant($t)) &&
  228. is_integer($v) && ($v > 0) && ($v < TypeMask)) {
  229. return $v;
  230. }
  231. error_log("Undefined type: $t", E_USER_WARNING);
  232. return $t;
  233. }
  234. function idl_infer_type($v) {
  235. switch(gettype($v)) {
  236. case 'boolean': return Boolean;
  237. case 'integer': return Int64;
  238. case 'double': return Double;
  239. case 'string': return String;
  240. case 'array': return VariantMap;
  241. case 'object': return Object;
  242. case 'resource': return Resource;
  243. default: return Any;
  244. }
  245. }
  246. function DefineConstant($const) {
  247. global $constants, $classes, $current_class;
  248. if (!isset($const['type']) && array_key_exists('value', $const)) {
  249. $const['type'] = idl_infer_type($const['value']);
  250. } else {
  251. $const['type'] = idl_parse_type($const['type']);
  252. }
  253. if (empty($current_class)) {
  254. $constants[] = $const;
  255. } else {
  256. $classes[$current_class]['consts'][] = $const;
  257. }
  258. }
  259. function DefineFunction($func) {
  260. global $classes, $current_class;
  261. if (empty($func['flags'])) {
  262. $func['flags'] = 0;
  263. } else {
  264. $func['flags'] = read_array_of_constant_names($func['flags']);
  265. if ($current_class && $classes[$current_class]['flags'] & HipHopSpecific) {
  266. $func['flags'] |= HipHopSpecific;
  267. }
  268. }
  269. if (!isset($func['return'])) $func['return'] = array();
  270. $func['ret_desc'] = idx($func['return'], 'desc');
  271. $func['ret_hint'] = idx($func['return'], 'hint');
  272. if (isset($func['return']['type'])) {
  273. if (idx($func['return'], 'ref')) {
  274. $func['return'] = Variant;
  275. } else {
  276. $func['return'] = idl_parse_type($func['return']['type']);
  277. }
  278. } else {
  279. $func['return'] = null;
  280. }
  281. $args = array();
  282. if (!empty($func['args'])) {
  283. foreach ($func['args'] as $arg) {
  284. if (array_key_exists('value', $arg)) {
  285. if (!is_string($arg['value']) || $arg['value'] === '') {
  286. throw new Exception('default value has to be non-empty string for '.
  287. $func['name'].'(..'.$arg['name'].'..)');
  288. }
  289. if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $arg['value'], $m)) {
  290. $class = $m[1];
  291. $constant = $m[2];
  292. $arg['default'] = "q_${class}_${constant}";
  293. } else {
  294. $arg['default'] = $arg['value'];
  295. }
  296. $arg['defaultSerialized'] = get_serialized_default($arg['value']);
  297. $arg['defaultText'] = get_default_text($arg['value']);
  298. }
  299. if (idx($arg, 'ref')) {
  300. $arg['type'] = Variant;
  301. } else {
  302. $arg['type'] = idl_parse_type($arg['type']);
  303. }
  304. $args[] = $arg;
  305. }
  306. $func['args'] = $args;
  307. } else {
  308. $func['args'] = array();
  309. }
  310. $doc = get_function_doc_comments($func, $current_class);
  311. if (!empty($doc)) {
  312. $func['doc'] = $doc;
  313. } else {
  314. $func['doc'] = null;
  315. }
  316. global $funcs, $classes, $current_class;
  317. if (empty($current_class)) {
  318. $funcs[] = $func;
  319. } else {
  320. $classes[$current_class]['methods'][] = $func;
  321. }
  322. }
  323. ///////////////////////////////////////////////////////////////////////////////
  324. // Read an IDL file into the 'funcs', 'classes' and 'consts' globals
  325. function ReadIDLFile($path) {
  326. $entries = json_decode(file_get_contents($path), /* use arrays */ true);
  327. if (!$entries) {
  328. throw new Exception("Unable to parse json from $path");
  329. }
  330. if (!empty($entries['funcs'])) {
  331. foreach ($entries['funcs'] as $func) {
  332. DefineFunction($func);
  333. }
  334. }
  335. if (!empty($entries['consts'])) {
  336. foreach ($entries['consts'] as $const) {
  337. DefineConstant($const);
  338. }
  339. }
  340. foreach ($entries['classes'] as $class) {
  341. $methods = isset($class['funcs']) ? $class['funcs'] : array();
  342. $consts = isset($class['consts']) ? $class['consts'] : array();
  343. unset($class['funcs']);
  344. unset($class['consts']);
  345. BeginClass($class);
  346. foreach ($methods as $method) {
  347. DefineFunction($method);
  348. }
  349. foreach ($consts as $const) {
  350. DefineConstant($const);
  351. }
  352. EndClass();
  353. }
  354. }
  355. ///////////////////////////////////////////////////////////////////////////////
  356. // code generation
  357. function typename($type, $prefix = true) {
  358. if (is_string($type)) {
  359. if ($prefix) return 'p_' . $type;
  360. return $type;
  361. }
  362. global $TYPENAMES;
  363. $type = $type & TypeMask;
  364. if ($type !== 0) {
  365. if (!isset($TYPENAMES[$type])) {
  366. exit("Unknown type $type\n");
  367. }
  368. return $TYPENAMES[$type]['name'];
  369. }
  370. return 'void';
  371. }
  372. function typeidlname($type, $null = '') {
  373. global $TYPENAMES;
  374. if ($type === null) {
  375. return $null;
  376. }
  377. if (is_string($type)) {
  378. return "'$type'";
  379. }
  380. if ($type & Reference) {
  381. return $TYPENAMES[$type & ~Reference]['idlname'];
  382. }
  383. return $TYPENAMES[$type]['idlname'];
  384. }
  385. function param_typename($arg, $forceRef = false) {
  386. $type = $arg['type'];
  387. if (is_string($type)) {
  388. return 'p_' . $type;
  389. }
  390. global $REFNAMES;
  391. $name = typename($type);
  392. $ref = idx($arg, 'ref');
  393. if (idx($arg, 'ref')) {
  394. return ($name === "Variant") ? "VRefParam" : $name;
  395. }
  396. if ($forceRef) {
  397. return $name;
  398. }
  399. return isset($REFNAMES[$name]) ? $REFNAMES[$name] : $name;
  400. }
  401. function typeenum($type) {
  402. if (is_string($type)) {
  403. return 'Void';
  404. }
  405. global $TYPENAMES;
  406. $type = $type & TypeMask;
  407. if ($type !== 0) {
  408. return $TYPENAMES[$type]['enum'];
  409. }
  410. return 'Void';
  411. }
  412. function fprintType($f, $type) {
  413. if (is_string($type)) {
  414. fprintf($f, 'S(999), "%s"', $type);
  415. } else {
  416. fprintf($f, 'T(%s)', typeenum($type));
  417. }
  418. }
  419. function get_serialized_default($s) {
  420. // These values are special and cannot be returned by
  421. // ReflectionParameter::getDefaultValue().
  422. if ($s == 'TimeStamp::Current()' ||
  423. preg_match('/^k_SQLITE3_/', $s)) {
  424. return "\x01";
  425. }
  426. if (preg_match('/^".*"$/', $s) ||
  427. preg_match('/^[\-0-9.]+$/', $s) ||
  428. preg_match('/^0x[0-9a-fA-F]+$/', $s) ||
  429. preg_match('/^(true|false|null)$/', $s)) {
  430. return serialize(eval("return $s;"));
  431. }
  432. if ($s == "empty_array_ref") return serialize(array());
  433. if (preg_match('/^null_(string|array|object|resource|variant)$/', $s)) {
  434. return serialize(null);
  435. }
  436. if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) {
  437. $s = preg_replace('/k_/', '', $s);
  438. return serialize(eval("return $s;"));
  439. }
  440. if (preg_match('/^q_([A-Za-z]+)\$\$(\w+)$/', $s, $m)) {
  441. $class = $m[1];
  442. $constant = $m[2];
  443. return serialize(eval("return $class::$constant;"));
  444. }
  445. if ($s == 'RAND_MAX') {
  446. return serialize(getrandmax());
  447. }
  448. if ($s == 'INT_MAX') {
  449. return serialize((1 << 31) - 1);
  450. }
  451. throw new Exception("Unable to serialize default value: [$s]");
  452. }
  453. function get_default_text($s) {
  454. if (preg_match('/^null_(string|array|object|variant)$/', $s)) {
  455. return 'null';
  456. }
  457. if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) {
  458. return preg_replace('/k_/', '', $s);
  459. }
  460. if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $s, $m)) {
  461. $class = $m[1];
  462. $constant = $m[2];
  463. return "$class::$constant";
  464. }
  465. return $s;
  466. }
  467. function generateFuncCPPInclude($func, $f, $newline = true) {
  468. fprintf($f, '"%s", ', $func['name']);
  469. fprintType($f, $func['return']);
  470. fprintf($f, ', S(%d), ', idx($func, 'ref') ? 1 : 0);
  471. for ($i = 0; $i < count($func['args']); $i++) {
  472. $arg = $func['args'][$i];
  473. fprintf($f, '"%s", ', $arg['name']);
  474. fprintType($f, $arg['type']);
  475. fprintf($f, ', ');
  476. if (isset($arg['default'])) {
  477. $serialized = escape_cpp($arg['defaultSerialized']);
  478. fprintf($f, '"%s", S(%d), ',
  479. $serialized, strlen($arg['defaultSerialized']));
  480. fprintf($f, '"%s", ', escape_cpp($arg['defaultText']));
  481. } else {
  482. fprintf($f, 'NULL, S(0), NULL, ');
  483. }
  484. fprintf($f, 'S(%d), ', idx($arg, 'ref') ? 1 : 0);
  485. }
  486. fprintf($f, "NULL, ");
  487. fprintf($f, 'S(%d), ', $func['flags']);
  488. if (!empty($func['doc'])) {
  489. fprintf($f, '"%s", ', escape_cpp($func['doc']));
  490. }
  491. if (!empty($func['opt'])) {
  492. fprintf($f, 'S(%s), ', $func['opt']);
  493. }
  494. if ($newline) fprintf($f, "\n");
  495. }
  496. function generateFuncOptDecls($func, $f) {
  497. if ($func['opt']) {
  498. fprintf($f, "extern ExpressionPtr ".
  499. "%s(CodeGenerator *cg, AnalysisResultConstPtr ar, ".
  500. "SimpleFunctionCallPtr call, int mode);\n",
  501. $func['opt']);
  502. }
  503. }
  504. function generateConstCPPInclude($const, $f) {
  505. fprintf($f, '"%s", T(%s),'. "\n", $const['name'], typeenum($const['type']));
  506. }
  507. function generateClassCPPInclude($class, $f) {
  508. fprintf($f, '"%s", "%s", ', $class['name'], strtolower($class['parent']));
  509. foreach ($class['ifaces'] as $if) {
  510. fprintf($f, '"%s",', strtolower($if));
  511. }
  512. fprintf($f, 'NULL, ');
  513. foreach ($class['methods'] as $m) {
  514. generateMethodCPPInclude($m, $f);
  515. fprintf($f, ",");
  516. }
  517. fprintf($f, "NULL,");
  518. foreach ($class['properties'] as $p) {
  519. generatePropertyCPPInclude($p, $f);
  520. fprintf($f, ",");
  521. }
  522. fprintf($f, "NULL,");
  523. foreach ($class['consts'] as $k) {
  524. fprintf($f, '"%s", T(%s),', $k['name'], typeenum($k['type']));
  525. }
  526. fprintf($f, "NULL,\n");
  527. fprintf($f, 'S(%d), ', $class['flags']);
  528. if (!empty($class['doc'])) {
  529. fprintf($f, '"%s", ', escape_cpp($class['doc']));
  530. }
  531. }
  532. function generateMethodCPPInclude($method, $f) {
  533. generateFuncCPPInclude($method, $f, false, 'G');
  534. fprintf($f, "S(%d)", $method['flags']);
  535. }
  536. function generatePropertyCPPInclude($property, $f) {
  537. fprintf($f, "S(%d), \"%s\", ", $property['flags'], $property['name']);
  538. fprintType($f, $property['type']);
  539. }
  540. function generateFuncArgsCPPHeader($func, $f, $forceRef = false,
  541. $static = false) {
  542. $var_arg = ($func['flags'] & VarArgsMask);
  543. $args = $func['args'];
  544. fprintf($f, "(");
  545. if ($var_arg) fprintf($f, 'int _argc');
  546. if ($var_arg && count($args) > 0) fprintf($f, ', ');
  547. for ($i = 0; $i < count($args); $i++) {
  548. $arg = $args[$i];
  549. if ($i > 0) fprintf($f, ', ');
  550. fprintf($f, '%s %s', param_typename($arg, $forceRef),
  551. $arg['name']);
  552. if (isset($arg['default'])) {
  553. fprintf($f, ' = %s', $arg['default']);
  554. }
  555. }
  556. if ($var_arg) {
  557. fprintf($f, ', CArrRef _argv = null_array');
  558. }
  559. fprintf($f, ")");
  560. }
  561. function generateFuncArgsCall($func, $f) {
  562. $var_arg = ($func['flags'] & VarArgsMask);
  563. $args = $func['args'];
  564. if ($var_arg) fprintf($f, '_argc');
  565. if ($var_arg && count($args) > 0) fprintf($f, ', ');
  566. for ($i = 0; $i < count($args); $i++) {
  567. $arg = $args[$i];
  568. fprintf($f, ', ');
  569. fprintf($f, '%s', $arg['name']);
  570. }
  571. if ($var_arg) {
  572. fprintf($f, ', _argv');
  573. }
  574. }
  575. function generateFuncCPPForwardDeclarations($func, $f) {
  576. if (is_string($func['return'])) {
  577. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  578. typename($func['return'], false));
  579. }
  580. foreach ($func['args'] as $arg) {
  581. if (is_string($arg['type'])) {
  582. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  583. typename($arg['type'], false));
  584. }
  585. }
  586. }
  587. function generateFuncCPPHeader($func, $f, $method = false, $forceRef = false,
  588. $static = false, $class = false) {
  589. if ($method) {
  590. fprintf($f, '%s%s %s_%s', $static ? 'static ' : '',
  591. typename($func['return']), $static ? "ti" : "t",
  592. strtolower($func['name']));
  593. } else {
  594. generateFuncCPPForwardDeclarations($func, $f);
  595. fprintf($f, '%s f_%s', typename($func['return']), $func['name']);
  596. }
  597. generateFuncArgsCPPHeader($func, $f, $forceRef, $static);
  598. fprintf($f, ";\n");
  599. }
  600. function generateConstCPPHeader($const, $f) {
  601. $name = typename($const['type']);
  602. if ($name == 'String') {
  603. $name = 'StaticString';
  604. }
  605. fprintf($f, "extern const %s k_%s;\n", $name, $const['name']);
  606. }
  607. function generateConstCPPImplementation($const, $f, $prefix = 'k_') {
  608. $name = typename($const['type']);
  609. if ($name == 'String') {
  610. $name = 'StaticString';
  611. }
  612. $def = '';
  613. if (isset($const['value'])) {
  614. if ($name == 'StaticString') {
  615. $def = '"' . addslashes($const['value']) . '"';
  616. } else if ($name == 'bool') {
  617. $def = $const['value'] ? 'true' : 'false';
  618. } else {
  619. $def = $const['value'];
  620. }
  621. $def = " = $def";
  622. }
  623. fprintf($f, "const %s %s%s%s;\n", $name, $prefix, $const['name'], $def);
  624. }
  625. function generateClassCPPHeader($class, $f) {
  626. global $MAGIC_METHODS;
  627. $clsname = $class['name'];
  628. foreach ($class['consts'] as $k) {
  629. $name = typename($k['type']);
  630. if ($name == 'String') {
  631. $name = 'StaticString';
  632. }
  633. fprintf($f, "extern const %s q_%s\$\$%s;\n", $name, $clsname, $k['name']);
  634. }
  635. fprintf($f,
  636. <<<EOT
  637. ///////////////////////////////////////////////////////////////////////////////
  638. // class ${class['name']}
  639. EOT
  640. );
  641. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n", $clsname);
  642. foreach ($class['properties'] as $p) {
  643. generatePropertyCPPForwardDeclarations($p, $f);
  644. }
  645. foreach ($class['methods'] as $m) {
  646. generateFuncCPPForwardDeclarations($m, $f);
  647. }
  648. fprintf($f, "class c_%s", $clsname);
  649. $flags = array();
  650. foreach ($class['methods'] as $m) {
  651. $name = $m['name'];
  652. if (isset($MAGIC_METHODS[$name]) && $MAGIC_METHODS[$name]) {
  653. $flags[$name] = $MAGIC_METHODS[$name];
  654. }
  655. }
  656. if ($class['parent']) {
  657. global $classes;
  658. $pclass = $class;
  659. while ($flags && $pclass['parent'] && isset($classes[$class['parent']])) {
  660. $pclass = $classes[$class['parent']];
  661. foreach ($pclass['methods'] as $m) {
  662. unset($flags[$m['name']]);
  663. }
  664. }
  665. fprintf($f, " : public c_" . $class['parent']);
  666. } else {
  667. fprintf($f, " : public ExtObjectData");
  668. if ($flags) {
  669. fprintf($f, "Flags<%s>", implode('|', $flags));
  670. $flags = false;
  671. }
  672. }
  673. foreach ($class['bases'] as $p) {
  674. fprintf($f, ", public $p");
  675. }
  676. $parents = array();
  677. fprintf($f, " {\n public:\n");
  678. fprintf($f, " DECLARE_CLASS(%s, %s, %s)\n", $clsname, $clsname,
  679. $class['parent'] ? $class['parent'] : 'ObjectData');
  680. fprintf($f, "\n");
  681. if (!empty($class['properties'])) {
  682. fprintf($f, " // properties\n");
  683. foreach ($class['properties'] as $p) {
  684. generatePropertyCPPHeader($p, $f);
  685. }
  686. fprintf($f, "\n");
  687. }
  688. fprintf($f, " // need to implement\n");
  689. if ($flags) {
  690. fprintf($f, " // constructor must call setAttributes(%s)\n",
  691. implode('|', $flags));
  692. }
  693. fprintf($f, " public: c_%s(Class* cls = c_%s::classof());\n",
  694. $class['name'], $class['name']);
  695. fprintf($f, " public: ~c_%s();\n", $class['name']);
  696. foreach ($class['methods'] as $m) {
  697. generateMethodCPPHeader($m, $class, $f);
  698. }
  699. fprintf($f, "\n");
  700. fprintf($f, " // implemented by HPHP\n");
  701. foreach ($class['methods'] as $m) {
  702. generatePreImplemented($m, $class, $f);
  703. }
  704. if (!empty($class['footer'])) {
  705. fprintf($f, $class['footer']);
  706. }
  707. fprintf($f, "\n};\n");
  708. }
  709. function generateClassCPPImplementation($class, $f) {
  710. foreach ($class['consts'] as $k) {
  711. generateConstCPPImplementation($k, $f, "q_{$class['name']}$$");
  712. }
  713. foreach ($class['methods'] as $m) {
  714. generateMethodCPPImplementation($m, $class, $f);
  715. }
  716. }
  717. function generateMethodCPPHeader($method, $class, $f) {
  718. global $MAGIC_METHODS;
  719. fprintf($f, " public: ");
  720. generateFuncCPPHeader($method, $f, true,
  721. isset($MAGIC_METHODS[$method['name']]),
  722. $method['flags'] & IsStatic, $class);
  723. }
  724. function generateMethodCPPImplementation($method, $class, $f) {
  725. if ($method['flags'] & IsStatic) {
  726. $prefix = "c_{$class['name']}::ti_";
  727. } else {
  728. $prefix = "c_{$class['name']}::t_";
  729. }
  730. generateFuncCPPImplementation($method, $f, $prefix);
  731. }
  732. function generatePropertyCPPHeader($property, $f) {
  733. fprintf($f, " public: ");
  734. fprintf($f, "%s m_%s;\n", typename($property['type']),
  735. $property['name']);
  736. }
  737. function generatePropertyCPPForwardDeclarations($property, $f) {
  738. if (is_string($property['type'])) {
  739. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  740. typename($property['type'], false));
  741. }
  742. }
  743. function generatePreImplemented($method, $class, $f) {
  744. if ($method['name'] == '__construct') {
  745. fprintf($f, " public: c_%s *create", $class['name']);
  746. generateFuncArgsCPPHeader($method, $f, true);
  747. fprintf($f, ";\n");
  748. }
  749. }
  750. function generateFuncCPPImplementation($func, $f, $prefix = 'f_') {
  751. $schema = "";
  752. $schema_no = 0;
  753. if ($func['return'] == Object || $func['return'] == Resource) {
  754. $schema .= '.set(' . ($schema_no++) . ', -1, "OO")';
  755. }
  756. $output = '';
  757. $need_ret = false;
  758. fprintf($f, '%s %s%s(',
  759. typename($func['return']),
  760. $prefix,
  761. strtolower($func['name']));
  762. $var_arg = ($func['flags'] & VarArgsMask);
  763. if ($var_arg) fprintf($f, 'int _argc');
  764. if ($var_arg && count($func['args']) > 0) fprintf($f, ', ');
  765. $params = "";
  766. $params_no = 0;
  767. for ($i = 0; $i < count($func['args']); $i++) {
  768. $arg = $func['args'][$i];
  769. if ($i > 0) fprintf($f, ', ');
  770. fprintf($f, '%s %s', param_typename($arg),
  771. $arg['name']);
  772. if (isset($arg['default'])) {
  773. fprintf($f, ' /* = %s */', $arg['default']);
  774. }
  775. if ($arg['type'] == Object || $arg['type'] == Resource) {
  776. $params .= '.set(' . ($params_no++) .
  777. ', (OpaqueObject::GetIndex(' . $arg['name'] . '))';
  778. } else {
  779. $params .= '.set(' . ($params_no++) . ', ' . $arg['name'] . ')';
  780. }
  781. if ($arg['type'] == Object || $arg['type'] == Resource) {
  782. if (idx($arg, 'ref')) {
  783. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "OO")';
  784. } else {
  785. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "O")';
  786. }
  787. } else if (idx($arg, 'ref')) {
  788. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "R")';
  789. }
  790. if (idx($arg, 'ref')) {
  791. $need_ret = true;
  792. $output .= ' '.$arg['name'].' = ((Variant)_ret[1])['.$i.'];'."\n";
  793. }
  794. }
  795. if ($var_arg) {
  796. fprintf($f, ', CArrRef _argv /* = null_array */');
  797. }
  798. fprintf($f, ") {\n");
  799. fprintf($f, " throw_not_implemented(__func__);\n");
  800. fprintf($f, "}\n\n");
  801. }
  802. function replaceParams($filename, $header) {
  803. global $funcs;
  804. $orig = $file = file_get_contents($filename);
  805. foreach ($funcs as &$func) {
  806. $var_arg = ($func['flags'] & VarArgsMask);
  807. $args = $func['args'];
  808. $search = '(?!return\s)\b\w+\s+f_'.$func['name'].'\s*\(\s*';
  809. if ($var_arg) $search .= '\w+\s+\w+';
  810. if ($var_arg && count($args) > 0) $search .= ',\s*';
  811. for ($i = 0; $i < count($args); $i++) {
  812. $arg = $args[$i];
  813. $search .= '\w+\s+\w+\s*';
  814. if (isset($arg['default'])) {
  815. if ($header) {
  816. $search .= '=\s*(?:'.preg_quote($arg['default'], '/').'|\d+)\s*';
  817. } else {
  818. $search .= '(?:\/\*\s*=\s*(?:'.preg_quote($arg['default'], '/').
  819. '|\d+)\s*\*\/\s*)?';
  820. }
  821. }
  822. if ($i < count($args) - 1) {
  823. $search .= ',(\s*)';
  824. }
  825. }
  826. if ($var_arg) {
  827. if ($header) {
  828. $search .= ',\s*\w+\s+\w+\s*=\s*null_array\s*';
  829. } else {
  830. $search .= ',(\s*)\w+\s+\w+\s*(?:\/\*\s*=\s*null_array\s*\*\/\s*)?';
  831. }
  832. }
  833. $search .= '\)';
  834. $replace = typename($func['return']).' f_'.$func['name'].'(';
  835. if ($var_arg) $replace .= 'int _argc, ';
  836. for ($i = 0; $i < count($args); $i++) {
  837. $arg = $args[$i];
  838. $replace .= param_typename($arg).' '.$arg['name'];
  839. if (isset($arg['default'])) {
  840. if ($header) {
  841. $replace .= ' = '.addcslashes($arg['default'], '\\');
  842. } else {
  843. $replace .= ' /* = '.addcslashes($arg['default'], '\\').' */';
  844. }
  845. }
  846. if ($i < count($args) - 1) {
  847. $replace .= ',${'.($i+1).'}';
  848. }
  849. }
  850. if ($var_arg) {
  851. if ($header) {
  852. $replace .= ', CArrRef _argv = null_array';
  853. } else {
  854. $replace .= ',${'.($i).'}';
  855. $replace .= 'CArrRef _argv /* = null_array */';
  856. }
  857. }
  858. $replace .= ')';
  859. if ($header && preg_match("/inline\s+$search/ms", $file)) {
  860. $func['inlined'] = true;
  861. }
  862. //var_dump($search, $replace);
  863. $count = preg_match_all("/$search/ms", $file, $m);
  864. if ($count == 0) {
  865. if ($header || !isset($func['inlined'])) {
  866. var_dump($search, $replace);
  867. print $func['name']." not found in $filename\n";
  868. }
  869. } else if ($count == 1) {
  870. $file = preg_replace("/$search/ms", $replace, $file);
  871. } else {
  872. print "skipped ".$func['name']." in $filename\n";
  873. }
  874. }
  875. if ($orig != $file) {
  876. file_put_contents($filename, $file);
  877. }
  878. }
  879. ///////////////////////////////////////////////////////////////////////////////
  880. // helpers
  881. function php_escape_val($val) {
  882. if (is_string($val)) {
  883. return '"'.escape_cpp($val).'"';
  884. } else if ($val === true) {
  885. return 'true';
  886. } else if ($val === false) {
  887. return 'false';
  888. } else if ($val === null) {
  889. return 'uninit_null()';
  890. } else {
  891. return var_export($val, true);
  892. }
  893. }
  894. function escape_php($val) {
  895. $val = preg_replace("/\\\\/", "\\\\\\\\", $val);
  896. $val = preg_replace("/\\\"/", "\\\\\"", $val);
  897. $val = preg_replace("/\\$/", "\\\\$", $val);
  898. $val = preg_replace("/\n/", "\\\\n", $val); // optional
  899. return $val;
  900. }
  901. function escape_cpp($val) {
  902. $len = strlen($val);
  903. $ret = '';
  904. for ($i = 0; $i < $len; $i++) {
  905. $ch = $val[$i];
  906. switch ($ch) {
  907. case "\n": $ret .= "\\n"; break;
  908. case "\r": $ret .= "\\r"; break;
  909. case "\t": $ret .= "\\t"; break;
  910. case "\a": $ret .= "\\a"; break;
  911. case "\b": $ret .= "\\b"; break;
  912. case "\f": $ret .= "\\f"; break;
  913. case "\v": $ret .= "\\v"; break;
  914. case "\0": $ret .= "\\000";break;
  915. case "\"": $ret .= "\\\""; break;
  916. case "\\": $ret .= "\\\\"; break;
  917. case "?": $ret .= "\\?"; break; // avoiding trigraph errors
  918. default:
  919. if (ord($ch) >= 0x20 && ord($ch) <= 0x7F) {
  920. $ret .= $ch;
  921. } else {
  922. $ret .= sprintf("\\%03o", ord($ch));
  923. }
  924. break;
  925. }
  926. }
  927. return $ret;
  928. }
  929. function idx($arr, $idx, $default=null) {
  930. if ($idx === null) {
  931. return $default;
  932. }
  933. if (isset($arr[$idx])) {
  934. return $arr[$idx];
  935. }
  936. return $default;
  937. }
  938. function format_doc_desc($arr, $clsname) {
  939. if (isset($arr['flags']) && $arr['flags'] & HipHopSpecific) {
  940. $desc = "( HipHop specific )\n";
  941. } else {
  942. $clsname = preg_replace('#_#', '-', strtolower($clsname));
  943. $name = preg_replace('#_#', '-', strtolower($arr['name']));
  944. $name = preg_replace('#^--#', '', $name);
  945. $url = "http://php.net/manual/en/$clsname.$name.php";
  946. $desc = "( excerpt from $url )\n";
  947. }
  948. $details = idx($arr, 'desc', '');
  949. if ($details) {
  950. $desc .= "\n$details";
  951. }
  952. return wordwrap($desc, 72)."\n\n";
  953. }
  954. function format_doc_arg($name, $type, $desc) {
  955. $width1 = 12;
  956. $width2 = 8;
  957. if (!$desc) $desc = ' ';
  958. $lines = explode("\n", wordwrap($desc, 72 - $width1 - $width2));
  959. $col = str_pad('@'.$name, $width1 - 1);
  960. $ret = $col;
  961. if (strlen($col) >= $width1) {
  962. $ret .= "\n".str_repeat(' ', $width1 - 1);
  963. }
  964. $col = str_pad(get_php_name($type), $width2 - 1);
  965. $ret .= ' '.$col;
  966. if (strlen($col) >= $width2) {
  967. $ret .= "\n".str_repeat(' ', $width1 + $width2 - 1);
  968. }
  969. $ret .= ' '.$lines[0]."\n";
  970. for ($i = 1; $i < count($lines); $i++) {
  971. $ret .= rtrim(str_repeat(' ', $width1 + $width2) . $lines[$i])."\n";
  972. }
  973. return $ret;
  974. }
  975. function format_doc_comment($text, $indent_spaces = 0) {
  976. $lines = explode("\n", $text);
  977. $indent = str_repeat(' ', $indent_spaces);
  978. $ret = "$indent/**\n";
  979. for ($i = 0; $i < count($lines) - 1; $i++) {
  980. $line = $lines[$i];
  981. $ret .= rtrim("$indent * $line")."\n";
  982. }
  983. $ret .= "$indent */";
  984. return $ret;
  985. }
  986. function get_function_doc_comments($func, $clsname) {
  987. $text = format_doc_desc($func, empty($clsname) ? 'function' : $clsname);
  988. if ($func['args']) {
  989. foreach ($func['args'] as $arg) {
  990. $desc = idx($arg, 'desc', '');
  991. if (idx($func, 'ref')) {
  992. $desc = '(output) ' . $desc;
  993. }
  994. $text .= format_doc_arg($arg['name'], idx($arg, 'type'), $desc);
  995. }
  996. }
  997. $ret = ($func['return'] !== null || !empty($func['ret_desc']));
  998. if ($func['args'] && $ret) {
  999. $text .= "\n";
  1000. }
  1001. if ($ret) {
  1002. $text .= format_doc_arg('return', $func['return'], $func['ret_desc']);
  1003. }
  1004. return format_doc_comment($text, empty($clsname) ? 0 : 2);
  1005. }
  1006. function get_class_doc_comments($class) {
  1007. return format_doc_comment(format_doc_desc($class, 'class'));
  1008. }
  1009. ///////////////////////////////////////////////////////////////////////////////
  1010. // phpnet
  1011. function phpnet_clean($text) {
  1012. $text = preg_replace('#<!--UdmComment.*?/UdmComment-->#s', '', $text);
  1013. $text = preg_replace('#<div class="example-contents">.*?</div>#s',
  1014. '<>', $text);
  1015. $text = preg_replace('#<p class="para">#', '<>', $text);
  1016. $text = preg_replace('#<strong class="note">Note</strong>:#', '', $text);
  1017. $text = preg_replace('#<.+?'.'>#', '', $text);
  1018. $text = preg_replace('#[ \t\n]+#s', ' ', $text);
  1019. $text = preg_replace('# ?<> ?#', "\n\n", $text);
  1020. $text = preg_replace('/&#039;/', "'", $text);
  1021. $text = trim(html_entity_decode($text));
  1022. $text = preg_replace('/[^\t\n -~]/', '', $text);
  1023. $text = preg_replace('/WarningThis/', 'Warning: This', $text);
  1024. return $text;
  1025. }
  1026. function phpnet_get_function_info($name, $clsname = 'function') {
  1027. $clsname = preg_replace('#_#', '-', strtolower($clsname));
  1028. $name = preg_replace('#__#', '', strtolower($name));
  1029. $name = preg_replace('#_#', '-', $name);
  1030. $doc = @file_get_contents("http://php.net/manual/en/$clsname.$name.php");
  1031. if ($doc === false) {
  1032. return array();
  1033. }
  1034. $ret = array();
  1035. if (preg_match('#<div class="refsect1 description"[^>]*>(.*?)'.
  1036. '<div class="refsect1 #s', $doc, $m)) {
  1037. $desc = $m[1];
  1038. if (preg_match('#<p class="para rdfs-comment">(.*)</div>#s', $desc, $m)) {
  1039. $ret['desc'] = phpnet_clean($m[1]);
  1040. }
  1041. }
  1042. if (preg_match('#<div class="refsect1 parameters"[^>]*>(.*?)'.
  1043. '<div class="refsect1 #s', $doc, $m)) {
  1044. $desc = $m[1];
  1045. if (preg_match_all('#<span class="term">\s*<em><code class="parameter">(.*?)</code>#s', $desc, $m)) {
  1046. foreach ($m[1] as $param) {
  1047. $ret['param_names'][] = phpnet_clean($param);
  1048. }
  1049. }
  1050. if (preg_match_all('#<dd>(.*?)</dd>#s', $desc, $m)) {
  1051. foreach ($m[1] as $param) {
  1052. $ret['params'][] = phpnet_clean($param);
  1053. }
  1054. }
  1055. $desc = preg_replace('#<h3.*</h3>#', '', $desc);
  1056. $desc = preg_replace('#<dl>.*</dl>#s', '', $desc);
  1057. $desc = phpnet_clean($desc);
  1058. if (!empty($desc)) {
  1059. $ret['desc'] .= "\n$desc";
  1060. }
  1061. }
  1062. if (preg_match('#<div class="refsect1 returnvalues"[^>]*>(.*?)'.
  1063. '(<div class="refsect1 |<div id="usernotes">)#s', $doc, $m)) {
  1064. $desc = $m[1];
  1065. $desc = preg_replace('#<h3.*</h3>#', '', $desc);
  1066. $ret['ret'] = phpnet_clean($desc);
  1067. }
  1068. return $ret;
  1069. }
  1070. function phpnet_get_class_info($name) {
  1071. $name = preg_replace('#_#', '-', strtolower($name));
  1072. $doc = @file_get_contents("http://php.net/manual/en/class.$name.php");
  1073. if ($doc === false) {
  1074. return array();
  1075. }
  1076. $ret = array(
  1077. 'desc' => '',
  1078. 'props' => array(),
  1079. 'funcs' => array()
  1080. );
  1081. if (preg_match('#<h2 class="title">Introduction</h2>(.*?)'.
  1082. '<div class="section"#s', $doc, $m)) {
  1083. $ret['desc'] = phpnet_clean($m[1]);
  1084. }
  1085. if (preg_match('#"modifier">extends</span>.*?class="classname">(.*?)#s', $doc, $m)) {
  1086. $ret['parent'] = phpnet_clean($m[1]);
  1087. }
  1088. if (preg_match_all('#<var class="varname">(.*?)</var>#s', $doc, $m)) {
  1089. foreach ($m[1] as $prop) {
  1090. $ret['props'][] = phpnet_clean($prop);
  1091. }
  1092. }
  1093. if (preg_match_all(
  1094. '#<a href="'.$name.'\..*?.php">'.$name.'::(.*?)</a>#si',
  1095. $doc, $m)) {
  1096. foreach ($m[1] as $prop) {
  1097. $ret['funcs'][] = phpnet_clean($prop);
  1098. }
  1099. }
  1100. return $ret;
  1101. }
  1102. function phpnet_get_class_desc($name) {
  1103. $name = preg_replace('#_#', '-', strtolower($name));
  1104. $doc = @file_get_contents("http://php.net/manual/en/class.$name.php");
  1105. if ($doc !== false &&
  1106. preg_match('#<h2 class="title">Introduction</h2>(.*?)'.
  1107. '<div class="section"#s', $doc, $m)) {
  1108. return phpnet_clean($m[1]);
  1109. }
  1110. return false;
  1111. }
  1112. function phpnet_get_extension_functions($name) {
  1113. $doc = @file_get_contents("http://www.php.net/manual/en/ref.$name.php");
  1114. if ($doc === false) {
  1115. return array();
  1116. }
  1117. preg_match_all('#<li><a href="function\..*?\.php">(.*?)</a>.*?</li>#',
  1118. $doc, $m);
  1119. return $m[1];
  1120. }
  1121. function phpnet_get_extension_constants($name) {
  1122. $doc = @file_get_contents("http://www.php.net/manual/en/$name.constants.php");
  1123. if ($doc === false) {
  1124. return array();
  1125. }
  1126. preg_match_all('#<code>(.*?)</code>#', $doc, $m);
  1127. return $m[1];
  1128. }
  1129. function phpnet_get_extension_classes($name) {
  1130. $doc = @file_get_contents("http://www.php.net/manual/en/book.$name.php");
  1131. if ($doc === false) {
  1132. return array();
  1133. }
  1134. preg_match_all('#<a href="class.[^"]*.php">(.*?)</a>#', $doc, $m);
  1135. return $m[1];
  1136. }