2 +----------------------------------------------------------------------+
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"
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
43 Static variable expression
44 Function call expression
45 Preinc/predec expression (but not postinc/postdec)
47 Assignment op expression
48 Binding assignment expression
49 Include/require 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
59 Class constant expression
60 Isset or empty 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
));
88 return GetRHSKind(u
->getExpression());
91 return u
->getFront() ?
92 ListAssignment::Regular
: ListAssignment::Checked
;
96 return ListAssignment::Regular
;
98 return ListAssignment::Null
;
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
;
112 case Expression::KindOfArrayPairExpression
:
113 case Expression::KindOfParameterExpression
:
114 case Expression::KindOfModifierExpression
:
115 case Expression::KindOfUserAttribute
:
116 always_assert(false);
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
];
135 if (v
->is(Expression::KindOfSimpleVariable
) &&
136 v
->canonCompare(var
)) {
139 if (v
->is(Expression::KindOfDynamicVariable
)) return true;
140 if (v
->is(Expression::KindOfListAssignment
) &&
141 AssignmentCouldSet(static_pointer_cast
<ListAssignment
>(v
)->
142 getVariables(), var
)) {
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
) {
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
);
175 void ListAssignment::setLValue() {
177 for (int i
= 0; i
< m_variables
->getCount(); i
++) {
178 ExpressionPtr exp
= (*m_variables
)[i
];
180 if (exp
->is(Expression::KindOfListAssignment
)) {
181 ListAssignmentPtr sublist
=
182 dynamic_pointer_cast
<ListAssignment
>(exp
);
183 sublist
->setLValue();
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 ///////////////////////////////////////////////////////////////////////////////
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
) {
209 for (int i
= 0; i
< m_variables
->getCount(); i
++) {
210 ExpressionPtr exp
= (*m_variables
)[i
];
212 if (!exp
->is(Expression::KindOfListAssignment
)) {
213 CheckNeeded(exp
, ExpressionPtr());
221 ConstructPtr
ListAssignment::getNthKid(int n
) const {
222 switch (m_rhsFirst
? 1 - n
: n
) {
231 return ConstructPtr();
234 int ListAssignment::getKidCount() const {
238 void ListAssignment::setNthKid(int n
, ConstructPtr cp
) {
239 switch (m_rhsFirst
? 1 - n
: n
) {
241 m_variables
= boost::dynamic_pointer_cast
<ExpressionList
>(cp
);
244 m_array
= boost::dynamic_pointer_cast
<Expression
>(cp
);
252 TypePtr
ListAssignment::inferTypes(AnalysisResultPtr ar
, TypePtr type
,
255 for (int i
= m_variables
->getCount(); i
--; ) {
256 ExpressionPtr exp
= (*m_variables
)[i
];
258 if (exp
->is(Expression::KindOfListAssignment
)) {
259 exp
->inferAndCheck(ar
, Type::Any
, false);
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
) {
276 if (m_variables
) m_variables
->outputPHP(cg
, ar
);
279 m_array
->outputPHP(cg
, ar
);