2b53df33bc
Generators are natively represented by 2 functions, which are now generated by parser. Not only it's more natural to do this only when we emit bytecode, but it will also allow us to reuse this logic for implementation of async functions. Differential Revision: D898769
143 linhas
5.1 KiB
C++
143 linhas
5.1 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/function_statement.h"
|
|
#include "hphp/compiler/analysis/analysis_result.h"
|
|
#include "hphp/compiler/expression/expression_list.h"
|
|
#include "hphp/compiler/analysis/file_scope.h"
|
|
#include "hphp/compiler/analysis/function_scope.h"
|
|
#include "hphp/compiler/statement/statement_list.h"
|
|
#include "hphp/util/util.h"
|
|
#include "hphp/compiler/expression/parameter_expression.h"
|
|
#include "hphp/compiler/expression/modifier_expression.h"
|
|
#include "hphp/compiler/option.h"
|
|
#include "hphp/compiler/analysis/variable_table.h"
|
|
#include "hphp/compiler/analysis/class_scope.h"
|
|
#include <sstream>
|
|
|
|
using namespace HPHP;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// constructors/destructors
|
|
|
|
FunctionStatement::FunctionStatement
|
|
(STATEMENT_CONSTRUCTOR_PARAMETERS,
|
|
ModifierExpressionPtr modifiers, bool ref, const std::string &name,
|
|
ExpressionListPtr params, const std::string &retTypeConstraint,
|
|
StatementListPtr stmt, int attr, const std::string &docComment,
|
|
ExpressionListPtr attrList)
|
|
: MethodStatement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(FunctionStatement),
|
|
modifiers, ref, name, params, retTypeConstraint, stmt,
|
|
attr, docComment, attrList, false), m_ignored(false) {
|
|
}
|
|
|
|
StatementPtr FunctionStatement::clone() {
|
|
FunctionStatementPtr stmt(new FunctionStatement(*this));
|
|
stmt->m_stmt = Clone(m_stmt);
|
|
stmt->m_params = Clone(m_params);
|
|
stmt->m_modifiers = Clone(m_modifiers);
|
|
return stmt;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// parser functions
|
|
|
|
void FunctionStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) {
|
|
// Correctness checks are normally done before adding function to scope.
|
|
if (m_params) {
|
|
for (int i = 0; i < m_params->getCount(); i++) {
|
|
ParameterExpressionPtr param =
|
|
dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
|
|
if (param->hasTypeHint() && param->defaultValue()) {
|
|
param->compatibleDefault();
|
|
}
|
|
}
|
|
}
|
|
|
|
// note it's important to add to scope, not a pushed FunctionContainer,
|
|
// as a function may be declared inside a class's method, yet this function
|
|
// is a global function, not a class method.
|
|
FunctionScopePtr fs = onInitialParse(ar, scope);
|
|
FunctionScope::RecordFunctionInfo(m_name, fs);
|
|
if (!scope->addFunction(ar, fs)) {
|
|
m_ignored = true;
|
|
return;
|
|
}
|
|
|
|
if (Option::PersistenceHook) {
|
|
fs->setPersistent(Option::PersistenceHook(fs, scope));
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// static analysis functions
|
|
|
|
std::string FunctionStatement::getName() const {
|
|
return string("Function ") + getScope()->getName();
|
|
}
|
|
|
|
void FunctionStatement::analyzeProgram(AnalysisResultPtr ar) {
|
|
FunctionScopeRawPtr fs = getFunctionScope();
|
|
// redeclared functions are automatically volatile
|
|
if (fs->isVolatile()) {
|
|
FunctionScopeRawPtr func =
|
|
getScope()->getOuterScope()->getContainingFunction();
|
|
if (func) {
|
|
func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer);
|
|
}
|
|
}
|
|
MethodStatement::analyzeProgram(ar);
|
|
}
|
|
|
|
void FunctionStatement::inferTypes(AnalysisResultPtr ar) {
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// code generation functions
|
|
|
|
void FunctionStatement::outputPHPHeader(CodeGenerator &cg,
|
|
AnalysisResultPtr ar) {
|
|
cg_printf("function ");
|
|
if (m_ref) cg_printf("&");
|
|
if (!ParserBase::IsClosureName(m_name)) {
|
|
cg_printf("%s", m_name.c_str());
|
|
}
|
|
cg_printf("(");
|
|
if (m_params) m_params->outputPHP(cg, ar);
|
|
cg_printf(")");
|
|
}
|
|
|
|
void FunctionStatement::outputPHPBody(CodeGenerator &cg,
|
|
AnalysisResultPtr ar) {
|
|
FunctionScopeRawPtr funcScope = getFunctionScope();
|
|
cg_indentBegin(" {\n");
|
|
funcScope->outputPHP(cg, ar);
|
|
if (m_stmt) m_stmt->outputPHP(cg, ar);
|
|
cg_indentEnd("}\n");
|
|
}
|
|
|
|
void FunctionStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
|
FunctionScopeRawPtr funcScope = getFunctionScope();
|
|
if (funcScope->isUserFunction()) {
|
|
outputPHPHeader(cg, ar);
|
|
outputPHPBody(cg, ar);
|
|
}
|
|
}
|
|
|
|
bool FunctionStatement::hasImpl() const {
|
|
return true;
|
|
}
|