PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/compiler/expression/static_member_expression.cpp

https://github.com/diegoIta/hiphop-php
C++ | 359 lines | 289 code | 38 blank | 32 comment | 59 complexity | 435a329b8dadf201f35beedd58e2dbf9 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010 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 <compiler/expression/static_member_expression.h>
  17. #include <compiler/expression/simple_variable.h>
  18. #include <compiler/expression/dynamic_variable.h>
  19. #include <compiler/expression/scalar_expression.h>
  20. #include <compiler/analysis/class_scope.h>
  21. #include <compiler/analysis/variable_table.h>
  22. #include <compiler/analysis/code_error.h>
  23. #include <util/util.h>
  24. #include <util/hash.h>
  25. #include <compiler/parser/hphp.tab.hpp>
  26. #include <compiler/analysis/dependency_graph.h>
  27. #include <compiler/option.h>
  28. using namespace HPHP;
  29. using namespace std;
  30. using namespace boost;
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // constructors/destructors
  33. StaticMemberExpression::StaticMemberExpression
  34. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  35. ExpressionPtr classExp, ExpressionPtr exp)
  36. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
  37. StaticClassName(classExp), m_exp(exp), m_valid(false),
  38. m_dynamicClass(false), m_redeclared(false) {
  39. if (exp->is(KindOfSimpleVariable)) {
  40. SimpleVariablePtr s(dynamic_pointer_cast<SimpleVariable>(exp));
  41. m_exp = ExpressionPtr
  42. (new ScalarExpression(getLocation(),
  43. KindOfScalarExpression,
  44. T_STRING, s->getName(), true));
  45. } else {
  46. assert(exp->is(KindOfDynamicVariable));
  47. m_exp = dynamic_pointer_cast<DynamicVariable>(exp)->getSubExpression();
  48. }
  49. }
  50. ExpressionPtr StaticMemberExpression::clone() {
  51. StaticMemberExpressionPtr exp(new StaticMemberExpression(*this));
  52. Expression::deepCopy(exp);
  53. if (m_class) exp->m_class = m_class->clone();
  54. exp->m_exp = m_exp->clone();
  55. return exp;
  56. }
  57. ///////////////////////////////////////////////////////////////////////////////
  58. // parser functions
  59. ///////////////////////////////////////////////////////////////////////////////
  60. // static analysis functions
  61. void StaticMemberExpression::analyzeProgram(AnalysisResultPtr ar) {
  62. if (m_class) {
  63. m_class->analyzeProgram(ar);
  64. } else {
  65. addUserClass(ar, m_className);
  66. }
  67. m_exp->analyzeProgram(ar);
  68. }
  69. ConstructPtr StaticMemberExpression::getNthKid(int n) const {
  70. switch (n) {
  71. case 0:
  72. return m_class;
  73. case 1:
  74. return m_exp;
  75. default:
  76. ASSERT(false);
  77. break;
  78. }
  79. return ConstructPtr();
  80. }
  81. int StaticMemberExpression::getKidCount() const {
  82. return 2;
  83. }
  84. void StaticMemberExpression::setNthKid(int n, ConstructPtr cp) {
  85. switch (n) {
  86. case 0:
  87. m_class = boost::dynamic_pointer_cast<Expression>(cp);
  88. case 1:
  89. m_exp = boost::dynamic_pointer_cast<Expression>(cp);
  90. break;
  91. default:
  92. ASSERT(false);
  93. break;
  94. }
  95. }
  96. ExpressionPtr StaticMemberExpression::preOptimize(AnalysisResultPtr ar) {
  97. if (m_class) {
  98. ar->preOptimize(m_class);
  99. updateClassName();
  100. }
  101. ar->preOptimize(m_exp);
  102. return ExpressionPtr();
  103. }
  104. ExpressionPtr StaticMemberExpression::postOptimize(AnalysisResultPtr ar) {
  105. if (m_class) ar->postOptimize(m_class);
  106. ar->postOptimize(m_exp);
  107. return ExpressionPtr();
  108. }
  109. /**
  110. * static_member can only be one of these two forms:
  111. *
  112. * T::$member
  113. * T::$$member or T::${$member}, where $member can be an arbitrary expression
  114. * The former is represented by a ScalarExpression with value "member",
  115. * the latter by the expression $member.
  116. */
  117. TypePtr StaticMemberExpression::inferTypes(AnalysisResultPtr ar,
  118. TypePtr type, bool coerce) {
  119. ConstructPtr self = shared_from_this();
  120. if (m_class) {
  121. if (m_context & (LValue | RefValue)) {
  122. ar->forceClassVariants();
  123. }
  124. m_class->inferAndCheck(ar, NEW_TYPE(Any), false);
  125. m_exp->inferAndCheck(ar, Type::String, false);
  126. return Type::Variant;
  127. }
  128. m_exp->inferAndCheck(ar, Type::String, false);
  129. ClassScopePtr cls = ar->resolveClass(m_className);
  130. m_valid = true;
  131. if (!cls) {
  132. if (ar->isFirstPass()) {
  133. ar->getCodeError()->record(self, CodeError::UnknownClass, self);
  134. }
  135. m_valid = false;
  136. }
  137. VariableTablePtr variables = ar->getScope()->getVariables();
  138. variables->setAttribute(VariableTable::NeedGlobalPointer);
  139. if (cls) {
  140. if (cls->isRedeclaring()) {
  141. m_redeclared = true;
  142. }
  143. if (cls->derivesFromRedeclaring()) {
  144. m_dynamicClass = true;
  145. }
  146. }
  147. if (m_exp->is(Expression::KindOfScalarExpression)) {
  148. if (!cls) {
  149. m_implementedType.reset();
  150. return Type::Variant;
  151. }
  152. ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(m_exp);
  153. const std::string &name = var->getString();
  154. int p;
  155. TypePtr tp;
  156. if (m_redeclared) {
  157. p = 0;
  158. BOOST_FOREACH(ClassScopePtr clsr,
  159. ar->findRedeclaredClasses(m_className)) {
  160. int p1;
  161. clsr->checkStatic(name, type, coerce, ar, self, p1);
  162. p |= p1;
  163. }
  164. tp = Type::Variant;
  165. } else {
  166. tp = cls->checkStatic(name, type, coerce, ar, self, p);
  167. }
  168. if (ar->isFirstPass() && p && !(p & VariableTable::VariableStatic)) {
  169. ar->getCodeError()->record(self, CodeError::MissingObjectContext, self);
  170. }
  171. m_valid = !p || (p & VariableTable::VariableStatic) ||
  172. m_redeclared || m_dynamicClass;
  173. if (cls->hasProperty(name) || m_redeclared) {
  174. m_resolvedClassName = m_className;
  175. } else {
  176. ClassScopePtr parent = cls->getVariables()->findParent(ar, name);
  177. ASSERT(parent);
  178. m_resolvedClassName = parent->getName();
  179. }
  180. return m_implementedType = tp;
  181. } else if (cls) {
  182. cls->getVariables()->forceVariants(ar);
  183. }
  184. // we have to use a variant to hold dynamic value
  185. return m_implementedType = Type::Variant;
  186. }
  187. unsigned StaticMemberExpression::getCanonHash() const {
  188. int64 val = Expression::getCanonHash() +
  189. hash_string(Util::toLower(m_className).c_str(), m_className.size());
  190. return ~unsigned(val) ^ unsigned(val >> 32);
  191. }
  192. bool StaticMemberExpression::canonCompare(ExpressionPtr e) const {
  193. if (!Expression::canonCompare(e)) return false;
  194. StaticMemberExpressionPtr s =
  195. static_pointer_cast<StaticMemberExpression>(e);
  196. return m_className == s->m_className;
  197. }
  198. ///////////////////////////////////////////////////////////////////////////////
  199. // code generation functions
  200. void StaticMemberExpression::outputPHP(CodeGenerator &cg,
  201. AnalysisResultPtr ar) {
  202. StaticClassName::outputPHP(cg, ar);
  203. cg_printf("::$");
  204. bool needsClose = false;
  205. switch (m_exp->getKindOf()) {
  206. case KindOfScalarExpression:
  207. {
  208. ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(m_exp);
  209. cg_printf("%s", var->getString().c_str());
  210. return;
  211. }
  212. case KindOfSimpleVariable:
  213. case KindOfDynamicVariable:
  214. break;
  215. default:
  216. cg_printf("{");
  217. needsClose = true;
  218. }
  219. m_exp->outputPHP(cg, ar);
  220. if (needsClose) {
  221. cg_printf("}");
  222. }
  223. }
  224. void StaticMemberExpression::preOutputStash(CodeGenerator &cg,
  225. AnalysisResultPtr ar,
  226. int state)
  227. {
  228. if (getContext() & (LValue|RefValue|RefParameter)) return;
  229. Expression::preOutputStash(cg, ar, state);
  230. }
  231. void StaticMemberExpression::outputCPPImpl(CodeGenerator &cg,
  232. AnalysisResultPtr ar) {
  233. if (m_class) {
  234. const char *func_suffix = "";
  235. if (m_context & (LValue | RefValue)) {
  236. func_suffix = "_lval";
  237. }
  238. cg_printf("get_static_property%s(", func_suffix);
  239. if (m_class->is(KindOfScalarExpression)) {
  240. ASSERT(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
  241. getString().c_str(), "static") == 0);
  242. cg_printf("FrameInjection::GetStaticClassName(info).data()");
  243. } else {
  244. cg_printf("get_static_class_name(");
  245. m_class->outputCPP(cg, ar);
  246. cg_printf(").data()");
  247. }
  248. cg_printf(", toString(");
  249. m_exp->outputCPP(cg, ar);
  250. cg_printf(").data())");
  251. return;
  252. }
  253. if (!m_valid) {
  254. if (m_resolvedClassName.empty()) {
  255. cg_printf("throw_fatal(\"unknown class %s\")", m_origClassName.c_str());
  256. } else {
  257. cg_printf("throw_fatal(\"Access to undeclared static property: ");
  258. outputPHP(cg, ar);
  259. cg_printf("\")");
  260. }
  261. return;
  262. }
  263. bool volatileCheck = false;
  264. bool outsideClass = !ar->checkClassPresent(m_origClassName);
  265. ClassScopePtr cls = ClassScopePtr();
  266. if (!m_resolvedClassName.empty()) {
  267. cls = ar->findClass(m_resolvedClassName);
  268. if (cls && outsideClass) {
  269. volatileCheck = cls->isVolatile();
  270. if (volatileCheck) {
  271. ClassScope::OutputVolatileCheckBegin(cg, ar, m_origClassName);
  272. }
  273. }
  274. }
  275. if (m_exp->is(Expression::KindOfScalarExpression) && !m_redeclared &&
  276. !m_dynamicClass) {
  277. ASSERT(cls);
  278. ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(m_exp);
  279. if (cls->needLazyStaticInitializer()) {
  280. cg_printf("%s%s::lazy_initializer(g)->%s%s%s%s",
  281. Option::ClassPrefix,
  282. cg.formatLabel(m_resolvedClassName).c_str(),
  283. Option::StaticPropertyPrefix,
  284. cg.formatLabel(m_resolvedClassName).c_str(),
  285. Option::IdPrefix.c_str(),
  286. cg.formatLabel(var->getString()).c_str());
  287. } else {
  288. cg_printf("g->%s%s%s%s", Option::StaticPropertyPrefix,
  289. cg.formatLabel(m_resolvedClassName).c_str(),
  290. Option::IdPrefix.c_str(),
  291. cg.formatLabel(var->getString()).c_str());
  292. }
  293. } else {
  294. if (m_context & (LValue | RefValue)) {
  295. if (m_redeclared) {
  296. cg_printf("g->%s%s->%slval(", Option::ClassStaticsObjectPrefix,
  297. cg.formatLabel(m_className).c_str(),
  298. Option::ObjectStaticPrefix);
  299. } else {
  300. cg_printf("%s%s::%slval(", Option::ClassPrefix,
  301. cg.formatLabel(m_className).c_str(),
  302. Option::ObjectStaticPrefix);
  303. }
  304. } else {
  305. if (m_redeclared) {
  306. cg_printf("g->%s%s->%sget(", Option::ClassStaticsObjectPrefix,
  307. cg.formatLabel(m_className).c_str(),
  308. Option::ObjectStaticPrefix);
  309. } else {
  310. cg_printf("%s%s::%sget(", Option::ClassPrefix,
  311. cg.formatLabel(m_className).c_str(),
  312. Option::ObjectStaticPrefix);
  313. }
  314. }
  315. m_exp->outputCPP(cg, ar);
  316. cg_printf(", -1)");
  317. }
  318. if (volatileCheck) {
  319. ClassScope::OutputVolatileCheckEnd(cg);
  320. }
  321. }