PageRenderTime 36ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/type_annotation.cpp

https://gitlab.com/0072016/0072016-PHP.LLC
C++ | 467 lines | 389 code | 40 blank | 38 comment | 93 complexity | 25bbc3823b4220b3716e8ee79d9872cb MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2015 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/compiler/type_annotation.h"
  17. #include <vector>
  18. #include "hphp/compiler/code_generator.h"
  19. #include "hphp/util/text-util.h"
  20. #include "hphp/runtime/base/array-data.h"
  21. #include "hphp/runtime/base/type-array.h"
  22. #include "hphp/runtime/base/type-structure.h"
  23. #include "hphp/runtime/base/type-variant.h"
  24. namespace HPHP {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // constructors/destructors
  27. TypeAnnotation::TypeAnnotation(const std::string &name,
  28. TypeAnnotationPtr typeArgs) : m_name(name),
  29. m_typeArgs(typeArgs),
  30. m_typeList(TypeAnnotationPtr()),
  31. m_nullable(false),
  32. m_soft(false),
  33. m_tuple(false),
  34. m_function(false),
  35. m_xhp(false),
  36. m_typevar(false),
  37. m_typeaccess(false),
  38. m_shape(false),
  39. m_clsCnsShapeField(false) { }
  40. std::string TypeAnnotation::vanillaName() const {
  41. // filter out types that should not be exposed to the runtime
  42. if (m_nullable || m_soft || m_typevar || m_function || m_typeaccess) {
  43. return "";
  44. }
  45. if (!strcasecmp(m_name.c_str(), "HH\\mixed") ||
  46. !strcasecmp(m_name.c_str(), "HH\\this")) {
  47. return "";
  48. }
  49. return m_name;
  50. }
  51. std::string TypeAnnotation::fullName() const {
  52. std::string name;
  53. if (m_soft) {
  54. name += '@';
  55. }
  56. if (m_nullable) {
  57. name += '?';
  58. }
  59. if (m_function) {
  60. functionTypeName(name);
  61. } else if (m_typeaccess) {
  62. accessTypeName(name);
  63. } else if (m_xhp) {
  64. xhpTypeName(name);
  65. } else if (m_tuple) {
  66. tupleTypeName(name);
  67. } else if (m_shape) {
  68. shapeTypeName(name);
  69. } else if (m_typeArgs) {
  70. genericTypeName(name);
  71. } else {
  72. name += m_name;
  73. }
  74. return name;
  75. }
  76. MaybeDataType TypeAnnotation::dataType() const {
  77. if (m_function || m_xhp || m_tuple) {
  78. return KindOfObject;
  79. }
  80. if (m_typeArgs) {
  81. return !strcasecmp(m_name.c_str(), "array") ? KindOfArray : KindOfObject;
  82. }
  83. if (m_nullable || m_soft) {
  84. return folly::none;
  85. }
  86. if (!strcasecmp(m_name.c_str(), "null") ||
  87. !strcasecmp(m_name.c_str(), "HH\\void")) {
  88. return KindOfNull;
  89. }
  90. if (!strcasecmp(m_name.c_str(), "HH\\bool")) return KindOfBoolean;
  91. if (!strcasecmp(m_name.c_str(), "HH\\int")) return KindOfInt64;
  92. if (!strcasecmp(m_name.c_str(), "HH\\float")) return KindOfDouble;
  93. if (!strcasecmp(m_name.c_str(), "HH\\num")) return folly::none;
  94. if (!strcasecmp(m_name.c_str(), "HH\\arraykey")) return folly::none;
  95. if (!strcasecmp(m_name.c_str(), "HH\\string")) return KindOfString;
  96. if (!strcasecmp(m_name.c_str(), "array")) return KindOfArray;
  97. if (!strcasecmp(m_name.c_str(), "HH\\resource")) return KindOfResource;
  98. if (!strcasecmp(m_name.c_str(), "HH\\mixed")) return folly::none;
  99. return KindOfObject;
  100. }
  101. void TypeAnnotation::getAllSimpleNames(std::vector<std::string>& names) const {
  102. names.push_back(m_name);
  103. if (m_typeList) {
  104. m_typeList->getAllSimpleNames(names);
  105. } else if (m_typeArgs) {
  106. // do not return the shape fields and keys
  107. if (!m_shape) {
  108. m_typeArgs->getAllSimpleNames(names);
  109. }
  110. }
  111. }
  112. void TypeAnnotation::shapeTypeName(std::string& name) const {
  113. name += "HH\\shape(";
  114. TypeAnnotationPtr shapeField = m_typeArgs;
  115. auto sep = "";
  116. while (shapeField) {
  117. name += sep;
  118. if (shapeField->isClsCnsShapeField()) {
  119. folly::toAppend(shapeField->m_name, &name);
  120. } else {
  121. folly::toAppend("'", shapeField->m_name, "'", &name);
  122. }
  123. auto fieldValue = shapeField->m_typeArgs;
  124. assert(fieldValue);
  125. folly::toAppend("=>", fieldValue->fullName(), &name);
  126. sep = ", ";
  127. shapeField = shapeField->m_typeList;
  128. }
  129. name += ")";
  130. }
  131. void TypeAnnotation::functionTypeName(std::string &name) const {
  132. name += "(function (";
  133. // return value of function types is the first element of type list
  134. TypeAnnotationPtr retType = m_typeArgs;
  135. TypeAnnotationPtr typeEl = m_typeArgs->m_typeList;
  136. auto sep = "";
  137. while (typeEl) {
  138. folly::toAppend(sep, typeEl->fullName(), &name);
  139. typeEl = typeEl->m_typeList;
  140. sep = ", ";
  141. }
  142. // add function return value
  143. folly::toAppend("): ", retType->fullName(), ")", &name);
  144. }
  145. // xhp names are mangled so we get them back to their original definition
  146. // @see the mangling in ScannerToken::xhpLabel
  147. void TypeAnnotation::xhpTypeName(std::string &name) const {
  148. // remove prefix if any
  149. if (m_name.compare(0, sizeof("xhp_") - 1, "xhp_") == 0) {
  150. name += std::string(m_name).replace(0, sizeof("xhp_") - 1, ":");
  151. } else {
  152. name += m_name;
  153. }
  154. // un-mangle back
  155. replaceAll(name, "__", ":");
  156. replaceAll(name, "_", "-");
  157. }
  158. void TypeAnnotation::tupleTypeName(std::string &name) const {
  159. name += "(";
  160. TypeAnnotationPtr typeEl = m_typeArgs;
  161. auto sep = "";
  162. while (typeEl) {
  163. folly::toAppend(sep, typeEl->fullName(), &name);
  164. typeEl = typeEl->m_typeList;
  165. sep = ", ";
  166. }
  167. name += ")";
  168. }
  169. void TypeAnnotation::genericTypeName(std::string &name) const {
  170. folly::toAppend(m_name, "<", &name);
  171. TypeAnnotationPtr typeEl = m_typeArgs;
  172. auto sep = "";
  173. while (typeEl) {
  174. folly::toAppend(sep, typeEl->fullName(), &name);
  175. typeEl = typeEl->m_typeList;
  176. sep = ", ";
  177. }
  178. name += ">";
  179. }
  180. void TypeAnnotation::accessTypeName(std::string &name) const {
  181. name += m_name;
  182. TypeAnnotationPtr typeEl = m_typeArgs;
  183. while (typeEl) {
  184. folly::toAppend("::", typeEl->fullName(), &name);
  185. typeEl = typeEl->m_typeList;
  186. }
  187. }
  188. void TypeAnnotation::appendToTypeList(TypeAnnotationPtr typeList) {
  189. if (m_typeList) {
  190. TypeAnnotationPtr current = m_typeList;
  191. while (current->m_typeList) {
  192. current = current->m_typeList;
  193. }
  194. current->m_typeList = typeList;
  195. } else {
  196. m_typeList = typeList;
  197. }
  198. }
  199. void TypeAnnotation::outputCodeModel(CodeGenerator& cg) {
  200. TypeAnnotationPtr typeArgsElem = m_typeArgs;
  201. auto numTypeArgs = this->numTypeArgs();
  202. auto numProps = 1;
  203. if (m_nullable) numProps++;
  204. if (m_soft) numProps++;
  205. if (m_function) {
  206. numProps++;
  207. // Since this is a function type, the first type argument is the return type
  208. // and no typeArguments property will be serialized unless there are at
  209. // least two type arguments.
  210. if (numTypeArgs > 1) numProps++;
  211. } else {
  212. if (numTypeArgs > 0) numProps++;
  213. }
  214. cg.printObjectHeader("TypeExpression", numProps);
  215. cg.printPropertyHeader("name");
  216. cg.printValue(m_tuple ? "tuple" : m_name);
  217. if (m_nullable) {
  218. cg.printPropertyHeader("isNullable");
  219. cg.printBool(true);
  220. }
  221. if (m_soft) {
  222. cg.printPropertyHeader("isSoft");
  223. cg.printBool(true);
  224. }
  225. if (m_function) {
  226. cg.printPropertyHeader("returnType");
  227. typeArgsElem->outputCodeModel(cg);
  228. typeArgsElem = typeArgsElem->m_typeList;
  229. // Since we've grabbed the first element of the list as the return
  230. // type, make sure that the logic for serializing type arguments gets
  231. // disabled unless there is at least one more type argument.
  232. numTypeArgs--;
  233. }
  234. if (numTypeArgs > 0) {
  235. cg.printPropertyHeader("typeArguments");
  236. cg.printf("V:9:\"HH\\Vector\":%d:{", numTypeArgs);
  237. while (typeArgsElem != nullptr) {
  238. typeArgsElem->outputCodeModel(cg);
  239. typeArgsElem = typeArgsElem->m_typeList;
  240. }
  241. cg.printf("}");
  242. }
  243. cg.printObjectFooter();
  244. }
  245. int TypeAnnotation::numTypeArgs() const {
  246. int n = 0;
  247. TypeAnnotationPtr typeEl = m_typeArgs;
  248. while (typeEl) {
  249. ++n;
  250. typeEl = typeEl->m_typeList;
  251. }
  252. return n;
  253. }
  254. TypeAnnotationPtr TypeAnnotation::getTypeArg(int n) const {
  255. int i = 0;
  256. TypeAnnotationPtr typeEl = m_typeArgs;
  257. while (typeEl) {
  258. if (i == n) {
  259. return typeEl;
  260. }
  261. ++i;
  262. typeEl = typeEl->m_typeList;
  263. }
  264. return TypeAnnotationPtr();
  265. }
  266. bool TypeAnnotation::isPrimType(const char* str) const{
  267. return !strcasecmp(m_name.c_str(), str);
  268. }
  269. TypeStructure::Kind TypeAnnotation::getKind() const {
  270. if (isVoid()) {
  271. return TypeStructure::Kind::T_void;
  272. }
  273. // Primitive types
  274. if (isPrimType("HH\\int")) {
  275. return TypeStructure::Kind::T_int;
  276. }
  277. if (isPrimType("HH\\bool")) {
  278. return TypeStructure::Kind::T_bool;
  279. }
  280. if (isPrimType("HH\\float")) {
  281. return TypeStructure::Kind::T_float;
  282. }
  283. if (isPrimType("HH\\string")) {
  284. return TypeStructure::Kind::T_string;
  285. }
  286. if (isPrimType("HH\\resource")) {
  287. return TypeStructure::Kind::T_resource;
  288. }
  289. if (isPrimType("HH\\num")) {
  290. return TypeStructure::Kind::T_num;
  291. }
  292. if (isPrimType("HH\\arraykey")) {
  293. return TypeStructure::Kind::T_arraykey;
  294. }
  295. if (isPrimType("HH\\noreturn")) {
  296. return TypeStructure::Kind::T_noreturn;
  297. }
  298. if (isMixed()) {
  299. return TypeStructure::Kind::T_mixed;
  300. }
  301. if (m_tuple) {
  302. return TypeStructure::Kind::T_tuple;
  303. }
  304. if (m_function) {
  305. return TypeStructure::Kind::T_fun;
  306. }
  307. if (!strcasecmp(m_name.c_str(), "array")) {
  308. return (m_shape)
  309. ? TypeStructure::Kind::T_shape
  310. : TypeStructure::Kind::T_array;
  311. }
  312. if (m_typevar) {
  313. return TypeStructure::Kind::T_typevar;
  314. }
  315. if (m_typeaccess) {
  316. return TypeStructure::Kind::T_typeaccess;
  317. }
  318. if (m_xhp) {
  319. // TODO(7657500): in the runtime, resolve this type to a class.
  320. return TypeStructure::Kind::T_xhp;
  321. }
  322. return TypeStructure::Kind::T_unresolved;
  323. }
  324. const StaticString
  325. s_nullable("nullable"),
  326. s_kind("kind"),
  327. s_name("name"),
  328. s_classname("classname"),
  329. s_elem_types("elem_types"),
  330. s_return_type("return_type"),
  331. s_param_types("param_types"),
  332. s_generic_types("generic_types"),
  333. s_root_name("root_name"),
  334. s_access_list("access_list"),
  335. s_fields("fields"),
  336. s_is_cls_cns("is_cls_cns"),
  337. s_value("value")
  338. ;
  339. /* Turns the argsList linked list of TypeAnnotation into a positioned
  340. * static array. */
  341. ArrayData* TypeAnnotation::argsListToScalarArray(TypeAnnotationPtr ta) const {
  342. int i = 0;
  343. auto typeargs = Array::Create();
  344. auto typeEl = ta;
  345. while (typeEl) {
  346. typeargs.add(i, Variant(typeEl->getScalarArrayRep()));
  347. ++i;
  348. typeEl = typeEl->m_typeList;
  349. }
  350. return ArrayData::GetScalarArray(typeargs.get());
  351. }
  352. void TypeAnnotation::shapeFieldsToScalarArray(Array& rep,
  353. TypeAnnotationPtr ta) const {
  354. auto fields = Array::Create();
  355. auto shapeField = ta;
  356. while (shapeField) {
  357. assert(shapeField->m_typeArgs);
  358. auto field = Array::Create();
  359. if (shapeField->isClsCnsShapeField()) field.add(s_is_cls_cns, true_varNR);
  360. field.add(s_value, Variant(shapeField->m_typeArgs->getScalarArrayRep()));
  361. fields.add(String(shapeField->m_name), Variant(field.get()));
  362. shapeField = shapeField->m_typeList;
  363. }
  364. rep.add(s_fields, Variant(ArrayData::GetScalarArray(fields.get())));
  365. }
  366. ArrayData* TypeAnnotation::getScalarArrayRep() const {
  367. auto rep = Array::Create();
  368. bool nullable = (bool) m_nullable;
  369. if (nullable) {
  370. rep.add(s_nullable, true_varNR);
  371. }
  372. TypeStructure::Kind kind = getKind();
  373. rep.add(s_kind, Variant(static_cast<uint8_t>(kind)));
  374. switch (kind) {
  375. case TypeStructure::Kind::T_tuple:
  376. assert(m_typeArgs);
  377. rep.add(s_elem_types, Variant(argsListToScalarArray(m_typeArgs)));
  378. break;
  379. case TypeStructure::Kind::T_fun:
  380. assert(m_typeArgs);
  381. // return type is the first of the typeArgs
  382. rep.add(s_return_type, Variant(m_typeArgs->getScalarArrayRep()));
  383. rep.add(s_param_types,
  384. Variant(argsListToScalarArray(m_typeArgs->m_typeList)));
  385. break;
  386. case TypeStructure::Kind::T_array:
  387. if (m_typeArgs) {
  388. rep.add(s_generic_types, Variant(argsListToScalarArray(m_typeArgs)));
  389. }
  390. break;
  391. case TypeStructure::Kind::T_shape:
  392. shapeFieldsToScalarArray(rep, m_typeArgs);
  393. break;
  394. case TypeStructure::Kind::T_typevar:
  395. rep.add(s_name, Variant(m_name));
  396. break;
  397. case TypeStructure::Kind::T_typeaccess: {
  398. // for now, only store the vanilla names (strings) as part of the
  399. // access list
  400. rep.add(s_root_name, Variant(m_name));
  401. auto accList = Array::Create();
  402. auto typeEl = m_typeArgs;
  403. int i = 0;
  404. while (typeEl) {
  405. accList.add(i, Variant(typeEl->vanillaName()));
  406. ++i;
  407. typeEl = typeEl->m_typeList;
  408. }
  409. accList = ArrayData::GetScalarArray(accList.get());
  410. rep.add(s_access_list, Variant(accList));
  411. break;
  412. }
  413. case TypeStructure::Kind::T_xhp:
  414. rep.add(s_classname, Variant(m_name));
  415. break;
  416. case TypeStructure::Kind::T_unresolved:
  417. rep.add(s_classname, Variant(m_name));
  418. if (m_typeArgs) {
  419. rep.add(s_generic_types, Variant(argsListToScalarArray(m_typeArgs)));
  420. }
  421. break;
  422. default:
  423. break;
  424. }
  425. return ArrayData::GetScalarArray(rep.get());
  426. }
  427. }