PageRenderTime 909ms CodeModel.GetById 22ms RepoModel.GetById 2ms app.codeStats 0ms

/hphp/tools/bootstrap/idl.cpp

http://github.com/facebook/hiphop-php
C++ | 789 lines | 748 code | 23 blank | 18 comment | 37 complexity | bc708dba07565bc10cbe327d1d3d39f1 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. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/tools/bootstrap/idl.h"
  17. #include <fstream>
  18. #include <unordered_map>
  19. #include <unordered_set>
  20. #include "folly/Format.h"
  21. #include "folly/json.h"
  22. #ifdef __APPLE__
  23. #define INT64_TYPE "long long"
  24. #else
  25. #define INT64_TYPE "long"
  26. #endif
  27. namespace HPHP { namespace IDL {
  28. /////////////////////////////////////////////////////////////////////////////
  29. static const std::unordered_map<fbstring, DataType> g_kindOfMap =
  30. {
  31. {"Boolean", KindOfBoolean},
  32. {"Int32", KindOfInt64},
  33. {"Int64", KindOfInt64},
  34. {"Double", KindOfDouble},
  35. {"String", KindOfString},
  36. {"Int64Vec", KindOfArray},
  37. {"StringVec", KindOfArray},
  38. {"VariantVec", KindOfArray},
  39. {"Int64Map", KindOfArray},
  40. {"StringMap", KindOfArray},
  41. {"VariantMap", KindOfArray},
  42. {"Object", KindOfObject},
  43. {"Resource", KindOfResource},
  44. {"Variant", KindOfAny},
  45. {"Numeric", KindOfAny},
  46. {"Primitive", KindOfAny},
  47. {"PlusOperand", KindOfAny},
  48. {"Sequence", KindOfAny},
  49. {"Any", KindOfAny},
  50. };
  51. static const std::unordered_map<int, fbstring> g_typeMap =
  52. {
  53. {(int)KindOfInvalid, "void"},
  54. {(int)KindOfNull, "HPHP::Variant"},
  55. {(int)KindOfBoolean, "bool"},
  56. {(int)KindOfInt64, INT64_TYPE},
  57. {(int)KindOfDouble, "double"},
  58. {(int)KindOfString, "HPHP::String"},
  59. {(int)KindOfArray, "HPHP::Array"},
  60. {(int)KindOfObject, "HPHP::Object"},
  61. {(int)KindOfResource, "HPHP::Resource"},
  62. {(int)KindOfAny, "HPHP::Variant"},
  63. };
  64. static const std::unordered_map<int, fbstring> g_phpTypeMap =
  65. {
  66. {(int)KindOfInvalid, "void"},
  67. {(int)KindOfNull, "void"},
  68. {(int)KindOfBoolean, "bool"},
  69. {(int)KindOfInt64, INT64_TYPE},
  70. {(int)KindOfDouble, "double"},
  71. {(int)KindOfString, "String"},
  72. {(int)KindOfArray, "Array"},
  73. {(int)KindOfObject, "Object"},
  74. {(int)KindOfResource, "Resource"},
  75. {(int)KindOfAny, "mixed"},
  76. };
  77. static const std::unordered_map<fbstring, FuncFlags> g_flagsMap =
  78. {
  79. {"ZendParamMode", ZendParamMode},
  80. {"ZendCompat", ZendCompat},
  81. {"IsAbstract", IsAbstract},
  82. {"IsFinal", IsFinal},
  83. {"IsPublic", IsPublic},
  84. {"IsProtected", IsProtected},
  85. {"IsPrivate", IsPrivate},
  86. {"IgnoreRedefinition", IgnoreRedefinition},
  87. {"IsStatic", IsStatic},
  88. {"IsCppAbstract", IsCppAbstract},
  89. {"IsReference", IsReference},
  90. {"IsConstructor", IsConstructor},
  91. {"IsNothing", IsNothing},
  92. {"IsCppSerializable", IsCppSerializable},
  93. {"HipHopSpecific", HipHopSpecific},
  94. {"VariableArguments", VariableArguments},
  95. {"RefVariableArguments", RefVariableArguments},
  96. {"MixedVariableArguments", MixedVariableArguments},
  97. {"FunctionIsFoldable", FunctionIsFoldable},
  98. {"NoEffect", NoEffect},
  99. {"NoInjection", NoInjection},
  100. {"HasOptFunction", HasOptFunction},
  101. {"AllowIntercept", AllowIntercept},
  102. {"NoProfile", NoProfile},
  103. {"ContextSensitive", ContextSensitive},
  104. {"NoDefaultSweep", NoDefaultSweep},
  105. {"IsSystem", IsSystem},
  106. {"IsTrait", IsTrait},
  107. {"NeedsActRec", NeedsActRec},
  108. };
  109. static const std::unordered_set<fbstring> g_knownStringConstants =
  110. { "k_HPHP_TRIM_CHARLIST" };
  111. bool isKindOfIndirect(DataType kindof) {
  112. return (kindof != KindOfBoolean) &&
  113. (kindof != KindOfInt64) &&
  114. (kindof != KindOfDouble) &&
  115. (kindof != KindOfInvalid) &&
  116. (kindof != KindOfNull);
  117. }
  118. // Parse type from a descriptive string, e.g. "int", "bool", etc...
  119. static DataType kindOfFromDynamic(const folly::dynamic& t) {
  120. if (!t.isString()) {
  121. return KindOfInvalid;
  122. }
  123. auto it = g_kindOfMap.find(t.asString());
  124. if (it == g_kindOfMap.end()) {
  125. return KindOfObject;
  126. }
  127. return it->second;
  128. }
  129. // Infer type from an actual value, e.g. 123, "foo", null, true, etc...
  130. static DataType kindOfFromValue(const folly::dynamic& v) {
  131. if (v.isNull()) {
  132. return KindOfNull;
  133. }
  134. if (v.isBool()) {
  135. return KindOfBoolean;
  136. }
  137. if (v.isInt()) {
  138. return KindOfInt64;
  139. }
  140. if (v.isDouble()) {
  141. return KindOfDouble;
  142. }
  143. if (v.isString()) {
  144. return KindOfString;
  145. }
  146. if (v.isArray()) {
  147. return KindOfArray;
  148. }
  149. if (v.isObject()) {
  150. return KindOfObject;
  151. }
  152. return KindOfInvalid;
  153. }
  154. static fbstring phpTypeFromDataType(DataType dt) {
  155. auto it = g_phpTypeMap.find((int)dt);
  156. if (it == g_phpTypeMap.end()) {
  157. return "mixed";
  158. }
  159. return it->second;
  160. }
  161. static fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
  162. if (typeNode == "Int32") {
  163. return "int";
  164. }
  165. DataType kindof = kindOfFromDynamic(typeNode);
  166. auto it = g_typeMap.find((int)kindof);
  167. assert(it != g_typeMap.end());
  168. auto& type = it->second;
  169. if (!isReturnType && isKindOfIndirect(kindof)) {
  170. return type + " const&";
  171. } else {
  172. return type;
  173. }
  174. }
  175. static unsigned long parseFlags(const folly::dynamic &flags) {
  176. if (flags.isNull()) {
  177. return 0;
  178. }
  179. if (!flags.isArray()) {
  180. throw std::logic_error("'flags' field must be an array");
  181. }
  182. unsigned long ret = 0;
  183. for (auto &flag : flags) {
  184. auto f = g_flagsMap.find(flag.asString());
  185. if (f == g_flagsMap.end()) {
  186. throw std::logic_error(
  187. folly::format("Unknown flag '{0}' specified", flag.asString()).str()
  188. );
  189. }
  190. ret |= f->second;
  191. }
  192. return ret;
  193. }
  194. static const std::unordered_map<fbstring,fbstring> g_serializedDefaults = {
  195. {"true", "b:1;"},
  196. {"false", "b:0;"},
  197. {"null", "N;"},
  198. {"empty_array", "a:0:{}"},
  199. {"null_string", "N;"},
  200. {"null_array", "N;"},
  201. {"null_object", "N;"},
  202. {"null_resource", "N;"},
  203. {"null_variant", "N;"},
  204. {"INT_MAX", "i:2147483647;"}, // (1 << 31) - 1
  205. };
  206. static const std::unordered_map<fbstring,fbstring> g_phpDefaults = {
  207. {"true", "true"},
  208. {"false", "false"},
  209. {"null", "null"},
  210. {"empty_array", "array()"},
  211. {"null_string", "null"},
  212. {"null_array", "null"},
  213. {"null_object", "null"},
  214. {"null_resource", "null"},
  215. {"null_variant", "null"},
  216. {"INT_MAX", "null"},
  217. };
  218. static fbstring unescapeString(fbstring val) {
  219. fbstring s = "";
  220. for (int i = 0; i < val.size(); ) {
  221. int ch = val[i++];
  222. if (ch == '\\') {
  223. if (i == val.size()) {
  224. throw std::logic_error(
  225. folly::format("Malformed string: '{0}'", val).str());
  226. }
  227. ch = val[i++];
  228. switch (ch) {
  229. case 'n': ch = '\n'; break;
  230. case 'r': ch = '\r'; break;
  231. case 't': ch = '\t'; break;
  232. case '/':
  233. case '"':
  234. case '\'':
  235. case '\\':break;
  236. case '0':
  237. ch = 0;
  238. if (i == val.size() ||
  239. (!isdigit(val[i]) && val[i] != 'x' && val[i] != 'X')) {
  240. break;
  241. }
  242. // fall through
  243. default:
  244. throw std::logic_error(
  245. folly::format("Malformed string: '{0}'", val).str());
  246. break;
  247. }
  248. }
  249. s += (char)ch;
  250. }
  251. return s;
  252. }
  253. /**
  254. * From idl/base.php:get_serialized_default()
  255. */
  256. fbstring PhpParam::getDefaultSerialized() const {
  257. auto valIt = m_param.find("value");
  258. if (valIt == m_param.items().end()) {
  259. return ""; // No default
  260. }
  261. auto dval = valIt->second;
  262. if (!dval.isString()) {
  263. throw std::logic_error(
  264. folly::format("Parameter '{0}' default value is non-string",
  265. m_name).str()
  266. );
  267. }
  268. auto val = dval.asString();
  269. if (!val.size()) {
  270. throw std::logic_error(
  271. folly::format("Parameter '{0}' default value malformed (empty string), "
  272. "specify \"\" as default value for actual empty string",
  273. m_name).str()
  274. );
  275. }
  276. // Function calls "foo()" or "foo::bar()" to C/C++ functions/static methods,
  277. // a constant, or a bitmask of constants
  278. //
  279. // Used by ext_reflection to resolve the value at runtime or
  280. // represent the function/method call.
  281. if ((val.size() > 2) &&
  282. (!strncmp(val.c_str(), "k_", 2) ||
  283. !strncmp(val.c_str(), "q_", 2) ||
  284. !strcmp(val.c_str() + val.size() - 2, "()"))) {
  285. return "\x01";
  286. }
  287. // Fixed substitutions
  288. auto it = g_serializedDefaults.find(val);
  289. if (it != g_serializedDefaults.end()) {
  290. return it->second;
  291. }
  292. if (val == "RAND_MAX") {
  293. return folly::to<fbstring>("i:", RAND_MAX, ";");
  294. }
  295. // Quoted string: "foo"
  296. if ((val.size() >= 2) && (val[0] == '"') && (val[val.size()-1] == '"')) {
  297. auto s = unescapeString(val.substr(1, val.size() - 2));
  298. return phpSerialize(s);
  299. }
  300. // Integers and Floats
  301. if (strchr(val.c_str(), '.')) {
  302. // Decimal float?
  303. char *e = nullptr;
  304. double dval = strtod(val.c_str(), &e);
  305. if (e && !*e) {
  306. return folly::to<fbstring>("d:", dval, ";");
  307. }
  308. }
  309. if (val[0] == '0') {
  310. if ((val.size() > 1) && (val[1] == 'x')) {
  311. // Hex?
  312. char *e = nullptr;
  313. long lval = strtol(val.c_str() + 2, &e, 16);
  314. if (e && !*e) {
  315. return folly::to<fbstring>("i:", lval, ";");
  316. }
  317. } else {
  318. // Octal?
  319. char *e = nullptr;
  320. long lval = strtol(val.c_str() + 1, &e, 8);
  321. if (e && !*e) {
  322. return folly::to<fbstring>("i:", lval, ";");
  323. }
  324. }
  325. }
  326. // Decimal?
  327. char *e = nullptr;
  328. long lval = strtol(val.c_str(), &e, 10);
  329. if (e && !*e) {
  330. return folly::to<fbstring>("i:", lval, ";");
  331. }
  332. throw std::logic_error(
  333. folly::format("'{0}' is not a valid default arg value", val).str()
  334. );
  335. }
  336. static fbstring transformConstants(const fbstring val) {
  337. fbstring ret = val;
  338. int i = 0;
  339. int len = ret.size();
  340. while (i < len) {
  341. while ((i < len) && (ret[i] == ' ')) i++;
  342. if ((len - i) < 2) break;
  343. if ((ret[i+1] == '_') &&
  344. ((ret[i] == 'k') || (ret[i] == 'q'))) {
  345. ret[i] = ret[i+1] = ' ';
  346. }
  347. while ((i < len) && (ret[i] != '|')) {
  348. if (ret[i] == '$') {
  349. ret[i] = ':';
  350. }
  351. i++;
  352. }
  353. i++;
  354. }
  355. return ret;
  356. }
  357. fbstring PhpParam::getDefaultPhp() const {
  358. fbstring val = getDefault();
  359. if (!val.size()) {
  360. return "";
  361. }
  362. auto it = g_phpDefaults.find(val);
  363. if (it != g_phpDefaults.end()) {
  364. return it->second;
  365. }
  366. if (val == "RAND_MAX") {
  367. return folly::to<fbstring>(RAND_MAX);
  368. }
  369. if ((val.size() > 2) && (val[1] == '_') &&
  370. ((val[0] == 'k') || (val[0] == 'q'))) {
  371. return transformConstants(val);
  372. }
  373. return val;
  374. }
  375. fbstring phpSerialize(const folly::dynamic& d) {
  376. if (d.isNull()) {
  377. return "N;";
  378. }
  379. if (d.isBool()) {
  380. return d.asBool() ? "b:1;" : "b:0;";
  381. }
  382. if (d.isInt()) {
  383. return "i:" + d.asString() + ";";
  384. }
  385. if (d.isDouble()) {
  386. return "d:" + d.asString() + ";";
  387. }
  388. if (d.isString()) {
  389. auto str = d.asString();
  390. return folly::to<fbstring>("s:", str.size(), ":\"", str, "\";");
  391. }
  392. if (d.isArray()) {
  393. fbstring ret = folly::to<fbstring>("a:", d.size(), ":{");
  394. int i = 0;
  395. for (auto &v : d) {
  396. ret += folly::to<fbstring>("i:", i, ";", phpSerialize(v));
  397. }
  398. return ret + "};";
  399. }
  400. if (d.isObject()) {
  401. fbstring ret = folly::to<fbstring>("a:", d.size(), ":{");
  402. int nextindex = 0;
  403. for (auto &k : d.keys()) {
  404. if (k.isNull()) {
  405. ret += "i:0;";
  406. if (nextindex <= 0) {
  407. nextindex = 1;
  408. }
  409. } else if (k.isInt() || k.isDouble()) {
  410. int i = k.asInt();
  411. ret += folly::to<fbstring>("i:", i, ";");
  412. if (nextindex <= i) {
  413. nextindex = i + 1;
  414. }
  415. } else if (k.isString()) {
  416. ret += folly::to<fbstring>("s:", k.size(), ":\"",
  417. escapeCpp(k.asString()), "\";");
  418. } else {
  419. /* Should never be reached, but cover it to be safe */
  420. ret += folly::to<fbstring>("i:", nextindex++, ";");
  421. }
  422. ret += phpSerialize(d[k]);
  423. }
  424. return ret + "};";
  425. }
  426. throw std::logic_error("Unhandled dynamic type in php serialization");
  427. return "N;";
  428. }
  429. static fbstring getFollyDynamicDefaultString(const folly::dynamic& d,
  430. const fbstring& key,
  431. const fbstring& def) {
  432. auto it = d.find(key);
  433. if (it == d.items().end()) {
  434. return def;
  435. }
  436. auto val = it->second;
  437. if (val.isNull()) {
  438. return def;
  439. }
  440. return val.asString();
  441. }
  442. /////////////////////////////////////////////////////////////////////////////
  443. // PhpConst
  444. bool PhpConst::parseType(const folly::dynamic& cns) {
  445. auto it = cns.find("type");
  446. if (it != cns.items().end()) {
  447. m_kindOf = kindOfFromDynamic(it->second);
  448. m_cppType = typeString(it->second, false);
  449. return true;
  450. }
  451. return false;
  452. }
  453. bool PhpConst::inferType(const folly::dynamic& cns) {
  454. auto it = cns.find("value");
  455. if (it != cns.items().end()) {
  456. m_kindOf = kindOfFromValue(it->second);
  457. auto typeIt = g_typeMap.find((int)m_kindOf);
  458. if (typeIt != g_typeMap.end()) {
  459. m_cppType = typeIt->second;
  460. return true;
  461. }
  462. }
  463. return false;
  464. }
  465. PhpConst::PhpConst(const folly::dynamic& cns,
  466. fbstring cls /* = "" */) :
  467. m_constant(cns),
  468. m_name(cns["name"].asString()),
  469. m_className(cls) {
  470. if (!parseType(cns) && !inferType(cns)) {
  471. // Constant has neither explicit type nor implicit type from 'value'
  472. assert(false);
  473. m_kindOf = KindOfInvalid;
  474. m_cppType = "void";
  475. }
  476. // Override typeString()'s selection for string values
  477. if (m_kindOf == KindOfString) {
  478. m_cppType = "HPHP::StaticString";
  479. }
  480. }
  481. /////////////////////////////////////////////////////////////////////////////
  482. // PhpParam
  483. PhpParam::PhpParam(const folly::dynamic& param,
  484. bool isMagicMethod /*= false */,
  485. ParamMode paramMode /*= CoerceAndCall */) :
  486. m_name(param["name"].asString()),
  487. m_param(param),
  488. m_desc(getFollyDynamicDefaultString(param, "desc", "")),
  489. m_paramMode(paramMode) {
  490. if (isMagicMethod) {
  491. m_kindOf = KindOfAny;
  492. m_cppType = "HPHP::Variant";
  493. return;
  494. }
  495. if (isRef()) {
  496. m_kindOf = KindOfRef;
  497. m_cppType = "HPHP::VRefParamValue const&";
  498. } else {
  499. m_kindOf = kindOfFromDynamic(param["type"]);
  500. m_cppType = typeString(param["type"], false);
  501. }
  502. m_phpType = phpTypeFromDataType(m_kindOf);
  503. }
  504. bool PhpParam::defValueNeedsVariable() const {
  505. DataType cppKindOf = kindOf();
  506. if (!hasDefault() || !isIndirectPass()) {
  507. return false;
  508. }
  509. fbstring defVal = getDefault();
  510. if (cppKindOf == KindOfString &&
  511. ((defVal == "empty_string") ||
  512. (defVal == "null_string") ||
  513. (g_knownStringConstants.count(defVal) > 0))) {
  514. return false;
  515. }
  516. if ((cppKindOf == KindOfArray) && (defVal == "null_array")) {
  517. return false;
  518. }
  519. if ((cppKindOf == KindOfObject) && (defVal == "null_object")) {
  520. return false;
  521. }
  522. if ((cppKindOf == KindOfResource) && (defVal == "null_resource")) {
  523. return false;
  524. }
  525. if ((cppKindOf == KindOfAny) && (defVal == "null_variant")) {
  526. return false;
  527. }
  528. return true;
  529. }
  530. /////////////////////////////////////////////////////////////////////////////
  531. // PhpFunc
  532. PhpFunc::PhpFunc(const folly::dynamic& d,
  533. const fbstring& className) :
  534. m_name(d["name"].asString()),
  535. m_className(className),
  536. m_func(d),
  537. m_desc(getFollyDynamicDefaultString(d, "desc", "")),
  538. m_returnRef(d.getDefault("ref", "false") == "true"),
  539. m_returnKindOf(KindOfNull),
  540. m_returnCppType("void"),
  541. m_returnPhpType("void"),
  542. m_minNumParams(0),
  543. m_numTypeChecks(0) {
  544. auto returnIt = d.find("return");
  545. if (returnIt != d.items().end()) {
  546. auto retNode = returnIt->second;
  547. auto typeIt = retNode.find("type");
  548. if (typeIt != retNode.items().end()) {
  549. auto type = typeIt->second;
  550. if ((type.isString()) && (type != "void") && (type != "null")) {
  551. m_returnKindOf = m_returnRef ? KindOfRef : kindOfFromDynamic(type);
  552. m_returnCppType = typeString(type, true);
  553. m_returnPhpType = phpTypeFromDataType(m_returnKindOf);
  554. }
  555. }
  556. m_returnDesc = getFollyDynamicDefaultString(retNode, "desc", "");
  557. }
  558. auto args = d.find("args");
  559. if (args == d.items().end() || !args->second.isArray()) {
  560. throw std::logic_error(
  561. folly::format("'{0}' must have an array field 'args'", name()).str()
  562. );
  563. }
  564. auto ret = d.find("return");
  565. if (ret == d.items().end() || !ret->second.isObject() ||
  566. ret->second.find("type") == ret->second.items().end()) {
  567. throw std::logic_error(
  568. folly::format("'{0}' must have an array field 'return', which must have "
  569. "a string field 'type'", name()).str()
  570. );
  571. }
  572. bool magic = isMagicMethod();
  573. m_flags = parseFlags(m_func["flags"]);
  574. ParamMode paramMode = (m_flags & ZendParamMode) ?
  575. ParamMode::Zend : ParamMode::CoerceAndCall;
  576. for (auto &p : args->second) {
  577. PhpParam param(p, magic, paramMode);
  578. m_params.push_back(param);
  579. if (!param.hasDefault()) {
  580. ++m_minNumParams;
  581. }
  582. if (param.isCheckedType()) {
  583. ++m_numTypeChecks;
  584. }
  585. }
  586. }
  587. fbstring PhpFunc::getCppSig() const {
  588. std::ostringstream out;
  589. fbstring nm = name();
  590. fbstring lowername = nm;
  591. std::transform(nm.begin(), nm.end(), lowername.begin(),
  592. std::ptr_fun<int, int>(std::tolower));
  593. if (!isMethod()) {
  594. out << "HPHP::f_" << lowername << "(";
  595. } else {
  596. if (isStatic()) {
  597. out << "HPHP::c_" << className() << "::ti_" << lowername << "(";
  598. } else {
  599. out << "HPHP::c_" << className() << "::t_" << lowername << "(";
  600. }
  601. }
  602. bool firstParam = true;
  603. if (isVarArgs()) {
  604. if (!firstParam) {
  605. out << ", ";
  606. }
  607. out << "int";
  608. firstParam = false;
  609. }
  610. for (auto const& param : m_params) {
  611. if (!firstParam) {
  612. out << ", ";
  613. }
  614. out << param.getCppType();
  615. firstParam = false;
  616. }
  617. if (isVarArgs()) {
  618. assert(!firstParam);
  619. out << ", HPHP::Array const&";
  620. }
  621. out << ")";
  622. return out.str();
  623. }
  624. /////////////////////////////////////////////////////////////////////////////
  625. // PhpProp
  626. PhpProp::PhpProp(const folly::dynamic& d, fbstring cls) :
  627. m_name(d["name"].asString()),
  628. m_className(cls),
  629. m_prop(d),
  630. m_flags(parseFlags(m_prop["flags"])),
  631. m_kindOf(kindOfFromDynamic(m_prop["type"])) {
  632. }
  633. /////////////////////////////////////////////////////////////////////////////
  634. // PhpClass
  635. PhpClass::PhpClass(const folly::dynamic &c) :
  636. m_class(c),
  637. m_name(c["name"].asString()),
  638. m_flags(parseFlags(m_class["flags"])),
  639. m_desc(getFollyDynamicDefaultString(c, "desc", "")) {
  640. auto ifacesIt = m_class.find("ifaces");
  641. if (ifacesIt != m_class.items().end()) {
  642. auto ifaces = ifacesIt->second;
  643. if (!ifaces.isArray()) {
  644. throw std::logic_error(
  645. folly::format("Class {0}.ifaces field must be an array", m_name).str()
  646. );
  647. }
  648. for (auto &interface : ifaces) {
  649. m_ifaces.push_back(interface.asString());
  650. }
  651. }
  652. for (auto const& f : c["funcs"]) {
  653. PhpFunc func(f, m_name);
  654. m_methods.push_back(func);
  655. }
  656. if (c.find("consts") != c.items().end()) {
  657. for (auto const& cns : c["consts"]) {
  658. PhpConst cons(cns, m_name);
  659. m_constants.push_back(cons);
  660. }
  661. }
  662. if (c.find("properties") != c.items().end()) {
  663. for (auto const& prp : c["properties"]) {
  664. PhpProp prop(prp, m_name);
  665. m_properties.push_back(prop);
  666. }
  667. }
  668. }
  669. /////////////////////////////////////////////////////////////////////////////
  670. void parseIDL(const char* idlFilePath,
  671. fbvector<PhpFunc>& funcVec,
  672. fbvector<PhpClass>& classVec,
  673. fbvector<PhpConst>& constVec,
  674. fbvector<PhpExtension>& extVec) {
  675. std::ostringstream jsonString;
  676. std::ifstream infile(idlFilePath);
  677. infile >> jsonString.rdbuf();
  678. auto parsed = folly::parseJson(jsonString.str());
  679. for (auto const& f : parsed["funcs"]) {
  680. PhpFunc func(f, "");
  681. funcVec.push_back(func);
  682. }
  683. for (auto const& c : parsed["classes"]) {
  684. PhpClass klass(c);
  685. classVec.push_back(klass);
  686. }
  687. for (auto const& c : parsed["consts"]) {
  688. PhpConst cns(c);
  689. constVec.push_back(cns);
  690. }
  691. auto it = parsed.find("extension");
  692. if (it != parsed.items().end()) {
  693. PhpExtension ext(it->second);
  694. extVec.push_back(ext);
  695. }
  696. }
  697. void parseIDL(const char* idlFilePath,
  698. fbvector<PhpFunc>& funcVec,
  699. fbvector<PhpClass>& classVec) {
  700. fbvector<PhpConst> consts; // dummy
  701. fbvector<PhpExtension> exts; // dummy
  702. parseIDL(idlFilePath, funcVec, classVec, consts, exts);
  703. }
  704. /////////////////////////////////////////////////////////////////////////////
  705. }} // namespace HPHP::IDL