Identify direct children of yield expressions
[hiphop-php.git] / hphp / compiler / expression / list_assignment.cpp
blobbc2115864e4b98603cd8d45ecd2f44d70e9c3f70
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 +----------------------------------------------------------------------+
17 #include "hphp/compiler/expression/list_assignment.h"
18 #include "hphp/compiler/expression/assignment_expression.h"
19 #include "hphp/compiler/expression/expression_list.h"
20 #include "hphp/compiler/analysis/file_scope.h"
21 #include "hphp/compiler/analysis/function_scope.h"
22 #include "hphp/compiler/expression/array_element_expression.h"
23 #include "hphp/compiler/expression/object_property_expression.h"
24 #include "hphp/compiler/expression/unary_op_expression.h"
25 #include "hphp/compiler/expression/binary_op_expression.h"
26 #include "hphp/util/parser/hphp.tab.hpp"
28 using namespace HPHP;
30 ///////////////////////////////////////////////////////////////////////////////
31 // constructors/destructors
34 Determine whether the rhs behaves normall, or abnormally.
36 1) If the expression is the silence operator, recurse on the inner expression.
37 2) If the expression is a list assignment expression, recurse on the
38 RHS of the expression.
39 3) If the expression is one of the following, then E behaves normally:
40 Simple/Dynamic variable (including $this and superglobals)
41 Array element expression
42 Property expression
43 Static variable expression
44 Function call expression
45 Preinc/predec expression (but not postinc/postdec)
46 Assignment expression
47 Assignment op expression
48 Binding assignment expression
49 Include/require expression
50 Eval expression
51 Array expression
52 Array cast expression
53 4) For all other expressions, E behaves abnormally. This includes:
54 All binary operator expressions
55 All unary operator expressions except silence and preinc/predec
56 Scalar expression of type null, bool, int, double, or string
57 Qop expression (?:)
58 Constant expression
59 Class constant expression
60 Isset or empty expression
61 Exit expression
62 Instanceof expression
64 static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
65 switch (rhs->getKindOf()) {
66 case Expression::KindOfSimpleVariable:
67 case Expression::KindOfDynamicVariable:
68 case Expression::KindOfArrayElementExpression:
69 case Expression::KindOfObjectPropertyExpression:
70 case Expression::KindOfStaticMemberExpression:
71 case Expression::KindOfSimpleFunctionCall:
72 case Expression::KindOfDynamicFunctionCall:
73 case Expression::KindOfObjectMethodExpression:
74 case Expression::KindOfNewObjectExpression:
75 case Expression::KindOfAssignmentExpression:
76 case Expression::KindOfExpressionList:
77 case Expression::KindOfIncludeExpression:
78 case Expression::KindOfYieldExpression:
79 return ListAssignment::Regular;
81 case Expression::KindOfListAssignment:
82 return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());
84 case Expression::KindOfUnaryOpExpression: {
85 UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(rhs));
86 switch (u->getOp()) {
87 case '@':
88 return GetRHSKind(u->getExpression());
89 case T_INC:
90 case T_DEC:
91 return u->getFront() ?
92 ListAssignment::Regular : ListAssignment::Checked;
93 case T_EVAL:
94 case T_ARRAY:
95 case T_ARRAY_CAST:
96 return ListAssignment::Regular;
97 default:
98 return ListAssignment::Null;
100 break;
103 case Expression::KindOfBinaryOpExpression: {
104 BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(rhs));
105 return b->isAssignmentOp() || b->getOp() == '+' ?
106 ListAssignment::Regular : ListAssignment::Null;
108 case Expression::KindOfQOpExpression:
109 return ListAssignment::Checked;
111 // invalid context
112 case Expression::KindOfArrayPairExpression:
113 case Expression::KindOfParameterExpression:
114 case Expression::KindOfModifierExpression:
115 case Expression::KindOfUserAttribute:
116 always_assert(false);
118 // non-arrays
119 case Expression::KindOfScalarExpression:
120 case Expression::KindOfConstantExpression:
121 case Expression::KindOfClassConstantExpression:
122 case Expression::KindOfEncapsListExpression:
123 case Expression::KindOfClosureExpression:
124 return ListAssignment::Null;
127 // unreachable for known expression kinds
128 always_assert(false);
131 static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) {
132 for (int i = 0; i < vars->getCount(); i++) {
133 ExpressionPtr v = (*vars)[i];
134 if (!v) continue;
135 if (v->is(Expression::KindOfSimpleVariable) &&
136 v->canonCompare(var)) {
137 return true;
139 if (v->is(Expression::KindOfDynamicVariable)) return true;
140 if (v->is(Expression::KindOfListAssignment) &&
141 AssignmentCouldSet(static_pointer_cast<ListAssignment>(v)->
142 getVariables(), var)) {
143 return true;
146 return false;
149 ListAssignment::ListAssignment
150 (EXPRESSION_CONSTRUCTOR_PARAMETERS,
151 ExpressionListPtr variables, ExpressionPtr array, bool rhsFirst /* = false */)
152 : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ListAssignment)),
153 m_variables(variables), m_array(array), m_rhsKind(Regular),
154 m_rhsFirst(rhsFirst) {
155 setLValue();
157 if (m_array) {
158 m_rhsKind = GetRHSKind(m_array);
159 if (m_array->is(KindOfSimpleVariable)) {
160 if (AssignmentCouldSet(m_variables, m_array)) {
161 m_array->setContext(LValue);
167 ExpressionPtr ListAssignment::clone() {
168 ListAssignmentPtr exp(new ListAssignment(*this));
169 Expression::deepCopy(exp);
170 exp->m_variables = Clone(m_variables);
171 exp->m_array = Clone(m_array);
172 return exp;
175 void ListAssignment::setLValue() {
176 if (m_variables) {
177 for (int i = 0; i < m_variables->getCount(); i++) {
178 ExpressionPtr exp = (*m_variables)[i];
179 if (exp) {
180 if (exp->is(Expression::KindOfListAssignment)) {
181 ListAssignmentPtr sublist =
182 dynamic_pointer_cast<ListAssignment>(exp);
183 sublist->setLValue();
184 } else {
185 // Magic contexts I took from assignment expression
186 exp->setContext(Expression::DeepAssignmentLHS);
187 exp->setContext(Expression::AssignmentLHS);
188 exp->setContext(Expression::LValue);
189 exp->setContext(Expression::NoLValueWrapper);
196 ///////////////////////////////////////////////////////////////////////////////
197 // parser functions
199 ///////////////////////////////////////////////////////////////////////////////
200 // static analysis functions
202 void ListAssignment::analyzeProgram(AnalysisResultPtr ar) {
203 if (m_variables) m_variables->analyzeProgram(ar);
204 if (m_array) m_array->analyzeProgram(ar);
205 FunctionScopePtr func = getFunctionScope();
206 if (func) func->disableInline();
207 if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
208 if (m_variables) {
209 for (int i = 0; i < m_variables->getCount(); i++) {
210 ExpressionPtr exp = (*m_variables)[i];
211 if (exp) {
212 if (!exp->is(Expression::KindOfListAssignment)) {
213 CheckNeeded(exp, ExpressionPtr());
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;
231 return ConstructPtr();
234 int ListAssignment::getKidCount() const {
235 return 2;
238 void ListAssignment::setNthKid(int n, ConstructPtr cp) {
239 switch (m_rhsFirst ? 1 - n : n) {
240 case 0:
241 m_variables = boost::dynamic_pointer_cast<ExpressionList>(cp);
242 break;
243 case 1:
244 m_array = boost::dynamic_pointer_cast<Expression>(cp);
245 break;
246 default:
247 assert(false);
248 break;
252 TypePtr ListAssignment::inferTypes(AnalysisResultPtr ar, TypePtr type,
253 bool coerce) {
254 if (m_variables) {
255 for (int i = m_variables->getCount(); i--; ) {
256 ExpressionPtr exp = (*m_variables)[i];
257 if (exp) {
258 if (exp->is(Expression::KindOfListAssignment)) {
259 exp->inferAndCheck(ar, Type::Any, false);
260 } else {
261 inferAssignmentTypes(ar, Type::Variant, true, exp);
267 if (!m_array) return TypePtr();
268 return m_array->inferAndCheck(ar, Type::Variant, false);
271 ///////////////////////////////////////////////////////////////////////////////
272 // code generation functions
274 void ListAssignment::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
275 cg_printf("list(");
276 if (m_variables) m_variables->outputPHP(cg, ar);
277 if (m_array) {
278 cg_printf(") = ");
279 m_array->outputPHP(cg, ar);
280 } else {
281 cg_printf(")");