Implement PHP7 null coalesce operator
[hiphop-php.git] / hphp / compiler / construct.h
blob0157acd8020304bcb9d22421426ff667cf8b2f9f
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
22 #include <memory>
23 #include "hphp/compiler/code_generator.h"
24 #include "hphp/compiler/analysis/code_error.h"
25 #include "hphp/compiler/analysis/block_scope.h"
27 namespace HPHP {
28 ///////////////////////////////////////////////////////////////////////////////
30 class Variant;
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;
42 class IParseHandler {
43 /**
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.
47 public:
48 virtual ~IParseHandler() {}
50 /**
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) {
55 always_assert(0);
57 /**
58 * onParseRecur is called by a parent construct (ultimately a class or
59 * interface).
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) {
66 always_assert(0);
70 #define DECLARE_STATEMENT_TYPES(x) \
71 x(Statement) \
72 x(FunctionStatement) \
73 x(ClassStatement) \
74 x(InterfaceStatement) \
75 x(ClassVariable) \
76 x(ClassConstant) \
77 x(MethodStatement) \
78 x(StatementList) \
79 x(BlockStatement) \
80 x(IfBranchStatement) \
81 x(IfStatement) \
82 x(WhileStatement) \
83 x(DoStatement) \
84 x(ForStatement) \
85 x(SwitchStatement) \
86 x(CaseStatement) \
87 x(BreakStatement) \
88 x(ContinueStatement) \
89 x(ReturnStatement) \
90 x(GlobalStatement) \
91 x(StaticStatement) \
92 x(EchoStatement) \
93 x(UnsetStatement) \
94 x(ExpStatement) \
95 x(ForEachStatement) \
96 x(FinallyStatement) \
97 x(CatchStatement) \
98 x(TryStatement) \
99 x(ThrowStatement) \
100 x(GotoStatement) \
101 x(LabelStatement) \
102 x(UseTraitStatement) \
103 x(ClassRequireStatement) \
104 x(TraitPrecStatement) \
105 x(TraitAliasStatement) \
106 x(TypedefStatement)
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 {
145 public:
146 virtual ~Construct() {}
148 #define DEC_STATEMENT_ENUM(x) KindOf##x,
149 #define DEC_EXPRESSION_ENUM(x,t) KindOf##x,
150 enum KindOf {
151 DECLARE_STATEMENT_TYPES(DEC_STATEMENT_ENUM)
152 DECLARE_EXPRESSION_TYPES(DEC_EXPRESSION_ENUM)
154 #undef DEC_EXPRESSION_ENUM
155 #undef DEC_STATEMENT_ENUM
157 protected:
158 Construct(BlockScopePtr scope, const Location::Range& loc, KindOf);
160 public:
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);
172 return m_kindOf;
175 bool isStatement() const {
176 return !isExpression();
178 bool isExpression() const {
179 return m_kindOf > KindOfExpression;
182 enum Effect {
183 NoEffect = 0,
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
187 // alias manager
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
193 // parameters
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; }
249 template<typename T>
250 static std::shared_ptr<T> Clone(std::shared_ptr<T> constr) {
251 if (constr) {
252 return dynamic_pointer_cast<T>(constr->clone());
254 return std::shared_ptr<T>();
257 template<typename T>
258 std::shared_ptr<T> Clone(std::shared_ptr<T> constr,
259 BlockScopePtr scope) {
260 if (constr) {
261 constr = constr->clone();
262 constr->resetScope(scope);
264 return constr;
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) {}
284 * get the kid count
286 virtual int getKidCount() const = 0;
288 // helpers for GDB
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;
321 private:
322 BlockScopeRawPtr m_blockScope;
323 union {
324 unsigned m_flagsVal;
325 struct {
326 unsigned fileLevel : 1; // is it at top level of a file
327 unsigned topLevel : 1; // is it at top level of a scope
328 unsigned needed : 1;
329 unsigned unpack : 1; // is this an unpack (only on params)
330 } m_flags;
332 Location::Range m_r;
333 protected:
334 KindOf m_kindOf;
335 mutable int m_containedEffects;
336 mutable int m_effectsTag;
339 class LocalEffectsContainer {
340 public:
341 int getLocalEffects() const { return m_localEffects; }
342 virtual void effectsCallback() = 0;
343 protected:
344 explicit LocalEffectsContainer(Construct::Effect localEffect) :
345 m_localEffects(localEffect) {}
346 LocalEffectsContainer() :
347 m_localEffects(0) {}
348 void setLocalEffect (Construct::Effect effect);
349 void clearLocalEffect(Construct::Effect effect);
350 bool hasLocalEffect (Construct::Effect effect) const;
351 protected:
352 int m_localEffects;
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_