PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/expression/assignment_expression.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 314 lines | 263 code | 22 blank | 29 comment | 62 complexity | 7b9a89d207e0420dd2c067f5b966125a 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/assignment_expression.h"
  17. #include "hphp/compiler/expression/array_element_expression.h"
  18. #include "hphp/compiler/expression/object_property_expression.h"
  19. #include "hphp/compiler/analysis/code_error.h"
  20. #include "hphp/compiler/expression/constant_expression.h"
  21. #include "hphp/compiler/expression/simple_variable.h"
  22. #include "hphp/compiler/analysis/block_scope.h"
  23. #include "hphp/compiler/analysis/variable_table.h"
  24. #include "hphp/compiler/analysis/constant_table.h"
  25. #include "hphp/compiler/analysis/file_scope.h"
  26. #include "hphp/compiler/expression/unary_op_expression.h"
  27. #include "hphp/parser/hphp.tab.hpp"
  28. #include "hphp/compiler/code_model_enums.h"
  29. #include "hphp/compiler/option.h"
  30. #include "hphp/compiler/analysis/class_scope.h"
  31. #include "hphp/compiler/analysis/function_scope.h"
  32. #include "hphp/compiler/expression/scalar_expression.h"
  33. #include "hphp/compiler/expression/expression_list.h"
  34. #include "hphp/compiler/expression/simple_function_call.h"
  35. #include "hphp/runtime/base/execution-context.h"
  36. using namespace HPHP;
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // constructors/destructors
  39. AssignmentExpression::AssignmentExpression
  40. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  41. ExpressionPtr variable, ExpressionPtr value, bool ref,
  42. bool rhsFirst /* = false */)
  43. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(AssignmentExpression)),
  44. m_variable(variable), m_value(value), m_ref(ref), m_rhsFirst(rhsFirst) {
  45. assert(!m_ref || !m_rhsFirst);
  46. m_variable->setContext(Expression::DeepAssignmentLHS);
  47. m_variable->setContext(Expression::AssignmentLHS);
  48. m_variable->setContext(Expression::LValue);
  49. m_variable->setContext(Expression::NoLValueWrapper);
  50. m_value->setContext(Expression::AssignmentRHS);
  51. if (ref) {
  52. m_variable->setContext(Expression::RefAssignmentLHS);
  53. m_value->setContext(Expression::RefValue);
  54. }
  55. }
  56. ExpressionPtr AssignmentExpression::clone() {
  57. AssignmentExpressionPtr exp(new AssignmentExpression(*this));
  58. Expression::deepCopy(exp);
  59. exp->m_variable = Clone(m_variable);
  60. exp->m_value = Clone(m_value);
  61. return exp;
  62. }
  63. ///////////////////////////////////////////////////////////////////////////////
  64. // parser functions
  65. void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar,
  66. ClassScopePtr scope) {
  67. // This is that much we can do during parse phase.
  68. TypePtr type;
  69. if (m_value->is(Expression::KindOfScalarExpression)) {
  70. type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl(
  71. ar, Type::Some, false);
  72. } else if (m_value->is(Expression::KindOfUnaryOpExpression)) {
  73. UnaryOpExpressionPtr uexp =
  74. dynamic_pointer_cast<UnaryOpExpression>(m_value);
  75. if (uexp->getOp() == T_ARRAY) {
  76. type = Type::Array;
  77. }
  78. }
  79. if (!type) type = Type::Some;
  80. if (m_variable->is(Expression::KindOfConstantExpression)) {
  81. // ...as in ClassConstant statement
  82. // We are handling this one here, not in ClassConstant, purely because
  83. // we need "value" to store in constant table.
  84. if (type->is(Type::KindOfArray)) {
  85. parseTimeFatal(Compiler::NoError,
  86. "Arrays are not allowed in class constants");
  87. }
  88. ConstantExpressionPtr exp =
  89. dynamic_pointer_cast<ConstantExpression>(m_variable);
  90. scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable);
  91. } else if (m_variable->is(Expression::KindOfSimpleVariable)) {
  92. SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable);
  93. scope->getVariables()->add(var->getName(), type, true, ar,
  94. shared_from_this(), scope->getModifiers());
  95. var->clearContext(Declaration); // to avoid wrong CodeError
  96. } else {
  97. assert(false); // parse phase shouldn't handle anything else
  98. }
  99. }
  100. ///////////////////////////////////////////////////////////////////////////////
  101. // static analysis functions
  102. int AssignmentExpression::getLocalEffects() const {
  103. return AssignEffect;
  104. }
  105. void AssignmentExpression::analyzeProgram(AnalysisResultPtr ar) {
  106. m_variable->analyzeProgram(ar);
  107. m_value->analyzeProgram(ar);
  108. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  109. if (m_ref && m_variable->is(Expression::KindOfSimpleVariable)) {
  110. SimpleVariablePtr var =
  111. dynamic_pointer_cast<SimpleVariable>(m_variable);
  112. const std::string &name = var->getName();
  113. VariableTablePtr variables = getScope()->getVariables();
  114. variables->addUsed(name);
  115. }
  116. } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
  117. if (m_variable->is(Expression::KindOfConstantExpression)) {
  118. ConstantExpressionPtr exp =
  119. dynamic_pointer_cast<ConstantExpression>(m_variable);
  120. if (!m_value->isScalar()) {
  121. getScope()->getConstants()->setDynamic(ar, exp->getName(), false);
  122. }
  123. } else {
  124. CheckNeeded(m_variable, m_value);
  125. }
  126. }
  127. }
  128. ConstructPtr AssignmentExpression::getNthKid(int n) const {
  129. switch (m_rhsFirst ? 1 - n : n) {
  130. case 0:
  131. return m_variable;
  132. case 1:
  133. return m_value;
  134. default:
  135. assert(false);
  136. break;
  137. }
  138. return ConstructPtr();
  139. }
  140. int AssignmentExpression::getKidCount() const {
  141. return 2;
  142. }
  143. void AssignmentExpression::setNthKid(int n, ConstructPtr cp) {
  144. switch (m_rhsFirst ? 1 - n : n) {
  145. case 0:
  146. m_variable = dynamic_pointer_cast<Expression>(cp);
  147. break;
  148. case 1:
  149. m_value = dynamic_pointer_cast<Expression>(cp);
  150. break;
  151. default:
  152. assert(false);
  153. break;
  154. }
  155. }
  156. bool AssignmentExpression::isSimpleGlobalAssign(StringData **name,
  157. TypedValue *tv) const {
  158. if (!m_variable->is(KindOfArrayElementExpression)) return false;
  159. ArrayElementExpressionPtr ae(
  160. static_pointer_cast<ArrayElementExpression>(m_variable));
  161. if (!ae->isSuperGlobal() || ae->isDynamicGlobal()) return false;
  162. Variant v;
  163. if (!m_value->getScalarValue(v) || v.is(KindOfArray)) return false;
  164. if (name) {
  165. *name = makeStaticString(ae->getGlobalName());
  166. }
  167. if (tv) {
  168. if (v.isString()) {
  169. v = makeStaticString(v.toCStrRef().get());
  170. }
  171. *tv = *v.asTypedValue();
  172. }
  173. return true;
  174. }
  175. ExpressionPtr AssignmentExpression::optimize(AnalysisResultConstPtr ar) {
  176. if (m_variable->is(Expression::KindOfSimpleVariable)) {
  177. SimpleVariablePtr var =
  178. dynamic_pointer_cast<SimpleVariable>(m_variable);
  179. if (var->checkUnused() &&
  180. !CheckNeeded(var, m_value)) {
  181. if (m_value->getContainedEffects() != getContainedEffects()) {
  182. recomputeEffects();
  183. }
  184. return replaceValue(m_value);
  185. }
  186. }
  187. return ExpressionPtr();
  188. }
  189. ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) {
  190. if (Option::EliminateDeadCode &&
  191. ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
  192. // otherwise used & needed flags may not be up to date yet
  193. ExpressionPtr rep = optimize(ar);
  194. if (rep) return rep;
  195. }
  196. if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) {
  197. return ExpressionPtr();
  198. }
  199. ExpressionPtr val = m_value;
  200. while (val) {
  201. if (val->is(KindOfExpressionList)) {
  202. ExpressionListPtr el(static_pointer_cast<ExpressionList>(val));
  203. val = el->listValue();
  204. continue;
  205. }
  206. if (val->is(KindOfAssignmentExpression)) {
  207. val = static_pointer_cast<AssignmentExpression>(val)->m_value;
  208. continue;
  209. }
  210. break;
  211. }
  212. if (val && val->isScalar()) {
  213. if (val != m_value) {
  214. ExpressionListPtr rep(new ExpressionList(
  215. getScope(), getLocation(),
  216. ExpressionList::ListKindWrapped));
  217. rep->addElement(m_value);
  218. m_value = val->clone();
  219. rep->addElement(static_pointer_cast<Expression>(shared_from_this()));
  220. return replaceValue(rep);
  221. }
  222. if (!m_ref && m_variable->is(KindOfArrayElementExpression)) {
  223. ArrayElementExpressionPtr ae(
  224. static_pointer_cast<ArrayElementExpression>(m_variable));
  225. ExpressionPtr avar(ae->getVariable());
  226. ExpressionPtr aoff(ae->getOffset());
  227. if (!aoff || aoff->isScalar()) {
  228. avar = avar->getCanonLVal();
  229. while (avar) {
  230. if (avar->isScalar()) {
  231. Variant v,o,r;
  232. if (!avar->getScalarValue(v)) break;
  233. if (!val->getScalarValue(r)) break;
  234. try {
  235. g_context->setThrowAllErrors(true);
  236. if (aoff) {
  237. if (!aoff->getScalarValue(o)) break;
  238. if (!v.isArray()) break;
  239. v.toArrRef().set(o, r);
  240. } else {
  241. if (!v.isArray()) break;
  242. v.toArrRef().append(r);
  243. }
  244. g_context->setThrowAllErrors(false);
  245. } catch (...) {
  246. break;
  247. }
  248. ExpressionPtr rep(
  249. new AssignmentExpression(
  250. getScope(), getLocation(),
  251. m_variable->replaceValue(Clone(ae->getVariable())),
  252. makeScalarExpression(ar, v), false));
  253. if (!isUnused()) {
  254. ExpressionListPtr el(
  255. new ExpressionList(
  256. getScope(), getLocation(),
  257. ExpressionList::ListKindWrapped));
  258. el->addElement(rep);
  259. el->addElement(val);
  260. rep = el;
  261. }
  262. return replaceValue(rep);
  263. }
  264. avar = avar->getCanonPtr();
  265. }
  266. g_context->setThrowAllErrors(false);
  267. }
  268. }
  269. }
  270. return ExpressionPtr();
  271. }
  272. ///////////////////////////////////////////////////////////////////////////////
  273. void AssignmentExpression::outputCodeModel(CodeGenerator &cg) {
  274. cg.printObjectHeader("BinaryOpExpression", 4);
  275. cg.printPropertyHeader("expression1");
  276. m_variable->outputCodeModel(cg);
  277. cg.printPropertyHeader("expression2");
  278. cg.printExpression(m_value, m_ref);
  279. cg.printPropertyHeader("operation");
  280. cg.printValue(PHP_ASSIGNMENT);
  281. cg.printPropertyHeader("sourceLocation");
  282. cg.printLocation(this->getLocation());
  283. cg.printObjectFooter();
  284. }
  285. ///////////////////////////////////////////////////////////////////////////////
  286. // code generation functions
  287. void AssignmentExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  288. m_variable->outputPHP(cg, ar);
  289. cg_printf(" = ");
  290. if (m_ref) cg_printf("&");
  291. m_value->outputPHP(cg, ar);
  292. }