f7fe29dcaf
Fixed the VM AST to Code Model serializer to use "sourceLocation" rather than "location". Also fixed the serialization of constant expressions to use "variableName" rather than just name and to use the original name field for its value. Also fixed serialization of closure expressions to check for the case where there are no captured variables. Reviewed By: duv Differential Revision: D1095904
198 linhas
5.9 KiB
C++
198 linhas
5.9 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/compiler/statement/foreach_statement.h"
|
|
#include "hphp/compiler/expression/assignment_expression.h"
|
|
#include "hphp/compiler/analysis/analysis_result.h"
|
|
#include "hphp/compiler/analysis/block_scope.h"
|
|
#include "hphp/compiler/expression/simple_variable.h"
|
|
#include "hphp/compiler/option.h"
|
|
#include "hphp/compiler/analysis/code_error.h"
|
|
#include "hphp/compiler/analysis/class_scope.h"
|
|
#include "hphp/compiler/analysis/function_scope.h"
|
|
#include "hphp/util/util.h"
|
|
|
|
using namespace HPHP;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// constructors/destructors
|
|
|
|
ForEachStatement::ForEachStatement
|
|
(STATEMENT_CONSTRUCTOR_PARAMETERS,
|
|
ExpressionPtr array, ExpressionPtr name, bool nameRef,
|
|
ExpressionPtr value, bool valueRef, StatementPtr stmt)
|
|
: LoopStatement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(ForEachStatement)),
|
|
m_array(array), m_name(name), m_value(value), m_ref(valueRef),
|
|
m_stmt(stmt) {
|
|
if (!m_value) {
|
|
m_value = m_name;
|
|
m_ref = nameRef;
|
|
m_name.reset();
|
|
}
|
|
if (m_name) {
|
|
m_name->setContext(Expression::LValue);
|
|
m_name->setContext(Expression::NoLValueWrapper);
|
|
}
|
|
m_value->setContext(Expression::LValue);
|
|
m_value->setContext(Expression::NoLValueWrapper);
|
|
if (m_ref) {
|
|
m_array->setContext(Expression::RefValue);
|
|
m_value->setContext(Expression::RefValue);
|
|
m_value->setContext(Expression::NoRefWrapper);
|
|
}
|
|
}
|
|
|
|
StatementPtr ForEachStatement::clone() {
|
|
ForEachStatementPtr stmt(new ForEachStatement(*this));
|
|
stmt->m_array = Clone(m_array);
|
|
stmt->m_name = Clone(m_name);
|
|
stmt->m_value = Clone(m_value);
|
|
stmt->m_stmt = Clone(m_stmt);
|
|
return stmt;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// parser functions
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// static analysis functions
|
|
|
|
void ForEachStatement::analyzeProgram(AnalysisResultPtr ar) {
|
|
m_array->analyzeProgram(ar);
|
|
if (m_name) m_name->analyzeProgram(ar);
|
|
m_value->analyzeProgram(ar);
|
|
if (m_stmt) m_stmt->analyzeProgram(ar);
|
|
}
|
|
|
|
ConstructPtr ForEachStatement::getNthKid(int n) const {
|
|
switch (n) {
|
|
case 0:
|
|
return m_array;
|
|
case 1:
|
|
return m_name;
|
|
case 2:
|
|
return m_value;
|
|
case 3:
|
|
return m_stmt;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
return ConstructPtr();
|
|
}
|
|
|
|
int ForEachStatement::getKidCount() const {
|
|
return 4;
|
|
}
|
|
|
|
void ForEachStatement::setNthKid(int n, ConstructPtr cp) {
|
|
switch (n) {
|
|
case 0:
|
|
m_array = dynamic_pointer_cast<Expression>(cp);
|
|
break;
|
|
case 1:
|
|
m_name = dynamic_pointer_cast<Expression>(cp);
|
|
break;
|
|
case 2:
|
|
m_value = dynamic_pointer_cast<Expression>(cp);
|
|
break;
|
|
case 3:
|
|
m_stmt = dynamic_pointer_cast<Statement>(cp);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ForEachStatement::inferTypes(AnalysisResultPtr ar) {
|
|
IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
|
|
|
|
m_array->inferAndCheck(ar, m_ref ? Type::Variant : Type::Array, m_ref);
|
|
if (m_name) {
|
|
if (m_name->is(Expression::KindOfListAssignment)) {
|
|
m_name->inferTypes(ar, TypePtr(), false);
|
|
} else {
|
|
m_name->inferAndCheck(ar, Type::Primitive, true);
|
|
}
|
|
}
|
|
|
|
if (m_value->is(Expression::KindOfListAssignment)) {
|
|
m_value->inferTypes(ar, TypePtr(), false);
|
|
} else {
|
|
m_value->inferAndCheck(ar, Type::Variant, true);
|
|
}
|
|
|
|
if (m_ref) {
|
|
TypePtr actualType = m_array->getActualType();
|
|
if (!actualType ||
|
|
actualType->is(Type::KindOfVariant) ||
|
|
actualType->is(Type::KindOfObject)) {
|
|
ar->forceClassVariants(getClassScope(), false, true);
|
|
}
|
|
}
|
|
if (m_stmt) {
|
|
getScope()->incLoopNestedLevel();
|
|
m_stmt->inferTypes(ar);
|
|
getScope()->decLoopNestedLevel();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ForEachStatement::outputCodeModel(CodeGenerator &cg) {
|
|
auto numProps = 3;
|
|
if (m_name != nullptr) numProps++;
|
|
if (m_stmt != nullptr) numProps++;
|
|
cg.printObjectHeader("ForeachStatement", numProps);
|
|
cg.printPropertyHeader("collection");
|
|
m_array->outputCodeModel(cg);
|
|
if (m_name != nullptr) {
|
|
cg.printPropertyHeader("key");
|
|
m_name->outputCodeModel(cg);
|
|
}
|
|
cg.printPropertyHeader("value");
|
|
cg.printExpression(m_value, m_ref);
|
|
if (m_stmt != nullptr) {
|
|
cg.printPropertyHeader("block");
|
|
cg.printAsBlock(m_stmt);
|
|
}
|
|
cg.printPropertyHeader("sourceLocation");
|
|
cg.printLocation(this->getLocation());
|
|
cg.printObjectFooter();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// code generation functions
|
|
|
|
void ForEachStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
|
cg_printf("foreach (");
|
|
m_array->outputPHP(cg, ar);
|
|
cg_printf(" as ");
|
|
if (m_name) {
|
|
m_name->outputPHP(cg, ar);
|
|
cg_printf(" => ");
|
|
}
|
|
if (m_ref) cg_printf("&");
|
|
m_value->outputPHP(cg, ar);
|
|
cg_printf(") ");
|
|
if (m_stmt) {
|
|
m_stmt->outputPHP(cg, ar);
|
|
} else {
|
|
cg_printf("{}\n");
|
|
}
|
|
}
|