Arquivos
hhvm/hphp/compiler/analysis/constant_table.cpp
T
2013-03-08 17:52:38 -08:00

254 linhas
8.5 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/constant_table.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/type.h>
#include <compiler/code_generator.h>
#include <compiler/expression/expression.h>
#include <compiler/expression/scalar_expression.h>
#include <compiler/option.h>
#include <util/util.h>
#include <util/hash.h>
#include <compiler/analysis/class_scope.h>
#include <runtime/base/complex_types.h>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
ConstantTable::ConstantTable(BlockScope &blockScope)
: SymbolTable(blockScope, true),
m_hasDynamic(false) {
}
///////////////////////////////////////////////////////////////////////////////
TypePtr ConstantTable::add(const std::string &name, TypePtr type,
ExpressionPtr exp, AnalysisResultConstPtr ar,
ConstructPtr construct) {
if (name == "true" || name == "false") {
return Type::Boolean;
}
Symbol *sym = genSymbol(name, true);
if (!sym->declarationSet()) {
assert(!sym->valueSet());
setType(ar, sym, type, true);
sym->setDeclaration(construct);
sym->setValue(exp);
return type;
}
assert(sym->declarationSet() && sym->valueSet());
if (m_blockScope.isFirstPass()) {
if (construct) {
if (exp != sym->getValue()) {
Compiler::Error(Compiler::DeclaredConstantTwice, construct,
sym->getDeclaration());
if (!sym->isDynamic()) {
sym->setDynamic();
m_hasDynamic = true;
}
type = Type::Variant;
}
} else if (exp) {
sym->setValue(exp);
}
setType(ar, sym, type, true);
}
return type;
}
void ConstantTable::setDynamic(AnalysisResultConstPtr ar,
const std::string &name, bool forceVariant) {
Symbol *sym = genSymbol(name, true);
if (!sym->isDynamic()) {
Lock lock(BlockScope::s_constMutex);
sym->setDynamic();
if (sym->getDeclaration()) {
sym->getDeclaration()->getScope()->
addUpdates(BlockScope::UseKindConstRef);
}
m_hasDynamic = true;
if (forceVariant) {
setType(ar, sym, Type::Variant, true);
}
}
}
void ConstantTable::setValue(AnalysisResultConstPtr ar, const std::string &name,
ExpressionPtr value) {
Symbol *sym = getSymbol(name);
assert(sym && sym->isPresent());
sym->setValue(value);
}
bool ConstantTable::isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const {
if (const Symbol *sym ATTRIBUTE_UNUSED = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
return true;
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
return parent->getConstants()->isRecursivelyDeclared(ar, name);
}
return false;
}
ConstructPtr ConstantTable::getValueRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass) const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getValue()) return sym->getValue();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getValueRecur(ar, name, defClass);
}
return ConstructPtr();
}
ConstructPtr ConstantTable::getDeclarationRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass)
const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getDeclaration()) return sym->getDeclaration();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getDeclarationRecur(ar, name, defClass);
}
return ConstructPtr();
}
void ConstantTable::cleanupForError(AnalysisResultConstPtr ar) {
AnalysisResult::Locker lock(ar);
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (!sym->isDynamic()) {
sym->setDynamic();
sym->setDeclaration(ConstructPtr());
sym->setValue(ConstructPtr());
}
}
}
TypePtr ConstantTable::check(BlockScopeRawPtr context,
const std::string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope) {
assert(!m_blockScope.is(BlockScope::FunctionScope));
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
TypePtr actualType;
defScope = nullptr;
if (name == "true" || name == "false") {
actualType = Type::Boolean;
} else {
Symbol *sym = getSymbol(name);
if (!sym) {
if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (isClassScope) {
ClassScopeRawPtr parent = findBase(ar, name, bases);
if (parent) {
actualType = parent->getConstants()->check(
context, name, type, coerce, ar, construct, bases, defScope);
if (defScope) return actualType;
}
}
if (!isClassScope || !((ClassScope*)&m_blockScope)->isTrait()) {
Compiler::Error(Compiler::UseUndeclaredConstant, construct);
}
actualType = isClassScope || !Option::WholeProgram ?
Type::Variant : Type::String;
}
} else {
assert(sym->isPresent());
assert(sym->getType());
assert(sym->isConstant());
defScope = &m_blockScope;
if (isClassScope) {
// if the current scope is a function scope, grab the lock.
// otherwise if it's a class scope, then *try* to grab the lock.
if (context->is(BlockScope::FunctionScope)) {
GET_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
} else {
TRY_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
}
} else {
Lock lock(m_blockScope.getMutex());
return setType(ar, sym, type, coerce);
}
}
}
return actualType;
}
ClassScopePtr ConstantTable::findParent(AnalysisResultConstPtr ar,
const std::string &name) const {
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
parent && !parent->isRedeclaring();
parent = parent->getParentScope(ar)) {
if (parent->hasConst(name)) {
return parent;
}
}
return ClassScopePtr();
}
ClassScopeRawPtr ConstantTable::findBase(
AnalysisResultConstPtr ar, const std::string &name,
const std::vector<std::string> &bases) const {
for (int i = bases.size(); i--; ) {
ClassScopeRawPtr p = ar->findClass(bases[i]);
if (!p || p->isRedeclaring()) continue;
if (p->hasConst(name)) return p;
ConstantTablePtr constants = p->getConstants();
p = constants->findBase(ar, name, p->getBases());
if (p) return p;
}
return ClassScopeRawPtr();
}
///////////////////////////////////////////////////////////////////////////////
void ConstantTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (Option::GenerateInferredTypes) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (sym->isSystem()) continue;
cg_printf("// @const %s\t$%s\n",
sym->getFinalType()->toString().c_str(),
sym->getName().c_str());
}
}
}