2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_CONSTRUCT_H_
18 #define incl_HPHP_CONSTRUCT_H_
20 #include "hphp/parser/location.h"
21 #include "hphp/compiler/json.h"
23 #include "hphp/compiler/code_generator.h"
24 #include "hphp/compiler/analysis/code_error.h"
25 #include "hphp/compiler/analysis/block_scope.h"
28 ///////////////////////////////////////////////////////////////////////////////
31 DECLARE_BOOST_TYPES(Expression
);
32 DECLARE_BOOST_TYPES(StatementList
);
33 DECLARE_BOOST_TYPES(IParseHandler
);
34 DECLARE_BOOST_TYPES(AnalysisResult
);
35 DECLARE_BOOST_TYPES(BlockScope
);
36 DECLARE_BOOST_TYPES(ClassScope
);
37 DECLARE_BOOST_TYPES(FunctionScope
);
38 DECLARE_BOOST_TYPES(FileScope
);
40 class AstWalkerStateVec
;
44 * To avoid iteration of parse tree, we move any work that can be done
45 * in parse phase into this function, so to speed up static analysis.
48 virtual ~IParseHandler() {}
51 * onParse is called by the parser when the construct has just been parsed
52 * to allow it to do any necessary work
54 virtual void onParse(AnalysisResultConstPtr ar
, FileScopePtr scope
) {
58 * onParseRecur is called by a parent construct (ultimately a class or
60 * This is done because at the time that onParse would be called for
61 * (eg) a method, the ClassScope doesnt exist. So we wait until onParse
62 * is called for the class, and it calls onParseRecur for its children.
64 virtual void onParseRecur(AnalysisResultConstPtr ar
, FileScopeRawPtr fs
,
65 ClassScopePtr scope
) {
70 #define DECLARE_STATEMENT_TYPES(x) \
72 x(FunctionStatement) \
74 x(InterfaceStatement) \
80 x(IfBranchStatement) \
88 x(ContinueStatement) \
102 x(UseTraitStatement) \
103 x(ClassRequireStatement) \
104 x(TraitPrecStatement) \
105 x(TraitAliasStatement) \
108 #define DECLARE_EXPRESSION_TYPES(x) \
109 x(Expression, None) \
110 x(ExpressionList, None) \
111 x(AssignmentExpression, Store) \
112 x(SimpleVariable, Load) \
113 x(DynamicVariable, Load) \
114 x(StaticMemberExpression, Load) \
115 x(ArrayElementExpression, Load) \
116 x(DynamicFunctionCall, Call) \
117 x(SimpleFunctionCall, Call) \
118 x(ScalarExpression, None) \
119 x(ObjectPropertyExpression, Load) \
120 x(ObjectMethodExpression, Call) \
121 x(ListAssignment, Store) \
122 x(NewObjectExpression, Call) \
123 x(UnaryOpExpression, Update) \
124 x(IncludeExpression, Call) \
125 x(BinaryOpExpression, Update) \
126 x(QOpExpression, None) \
127 x(NullCoalesceExpression, None) \
128 x(ArrayPairExpression, None) \
129 x(ClassConstantExpression, Const) \
130 x(ParameterExpression, None) \
131 x(ModifierExpression, None) \
132 x(ConstantExpression, Const) \
133 x(EncapsListExpression, None) \
134 x(ClosureExpression, None) \
135 x(ClassExpression, None) \
136 x(YieldExpression, None) \
137 x(AwaitExpression, None) \
138 x(UserAttribute, None)
141 * Base class of Expression and Statement.
143 class Construct
: public std::enable_shared_from_this
<Construct
>,
144 public JSON::CodeError::ISerializable
{
146 virtual ~Construct() {}
148 #define DEC_STATEMENT_ENUM(x) KindOf##x,
149 #define DEC_EXPRESSION_ENUM(x,t) KindOf##x,
151 DECLARE_STATEMENT_TYPES(DEC_STATEMENT_ENUM
)
152 DECLARE_EXPRESSION_TYPES(DEC_EXPRESSION_ENUM
)
154 #undef DEC_EXPRESSION_ENUM
155 #undef DEC_STATEMENT_ENUM
158 Construct(BlockScopePtr scope
, const Location::Range
& loc
, KindOf
);
162 * Type checking without RTTI.
164 bool is(KindOf type
) const {
165 assert(m_kindOf
!= KindOfStatement
);
166 assert(m_kindOf
!= KindOfExpression
);
167 return m_kindOf
== type
;
169 KindOf
getKindOf() const {
170 assert(m_kindOf
!= KindOfStatement
);
171 assert(m_kindOf
!= KindOfExpression
);
175 bool isStatement() const {
176 return !isExpression();
178 bool isExpression() const {
179 return m_kindOf
> KindOfExpression
;
184 IOEffect
= 1, // could have an observable effect (not
185 // changing variable values)
186 AssignEffect
= 2, // writes an object in a way understood by the
188 GlobalEffect
= 4, // could affect global variables
189 LocalEffect
= 8, // could affect variables from the local scope
190 ParamEffect
= 0x10, // a function could affect its parameters
191 DeepParamEffect
= 0x20, // a function could affect the array elements
192 // or object members referenced by its
194 DynamicParamEffect
= 0x40, // a function creates dynamic exps based
195 // on its parameters, which it could affect
196 CanThrow
= 0x80, // can throw PHP exception
197 AccessorEffect
= 0x100, // could contain a getter/setter
198 CreateEffect
= 0x200, // could cause the creation of an array
199 // element or an object property
200 DiagnosticEffect
= 0x400, // can cause a diagnostic to be issued
201 OtherEffect
= 0x800, // something else
202 UnknownEffect
= 0xfff // any of the above
205 static bool SkipRecurse(ConstructPtr c
) {
206 return c
&& c
->skipRecurse();
208 bool skipRecurse() const;
209 void copyLocationTo(ConstructPtr other
);
210 const Location::Range
& getRange() const { return m_r
; }
211 int line0() const { return m_r
.line0
; }
212 int line1() const { return m_r
.line1
; }
213 void setFirst(int line0
, int char0
) { m_r
.line0
= line0
; m_r
.char0
= char0
; }
214 void setFileLevel() { m_flags
.topLevel
= m_flags
.fileLevel
= true;}
215 void setTopLevel() { m_flags
.topLevel
= true;}
216 bool isFileLevel() const { return m_flags
.fileLevel
;}
217 bool isTopLevel() const { return m_flags
.topLevel
;}
219 void setNeeded() { m_flags
.needed
= true; }
220 void clearNeeded() { m_flags
.needed
= false; }
221 bool isNeeded() const { return m_flags
.needed
; }
223 void setIsUnpack() { m_flags
.unpack
= 1; }
224 bool isUnpack() const { return m_flags
.unpack
; }
225 void clearIsUnpack() { m_flags
.unpack
= 0; }
227 BlockScopeRawPtr
getScope() const { return m_blockScope
; }
228 void setBlockScope(BlockScopeRawPtr scope
) { m_blockScope
= scope
; }
229 FileScopeRawPtr
getFileScope() const {
230 return m_blockScope
->getContainingFile();
232 FunctionScopeRawPtr
getFunctionScope() const {
233 return m_blockScope
->getContainingFunction();
235 ClassScopeRawPtr
getClassScope() const {
236 return m_blockScope
->getContainingClass();
238 void resetScope(BlockScopeRawPtr scope
);
239 void parseTimeFatal(FileScopeRawPtr fs
, Compiler::ErrorType error
,
240 ATTRIBUTE_PRINTF_STRING
const char *fmt
, ...) ATTRIBUTE_PRINTF(4,5);
241 void analysisTimeFatal(Compiler::ErrorType error
,
242 ATTRIBUTE_PRINTF_STRING
const char *fmt
, ...) ATTRIBUTE_PRINTF(3,4);
243 virtual int getLocalEffects() const { return UnknownEffect
;}
244 int getChildrenEffects() const;
245 int getContainedEffects() const;
246 bool hasEffect() const { return getContainedEffects() != NoEffect
;}
247 virtual bool kidUnused(int i
) const { return false; }
250 static std::shared_ptr
<T
> Clone(std::shared_ptr
<T
> constr
) {
252 return dynamic_pointer_cast
<T
>(constr
->clone());
254 return std::shared_ptr
<T
>();
258 std::shared_ptr
<T
> Clone(std::shared_ptr
<T
> constr
,
259 BlockScopePtr scope
) {
261 constr
= constr
->clone();
262 constr
->resetScope(scope
);
268 * Called when we analyze a program, which file it includes, which function
269 * and class it uses, etc.
271 virtual void analyzeProgram(AnalysisResultPtr ar
) = 0;
274 * return the nth child construct
276 virtual ConstructPtr
getNthKid(int n
) const { return ConstructPtr(); }
279 * set the nth child construct
281 virtual void setNthKid(int n
, ConstructPtr cp
) {}
286 virtual int getKidCount() const = 0;
289 void dumpNode(int spc
);
290 void dumpNode(int spc
) const;
292 void dump(int spc
, AnalysisResultConstPtr ar
);
293 void dumpNode(int spc
, AnalysisResultConstPtr ar
);
296 * Called when generating code.
298 virtual void outputPHP(CodeGenerator
&cg
, AnalysisResultPtr ar
) = 0;
301 * Implements JSON::CodeError::ISerializable.
303 virtual void serialize(JSON::CodeError::OutputStream
&out
) const;
306 * Get canonicalized PHP source code for this construct.
308 std::string
getText(AnalysisResultPtr ar
);
309 std::string
getText();
311 void recomputeEffects();
314 * Write where this construct was in PHP files.
316 void printSource(CodeGenerator
&cg
);
317 ExpressionPtr
makeConstant(AnalysisResultConstPtr ar
,
318 const std::string
&value
) const;
319 ExpressionPtr
makeScalarExpression(AnalysisResultConstPtr ar
,
320 const Variant
&value
) const;
322 BlockScopeRawPtr m_blockScope
;
326 unsigned fileLevel
: 1; // is it at top level of a file
327 unsigned topLevel
: 1; // is it at top level of a scope
329 unsigned unpack
: 1; // is this an unpack (only on params)
335 mutable int m_containedEffects
;
336 mutable int m_effectsTag
;
339 class LocalEffectsContainer
{
341 int getLocalEffects() const { return m_localEffects
; }
342 virtual void effectsCallback() = 0;
344 explicit LocalEffectsContainer(Construct::Effect localEffect
) :
345 m_localEffects(localEffect
) {}
346 LocalEffectsContainer() :
348 void setLocalEffect (Construct::Effect effect
);
349 void clearLocalEffect(Construct::Effect effect
);
350 bool hasLocalEffect (Construct::Effect effect
) const;
355 #define DECL_AND_IMPL_LOCAL_EFFECTS_METHODS \
356 int getLocalEffects() const override { \
357 return LocalEffectsContainer::getLocalEffects(); \
359 void effectsCallback() override { recomputeEffects(); }
361 ///////////////////////////////////////////////////////////////////////////////
363 #endif // incl_HPHP_CONSTRUCT_H_