PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/compiler/expression/list_assignment.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 301 lines | 216 code | 26 blank | 59 comment | 34 complexity | 3958cecdc8708179f116b6b8e95b3014 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 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/expression/list_assignment.h"
  17. #include "hphp/compiler/expression/assignment_expression.h"
  18. #include "hphp/compiler/expression/expression_list.h"
  19. #include "hphp/compiler/analysis/file_scope.h"
  20. #include "hphp/compiler/analysis/function_scope.h"
  21. #include "hphp/compiler/expression/array_element_expression.h"
  22. #include "hphp/compiler/expression/object_property_expression.h"
  23. #include "hphp/compiler/expression/unary_op_expression.h"
  24. #include "hphp/compiler/expression/binary_op_expression.h"
  25. #include "hphp/parser/hphp.tab.hpp"
  26. using namespace HPHP;
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // constructors/destructors
  29. /*
  30. Determine whether the rhs behaves normally, or abnormally.
  31. 1) If the expression is the silence operator, recurse on the inner expression.
  32. 2) If the expression is a list assignment expression, recurse on the
  33. RHS of the expression.
  34. 3) If the expression is one of the following, then E behaves normally:
  35. Simple/Dynamic variable (including $this and superglobals)
  36. Array element expression
  37. Property expression
  38. Static variable expression
  39. Function call expression
  40. Preinc/predec expression (but not postinc/postdec)
  41. Assignment expression
  42. Assignment op expression
  43. Binding assignment expression
  44. Include/require expression
  45. Eval expression
  46. Array expression
  47. Array cast expression
  48. 4) For all other expressions, E behaves abnormally. This includes:
  49. All binary operator expressions
  50. All unary operator expressions except silence and preinc/predec
  51. Scalar expression of type null, bool, int, double, or string
  52. Qop expression (?:)
  53. Constant expression
  54. Class constant expression
  55. Isset or empty expression
  56. Exit expression
  57. Instanceof expression
  58. */
  59. static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
  60. switch (rhs->getKindOf()) {
  61. case Construct::KindOfSimpleVariable:
  62. case Construct::KindOfDynamicVariable:
  63. case Construct::KindOfArrayElementExpression:
  64. case Construct::KindOfObjectPropertyExpression:
  65. case Construct::KindOfStaticMemberExpression:
  66. case Construct::KindOfSimpleFunctionCall:
  67. case Construct::KindOfDynamicFunctionCall:
  68. case Construct::KindOfObjectMethodExpression:
  69. case Construct::KindOfNewObjectExpression:
  70. case Construct::KindOfAssignmentExpression:
  71. case Construct::KindOfExpressionList:
  72. case Construct::KindOfIncludeExpression:
  73. case Construct::KindOfYieldExpression:
  74. case Construct::KindOfAwaitExpression:
  75. case Construct::KindOfQueryExpression:
  76. return ListAssignment::Regular;
  77. case Construct::KindOfListAssignment:
  78. return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());
  79. case Construct::KindOfUnaryOpExpression: {
  80. UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(rhs));
  81. switch (u->getOp()) {
  82. case '@':
  83. return GetRHSKind(u->getExpression());
  84. case T_INC:
  85. case T_DEC:
  86. return u->getFront() ?
  87. ListAssignment::Regular : ListAssignment::Checked;
  88. case T_EVAL:
  89. case T_ARRAY:
  90. case T_ARRAY_CAST:
  91. return ListAssignment::Regular;
  92. default:
  93. return ListAssignment::Null;
  94. }
  95. break;
  96. }
  97. case Construct::KindOfBinaryOpExpression: {
  98. BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(rhs));
  99. if (b->isAssignmentOp() ||
  100. b->getOp() == '+' ||
  101. b->getOp() == T_COLLECTION) {
  102. return ListAssignment::Regular;
  103. }
  104. return ListAssignment::Null;
  105. }
  106. case Construct::KindOfQOpExpression:
  107. return ListAssignment::Checked;
  108. // invalid context
  109. case Construct::KindOfExpression:
  110. case Construct::KindOfArrayPairExpression:
  111. case Construct::KindOfParameterExpression:
  112. case Construct::KindOfModifierExpression:
  113. case Construct::KindOfUserAttribute:
  114. case Construct::KindOfFromClause:
  115. case Construct::KindOfLetClause:
  116. case Construct::KindOfWhereClause:
  117. case Construct::KindOfSelectClause:
  118. case Construct::KindOfIntoClause:
  119. case Construct::KindOfJoinClause:
  120. case Construct::KindOfGroupClause:
  121. case Construct::KindOfOrderbyClause:
  122. case Construct::KindOfOrdering:
  123. always_assert(false);
  124. // non-arrays
  125. case Construct::KindOfScalarExpression:
  126. case Construct::KindOfConstantExpression:
  127. case Construct::KindOfClassConstantExpression:
  128. case Construct::KindOfEncapsListExpression:
  129. case Construct::KindOfClosureExpression:
  130. return ListAssignment::Null;
  131. #define STATEMENT_CASE(x) case Construct::KindOf##x:
  132. DECLARE_STATEMENT_TYPES(STATEMENT_CASE) {
  133. always_assert(false);
  134. }
  135. #undef STATEMENT_CASE
  136. }
  137. // unreachable for known expression kinds
  138. always_assert(false);
  139. }
  140. static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) {
  141. for (int i = 0; i < vars->getCount(); i++) {
  142. ExpressionPtr v = (*vars)[i];
  143. if (!v) continue;
  144. if (v->is(Construct::KindOfSimpleVariable) &&
  145. v->canonCompare(var)) {
  146. return true;
  147. }
  148. if (v->is(Construct::KindOfDynamicVariable)) return true;
  149. if (v->is(Construct::KindOfListAssignment) &&
  150. AssignmentCouldSet(static_pointer_cast<ListAssignment>(v)->
  151. getVariables(), var)) {
  152. return true;
  153. }
  154. }
  155. return false;
  156. }
  157. ListAssignment::ListAssignment
  158. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  159. ExpressionListPtr variables, ExpressionPtr array, bool rhsFirst /* = false */)
  160. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ListAssignment)),
  161. m_variables(variables), m_array(array), m_rhsKind(Regular),
  162. m_rhsFirst(rhsFirst) {
  163. setLValue();
  164. if (m_array) {
  165. m_rhsKind = GetRHSKind(m_array);
  166. if (m_array->is(KindOfSimpleVariable)) {
  167. if (AssignmentCouldSet(m_variables, m_array)) {
  168. m_array->setContext(LValue);
  169. }
  170. }
  171. }
  172. }
  173. ExpressionPtr ListAssignment::clone() {
  174. ListAssignmentPtr exp(new ListAssignment(*this));
  175. Expression::deepCopy(exp);
  176. exp->m_variables = Clone(m_variables);
  177. exp->m_array = Clone(m_array);
  178. return exp;
  179. }
  180. void ListAssignment::setLValue() {
  181. if (m_variables) {
  182. for (int i = 0; i < m_variables->getCount(); i++) {
  183. ExpressionPtr exp = (*m_variables)[i];
  184. if (exp) {
  185. if (exp->is(Construct::KindOfListAssignment)) {
  186. ListAssignmentPtr sublist =
  187. dynamic_pointer_cast<ListAssignment>(exp);
  188. sublist->setLValue();
  189. } else {
  190. // Magic contexts I took from assignment expression
  191. exp->setContext(Expression::DeepAssignmentLHS);
  192. exp->setContext(Expression::AssignmentLHS);
  193. exp->setContext(Expression::LValue);
  194. exp->setContext(Expression::NoLValueWrapper);
  195. }
  196. }
  197. }
  198. }
  199. }
  200. ///////////////////////////////////////////////////////////////////////////////
  201. // parser functions
  202. ///////////////////////////////////////////////////////////////////////////////
  203. // static analysis functions
  204. void ListAssignment::analyzeProgram(AnalysisResultPtr ar) {
  205. if (m_variables) m_variables->analyzeProgram(ar);
  206. if (m_array) m_array->analyzeProgram(ar);
  207. FunctionScopePtr func = getFunctionScope();
  208. if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
  209. if (m_variables) {
  210. for (int i = 0; i < m_variables->getCount(); i++) {
  211. ExpressionPtr exp = (*m_variables)[i];
  212. if (exp) {
  213. if (!exp->is(Construct::KindOfListAssignment)) {
  214. CheckNeeded(exp, ExpressionPtr());
  215. }
  216. }
  217. }
  218. }
  219. }
  220. }
  221. ConstructPtr ListAssignment::getNthKid(int n) const {
  222. switch (m_rhsFirst ? 1 - n : n) {
  223. case 0:
  224. return m_variables;
  225. case 1:
  226. return m_array;
  227. default:
  228. assert(false);
  229. break;
  230. }
  231. return ConstructPtr();
  232. }
  233. int ListAssignment::getKidCount() const {
  234. return 2;
  235. }
  236. void ListAssignment::setNthKid(int n, ConstructPtr cp) {
  237. switch (m_rhsFirst ? 1 - n : n) {
  238. case 0:
  239. m_variables = dynamic_pointer_cast<ExpressionList>(cp);
  240. break;
  241. case 1:
  242. m_array = dynamic_pointer_cast<Expression>(cp);
  243. break;
  244. default:
  245. assert(false);
  246. break;
  247. }
  248. }
  249. ///////////////////////////////////////////////////////////////////////////////
  250. void ListAssignment::outputCodeModel(CodeGenerator &cg) {
  251. auto numProps = m_array != nullptr ? 3 : 2;
  252. cg.printObjectHeader("ListAssignmentExpression", numProps);
  253. cg.printPropertyHeader("variables");
  254. cg.printExpressionVector(m_variables);
  255. if (m_array != nullptr) {
  256. cg.printPropertyHeader("expression");
  257. m_array->outputCodeModel(cg);
  258. }
  259. cg.printPropertyHeader("sourceLocation");
  260. cg.printLocation(this->getLocation());
  261. cg.printObjectFooter();
  262. }
  263. ///////////////////////////////////////////////////////////////////////////////
  264. // code generation functions
  265. void ListAssignment::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  266. cg_printf("list(");
  267. if (m_variables) m_variables->outputPHP(cg, ar);
  268. if (m_array) {
  269. cg_printf(") = ");
  270. m_array->outputPHP(cg, ar);
  271. } else {
  272. cg_printf(")");
  273. }
  274. }