Arquivos
hhvm/hphp/compiler/expression/include_expression.cpp
T
Paul Tarjan c4357440b0 slice up builtin_extension
This .expectf files turns into a huge regex and is our largest one. Instead lets have many small tests.

I made it with some fancy bash script.
2013-05-09 11:37:39 -07:00

292 linhas
9.0 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/expression/include_expression.h>
#include "hphp/util/parser/hphp.tab.hpp"
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/statement/statement_list.h>
#include <compiler/option.h>
#include <compiler/expression/expression_list.h>
#include <compiler/expression/binary_op_expression.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/parser/parser.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/expression/scalar_expression.h>
#include <util/util.h>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
IncludeExpression::IncludeExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, ExpressionPtr exp, int op)
: UnaryOpExpression(
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(IncludeExpression),
exp, op, true),
m_documentRoot(false), m_depsSet(false) {
}
ExpressionPtr IncludeExpression::clone() {
IncludeExpressionPtr exp(new IncludeExpression(*this));
Expression::deepCopy(exp);
exp->m_exp = Clone(m_exp);
exp->m_depsSet = false;
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
static string get_include_file_path(const string &source,
const string &var, const string &lit,
bool documentRoot) {
if (var.empty()) {
// absolute path
if (!lit.empty() && lit[0] == '/') {
return lit;
}
// relative path to document root
if (documentRoot) {
return lit;
}
struct stat sb;
// relative path to containing file's directory
if (source.empty() && (stat(lit.c_str(), &sb) == 0)) {
return lit;
}
size_t pos = source.rfind('/');
string resolved;
if (pos != string::npos) {
resolved = source.substr(0, pos + 1) + lit;
if (stat(resolved.c_str(), &sb) == 0) {
return resolved;
}
}
// if file cannot be found, resolve it using search paths
for (unsigned int i = 0; i < Option::IncludeSearchPaths.size(); i++) {
string filename = Option::IncludeSearchPaths[i] + "/" + lit;
struct stat sb;
if (stat(filename.c_str(), &sb) == 0) {
return filename;
}
}
// try still use relative path to containing file's directory
if (!resolved.empty()) {
return resolved;
}
return lit;
}
// [IncludeRoot] . 'string'
std::map<string, string>::const_iterator iter =
Option::IncludeRoots.find(var);
if (iter != Option::IncludeRoots.end()) {
string includeRoot = iter->second;
if (!includeRoot.empty()) {
if (includeRoot[0] == '/') includeRoot = includeRoot.substr(1);
if (includeRoot.empty() ||
includeRoot[includeRoot.size()-1] != '/') {
includeRoot += "/";
}
}
if (!lit.empty() && lit[0] == '/') {
includeRoot += lit.substr(1);
} else {
includeRoot += lit;
}
return includeRoot;
}
return "";
}
static void parse_string_arg(ExpressionPtr exp, string &var, string &lit) {
if (exp->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(exp));
if (u->getOp() == '(') {
parse_string_arg(u->getExpression(), var, lit);
return;
}
} else if (exp->is(Expression::KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(exp));
if (b->getOp() == '.') {
string v, l;
parse_string_arg(b->getExp2(), v, l);
if (v.empty()) {
parse_string_arg(b->getExp1(), var, lit);
lit += l;
return;
}
}
}
if (exp->isLiteralString()) {
var = "";
lit = exp->getLiteralString();
return;
}
var = exp->getText();
lit = "";
return;
}
string IncludeExpression::CheckInclude(ConstructPtr includeExp,
ExpressionPtr fileExp,
bool &documentRoot) {
string container = includeExp->getLocation()->file;
string var, lit;
parse_string_arg(fileExp, var, lit);
if (lit.empty()) return lit;
if (var == "__DIR__") {
var = "";
// get_include_file_path will check relative to the current file's dir
// as long as the first char isn't a /
if (lit[0] == '/') {
lit = lit.substr(1);
}
}
string included = get_include_file_path(container, var, lit, documentRoot);
if (!included.empty()) {
if (included == container) {
Compiler::Error(Compiler::BadPHPIncludeFile, includeExp);
}
included = Util::canonicalize(included);
if (!var.empty()) documentRoot = true;
}
return included;
}
void IncludeExpression::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) {
/* m_documentRoot is a bitfield */
bool dr = m_documentRoot;
m_include = CheckInclude(shared_from_this(), m_exp, dr);
m_documentRoot = dr;
if (!m_include.empty()) ar->parseOnDemand(m_include);
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
FileScopeRawPtr IncludeExpression::getIncludedFile(
AnalysisResultConstPtr ar) const {
if (m_include.empty()) return FileScopeRawPtr();
return ar->findFileScope(m_include);
}
std::string IncludeExpression::includePath() const {
return m_include;
}
bool IncludeExpression::isReqLit() const {
return !m_include.empty() &&
m_op == T_REQUIRE_ONCE && isDocumentRoot();
}
bool IncludeExpression::analyzeInclude(AnalysisResultConstPtr ar,
const std::string &include) {
ConstructPtr self = shared_from_this();
FileScopePtr file = ar->findFileScope(include);
if (!file) {
Compiler::Error(Compiler::PHPIncludeFileNotFound, self);
return false;
}
FunctionScopePtr func = getFunctionScope();
if (func && file->getPseudoMain()) {
file->getPseudoMain()->addUse(func, BlockScope::UseKindInclude);
}
return true;
}
void IncludeExpression::analyzeProgram(AnalysisResultPtr ar) {
if (!m_include.empty()) {
if (ar->getPhase() == AnalysisResult::AnalyzeAll ||
ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (analyzeInclude(ar, m_include)) {
FunctionScopePtr func = getFunctionScope();
getFileScope()->addIncludeDependency(ar, m_include,
func && func->isInlined());
}
}
}
VariableTablePtr var = getScope()->getVariables();
var->setAttribute(VariableTable::ContainsLDynamicVariable);
var->forceVariants(ar, VariableTable::AnyVars);
UnaryOpExpression::analyzeProgram(ar);
}
ExpressionPtr IncludeExpression::preOptimize(AnalysisResultConstPtr ar) {
if (ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
if (m_include.empty()) {
bool dr = m_documentRoot;
m_include = CheckInclude(shared_from_this(), m_exp, dr);
m_documentRoot = dr;
m_depsSet = false;
}
if (!m_depsSet && !m_include.empty()) {
analyzeInclude(ar, m_include);
m_depsSet = true;
}
}
return ExpressionPtr();
}
ExpressionPtr IncludeExpression::postOptimize(AnalysisResultConstPtr ar) {
if (!m_include.empty()) {
if (!m_depsSet) {
analyzeInclude(ar, m_include);
m_depsSet = true;
}
FileScopePtr fs = ar->findFileScope(m_include);
if (fs && fs->getPseudoMain()) {
if (!Option::KeepStatementsWithNoEffect) {
if (ExpressionPtr rep = fs->getEffectiveImpl(ar)) {
recomputeEffects();
return replaceValue(rep->clone());
}
}
} else {
m_include = "";
}
}
return ExpressionPtr();
}
TypePtr IncludeExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
return UnaryOpExpression::inferTypes(ar, type, coerce);
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void IncludeExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
UnaryOpExpression::outputPHP(cg, ar);
}