Arquivos
Jordan DeLong de03fa1f5d Move util/json.h to compiler
It references compiler-specific types like AnalysisResult.
Replace the one live use of the JSON::Escape function from this header
in the runtime with folly call; other use is about to be removed in
another diff from dario.

Reviewed By: @dariorussi

Differential Revision: D1115340
2014-01-06 11:42:20 -08:00

346 linhas
13 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. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_CONSTRUCT_H_
#define incl_HPHP_CONSTRUCT_H_
#include "hphp/compiler/json.h"
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/block_scope.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class Variant;
DECLARE_BOOST_TYPES(StatementList);
DECLARE_BOOST_TYPES(IParseHandler);
DECLARE_BOOST_TYPES(Location);
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(BlockScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(FileScope);
class AstWalkerStateVec;
class IParseHandler {
/**
* To avoid iteration of parse tree, we move any work that can be done
* in parse phase into this function, so to speed up static analysis.
*/
public:
virtual ~IParseHandler() {}
/**
* onParse is called by the parser when the construct has just been parsed
* to allow it to do any necessary work
*/
virtual void onParse(AnalysisResultConstPtr ar, FileScopePtr scope) {
always_assert(0);
}
/**
* onParseRecur is called by a parent construct (ultimately a class or
* interface).
* This is done because at the time that onParse would be called for
* (eg) a method, the ClassScope doesnt exist. So we wait until onParse
* is called for the class, and it calls onParseRecur for its children.
*/
virtual void onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) {
always_assert(0);
}
};
/**
* Base class of Expression and Statement.
*/
class Construct : public std::enable_shared_from_this<Construct>,
public JSON::CodeError::ISerializable {
protected:
Construct(BlockScopePtr scope, LocationPtr loc);
public:
virtual ~Construct() {}
enum Effect {
NoEffect = 0,
IOEffect = 1, // could have an observable effect (not
// changing variable values)
AssignEffect = 2, // writes an object in a way understood by the
// alias manager
GlobalEffect = 4, // could affect global variables
LocalEffect = 8, // could affect variables from the local scope
ParamEffect = 0x10, // a function could affect its parameters
DeepParamEffect = 0x20, // a function could affect the array elements
// or object members referenced by its
// parameters
DynamicParamEffect = 0x40, // a function creates dynamic exps based
// on its parameters, which it could affect
CanThrow = 0x80, // can throw PHP exception
AccessorEffect = 0x100, // could contain a getter/setter
CreateEffect = 0x200, // could cause the creation of an array
// element or an object property
DiagnosticEffect = 0x400, // can cause a diagnostic to be issued
OtherEffect = 0x800, // something else
UnknownEffect = 0xfff // any of the above
};
LocationPtr getLocation() const { return m_loc;}
void setLocation(LocationPtr loc) { m_loc = loc;}
void setFileLevel() { m_flags.topLevel = m_flags.fileLevel = true;}
void setTopLevel() { m_flags.topLevel = true;}
void setVisited() { m_flags.visited = true;}
void clearVisited() { m_flags.visited = false;}
bool isFileLevel() const { return m_flags.fileLevel;}
bool isTopLevel() const { return m_flags.topLevel;}
bool isVisited() const { return m_flags.visited; }
void setAnticipated() { m_flags.anticipated = true; }
void clearAnticipated() { m_flags.anticipated = false; }
bool isAnticipated() const { return m_flags.anticipated; }
void setAvailable() { m_flags.available = true; }
void clearAvailable() { m_flags.available = false; }
bool isAvailable() const { return m_flags.available; }
void setNonNull() { m_flags.nonNull = true; }
void clearNonNull() { m_flags.nonNull = false; }
bool isNonNull() const { return m_flags.nonNull; }
void setLocalExprAltered() { m_flags.localExprNotAltered = false; }
void clearLocalExprAltered() { m_flags.localExprNotAltered = true; }
bool isLocalExprAltered() const { return !m_flags.localExprNotAltered; }
void setChainRoot() { m_flags.chainRoot = true; }
void clearChainRoot() { m_flags.chainRoot = false; }
bool isChainRoot() const { return m_flags.chainRoot; }
void setReferencedValid() { m_flags.referenced_valid = true; }
void clearReferencedValid() { m_flags.referenced_valid = false; }
bool isReferencedValid() const { return m_flags.referenced_valid; }
void setReferenced() { m_flags.referenced = true; }
void clearReferenced() { m_flags.referenced = false; }
bool isReferenced() const { return m_flags.referenced; }
void setNeededValid() { m_flags.needed_valid = true; }
void clearNeededValid() { m_flags.needed_valid = false; }
bool isNeededValid() const { return m_flags.needed_valid; }
void setNeeded() { m_flags.needed = true; }
void clearNeeded() { m_flags.needed = false; }
bool isNeeded() const { return m_flags.needed; }
void setNoRemove() { m_flags.noRemove = true; }
void clearNoRemove() { m_flags.noRemove = false; }
bool isNoRemove() const { return m_flags.noRemove; }
void setGuarded() { m_flags.guarded = true; }
void clearGuarded() { m_flags.guarded = false; }
bool isGuarded() const { return m_flags.guarded; }
void setRefCounted() { m_flags.refCounted = 3; }
void clearRefCounted() { m_flags.refCounted = 2; }
bool maybeRefCounted() const {
return !(m_flags.refCounted & 2) || (m_flags.refCounted & 1);
}
void setInited() { m_flags.inited = 3; }
void clearInited() { m_flags.inited = 2; }
bool maybeInited() const {
return !(m_flags.inited & 2) || (m_flags.inited & 1);
}
void setKilled() { m_flags.killed = true; }
void clearKilled() { m_flags.killed = false; }
bool isKilled() const { return m_flags.killed; }
BlockScopeRawPtr getScope() const { return m_blockScope; }
void setBlockScope(BlockScopeRawPtr scope) { m_blockScope = scope; }
FileScopeRawPtr getFileScope() const {
return m_blockScope->getContainingFile();
}
FunctionScopeRawPtr getFunctionScope() const {
return m_blockScope->getContainingFunction();
}
ClassScopeRawPtr getClassScope() const {
return m_blockScope->getContainingClass();
}
void resetScope(BlockScopeRawPtr scope, bool resetOrigScope=false);
void parseTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
ATTRIBUTE_PRINTF(3,4);
void analysisTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
ATTRIBUTE_PRINTF(3,4);
virtual int getLocalEffects() const { return UnknownEffect;}
int getChildrenEffects() const;
int getContainedEffects() const;
bool hasEffect() const { return getContainedEffects() != NoEffect;}
virtual bool kidUnused(int i) const { return false; }
template<typename T>
static std::shared_ptr<T> Clone(std::shared_ptr<T> constr) {
if (constr) {
return dynamic_pointer_cast<T>(constr->clone());
}
return std::shared_ptr<T>();
}
template<typename T>
std::shared_ptr<T> Clone(std::shared_ptr<T> constr,
BlockScopePtr scope) {
if (constr) {
constr = constr->clone();
constr->resetScope(scope);
}
return constr;
}
/**
* Called when we analyze a program, which file it includes, which function
* and class it uses, etc.
*/
virtual void analyzeProgram(AnalysisResultPtr ar) = 0;
/**
* return the nth child construct
*/
virtual ConstructPtr getNthKid(int n) const { return ConstructPtr(); }
/**
* set the nth child construct
*/
virtual void setNthKid(int n, ConstructPtr cp) {}
/**
* get the kid count
*/
virtual int getKidCount() const = 0;
// helpers for GDB
void dump(int spc, AnalysisResultPtr ar) {
AnalysisResultConstPtr arp(ar);
dump(spc, arp);
}
void dumpNode(int spc, AnalysisResultPtr ar) {
AnalysisResultConstPtr arp(ar);
dumpNode(spc, arp);
}
void dumpNode(int spc);
void dumpNode(int spc) const;
void dump(int spc, AnalysisResultConstPtr ar);
void dumpNode(int spc, AnalysisResultConstPtr ar);
static void dump(int spc, AnalysisResultConstPtr ar, bool functionOnly,
const AstWalkerStateVec &start,
ConstructPtr endBefore, ConstructPtr endAfter);
/**
* Generates a serialized Code Model corresponding to this AST.
*/
virtual void outputCodeModel(CodeGenerator &cg) = 0;
/**
* Called when generating code.
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
/**
* Implements JSON::CodeError::ISerializable.
*/
virtual void serialize(JSON::CodeError::OutputStream &out) const;
/**
* Get canonicalized PHP source code for this construct.
*/
std::string getText(bool useCache, bool translate = false,
AnalysisResultPtr ar = AnalysisResultPtr());
std::string getText() { return getText(false); }
void recomputeEffects();
/**
* Write where this construct was in PHP files.
*/
void printSource(CodeGenerator &cg);
ExpressionPtr makeConstant(AnalysisResultConstPtr ar,
const std::string &value) const;
ExpressionPtr makeScalarExpression(AnalysisResultConstPtr ar,
const Variant &value) const;
private:
std::string m_text;
BlockScopeRawPtr m_blockScope;
union {
unsigned m_flagsVal;
struct {
unsigned fileLevel : 1; // is it at top level of a file
unsigned topLevel : 1; // is it at top level of a scope
unsigned visited : 1; // general purpose for walks
unsigned anticipated : 1;
unsigned available : 1;
unsigned localExprNotAltered : 1; // whether this node can be
// altered in this expression
unsigned nonNull : 1; // expression is not null
unsigned referenced : 1;
unsigned referenced_valid : 1; // is the above flag is valid
unsigned needed : 1;
unsigned needed_valid : 1; // is the above flag is valid
unsigned chainRoot : 1; // is this the begining of a
// CSE chain
unsigned noRemove : 1; // DCE should NOT remove this node
unsigned guarded : 1; // previously used
unsigned killed : 1;
unsigned refCounted : 2; // high bit indicates whether its valid
unsigned inited : 2; // high bit indicates whether its valid
} m_flags;
};
protected:
LocationPtr m_loc;
mutable int m_containedEffects;
mutable int m_effectsTag;
/**
* Called by analyzeProgram() to add a reference to a user class or
* function.
*/
void addUserFunction(AnalysisResultPtr ar, const std::string &name);
void addUserClass(AnalysisResultPtr ar, const std::string &name);
};
class LocalEffectsContainer {
public:
int getLocalEffects() const { return m_localEffects; }
virtual void effectsCallback() = 0;
protected:
explicit LocalEffectsContainer(Construct::Effect localEffect) :
m_localEffects(localEffect) {}
LocalEffectsContainer() :
m_localEffects(0) {}
void setLocalEffect (Construct::Effect effect);
void clearLocalEffect(Construct::Effect effect);
bool hasLocalEffect (Construct::Effect effect) const;
protected:
int m_localEffects;
};
#define DECL_AND_IMPL_LOCAL_EFFECTS_METHODS \
virtual int getLocalEffects() const { \
return LocalEffectsContainer::getLocalEffects(); \
} \
virtual void effectsCallback() { recomputeEffects(); }
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_CONSTRUCT_H_