Arquivos
hhvm/hphp/compiler/statement/static_statement.cpp
T
Herman Venter afbde6181a Provide a way to serialize the compiler's AST in the form of a PHP Code Model.
The AST classes now have an additional visitor that can serialize the AST in the format expected by the unserialize function. The concrete classes to be produced by the unserialize function can be controlled by passing in a prefix argument to the visitor.

Facebook only:

Also added is an extension function fb_serialize_code_model_for(codeobject, prefix) that takes a string as its first argument, prefixes it with "<?php " and then parses it as if it were an eval string and then returns the serialized AST.

Reviewed By: @paroski

Differential Revision: D1027004
2013-11-26 21:14:17 -08:00

210 linhas
7.8 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/static_statement.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/compiler/option.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
StaticStatement::StaticStatement
(STATEMENT_CONSTRUCTOR_PARAMETERS, ExpressionListPtr exp)
: Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(StaticStatement)),
m_exp(exp) {
}
StatementPtr StaticStatement::clone() {
StaticStatementPtr stmt(new StaticStatement(*this));
stmt->m_exp = Clone(m_exp);
return stmt;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void StaticStatement::analyzeProgram(AnalysisResultPtr ar) {
m_exp->analyzeProgram(ar);
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
BlockScopePtr scope = getScope();
for (int i = 0; i < m_exp->getCount(); i++) {
ExpressionPtr exp = (*m_exp)[i];
ExpressionPtr variable;
ExpressionPtr value;
// turn static $a; into static $a = null;
if (exp->is(Expression::KindOfSimpleVariable)) {
variable = dynamic_pointer_cast<SimpleVariable>(exp);
exp = AssignmentExpressionPtr
(new AssignmentExpression(exp->getScope(), exp->getLocation(),
variable,
CONSTANT("null"),
false));
(*m_exp)[i] = exp;
}
always_assert(exp->is(Expression::KindOfAssignmentExpression));
AssignmentExpressionPtr assignment_exp =
dynamic_pointer_cast<AssignmentExpression>(exp);
variable = assignment_exp->getVariable();
value = assignment_exp->getValue();
SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
// set the Declaration context here instead of all over this file - this phase
// is the first to run
var->setContext(Expression::Declaration);
Symbol *sym = var->getSymbol();
sym->setStaticInitVal(value);
}
}
}
ConstructPtr StaticStatement::getNthKid(int n) const {
switch (n) {
case 0:
return m_exp;
default:
assert(false);
break;
}
return ConstructPtr();
}
int StaticStatement::getKidCount() const {
return 1;
}
void StaticStatement::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_exp = dynamic_pointer_cast<ExpressionList>(cp);
break;
default:
assert(false);
break;
}
}
StatementPtr StaticStatement::preOptimize(AnalysisResultConstPtr ar) {
BlockScopePtr scope = getScope();
for (int i = 0; i < m_exp->getCount(); i++) {
ExpressionPtr exp = (*m_exp)[i];
AssignmentExpressionPtr assignment_exp =
dynamic_pointer_cast<AssignmentExpression>(exp);
ExpressionPtr variable = assignment_exp->getVariable();
ExpressionPtr value = assignment_exp->getValue();
SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
Symbol *sym = var->getSymbol();
sym->setStaticInitVal(value);
}
return StatementPtr();
}
void StaticStatement::inferTypes(AnalysisResultPtr ar) {
IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
BlockScopePtr scope = getScope();
if (scope->inPseudoMain()) { // static just means to unset at global level
for (int i = 0; i < m_exp->getCount(); i++) {
ExpressionPtr exp = (*m_exp)[i];
if (exp->is(Expression::KindOfAssignmentExpression)) {
AssignmentExpressionPtr assignment_exp =
dynamic_pointer_cast<AssignmentExpression>(exp);
ExpressionPtr variable = assignment_exp->getVariable();
assert(variable->is(Expression::KindOfSimpleVariable));
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(variable);
assert(var->hasContext(Expression::Declaration));
scope->getVariables()->forceVariant(ar, var->getName(),
VariableTable::AnyStaticVars);
} else {
// Expression was optimized away; remove it
m_exp->removeElement(i--);
}
}
m_exp->inferTypes(ar, Type::Any, true);
return;
}
scope->getVariables()->setAttribute(VariableTable::InsideStaticStatement);
for (int i = 0; i < m_exp->getCount(); i++) {
ExpressionPtr exp = (*m_exp)[i];
VariableTablePtr variables = scope->getVariables();
if (exp->is(Expression::KindOfAssignmentExpression)) {
AssignmentExpressionPtr assignment_exp =
dynamic_pointer_cast<AssignmentExpression>(exp);
ExpressionPtr variable = assignment_exp->getVariable();
assert(variable->is(Expression::KindOfSimpleVariable));
SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
assert(var->hasContext(Expression::Declaration));
const std::string &name = var->getName();
/* If we have already seen this variable in the current scope and
it is not a static variable, record this variable as "redeclared"
to force Variant type.
*/
if (getScope()->isFirstPass()) {
variables->checkRedeclared(name, KindOfStaticStatement);
}
/* If this is not a top-level static statement, the variable also
needs to be Variant type. This should not be a common use case in
php code.
*/
if (!isTopLevel()) {
variables->addNestedStatic(name);
}
if (variables->needLocalCopy(name)) {
variables->forceVariant(ar, name, VariableTable::AnyStaticVars);
}
} else {
// Expression was optimized away; remove it
m_exp->removeElement(i--);
continue;
}
exp->inferAndCheck(ar, Type::Any, false);
}
scope->getVariables()->clearAttribute(VariableTable::InsideStaticStatement);
}
///////////////////////////////////////////////////////////////////////////////
void StaticStatement::outputCodeModel(CodeGenerator &cg) {
cg.printObjectHeader("StaticStatement", 2);
cg.printPropertyHeader("expressions");
m_exp->outputCodeModel(cg);
cg.printPropertyHeader("location");
cg.printLocation(this->getLocation());
cg.printObjectFooter();
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void StaticStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("static ");
m_exp->outputPHP(cg, ar);
cg_printf(";\n");
}