2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 +----------------------------------------------------------------------+
16 #include "hphp/compiler/parser/parser.h"
18 #include <boost/make_shared.hpp>
20 #include "hphp/compiler/type_annotation.h"
21 #include "hphp/util/parser/hphp.tab.hpp"
22 #include "hphp/compiler/analysis/file_scope.h"
24 #include "hphp/compiler/expression/expression_list.h"
25 #include "hphp/compiler/expression/assignment_expression.h"
26 #include "hphp/compiler/expression/simple_variable.h"
27 #include "hphp/compiler/expression/dynamic_variable.h"
28 #include "hphp/compiler/expression/static_member_expression.h"
29 #include "hphp/compiler/expression/array_element_expression.h"
30 #include "hphp/compiler/expression/dynamic_function_call.h"
31 #include "hphp/compiler/expression/simple_function_call.h"
32 #include "hphp/compiler/expression/scalar_expression.h"
33 #include "hphp/compiler/expression/object_property_expression.h"
34 #include "hphp/compiler/expression/object_method_expression.h"
35 #include "hphp/compiler/expression/list_assignment.h"
36 #include "hphp/compiler/expression/new_object_expression.h"
37 #include "hphp/compiler/expression/include_expression.h"
38 #include "hphp/compiler/expression/unary_op_expression.h"
39 #include "hphp/compiler/expression/binary_op_expression.h"
40 #include "hphp/compiler/expression/qop_expression.h"
41 #include "hphp/compiler/expression/array_pair_expression.h"
42 #include "hphp/compiler/expression/class_constant_expression.h"
43 #include "hphp/compiler/expression/parameter_expression.h"
44 #include "hphp/compiler/expression/modifier_expression.h"
45 #include "hphp/compiler/expression/constant_expression.h"
46 #include "hphp/compiler/expression/encaps_list_expression.h"
47 #include "hphp/compiler/expression/closure_expression.h"
48 #include "hphp/compiler/expression/yield_expression.h"
49 #include "hphp/compiler/expression/user_attribute.h"
51 #include "hphp/compiler/statement/function_statement.h"
52 #include "hphp/compiler/statement/class_statement.h"
53 #include "hphp/compiler/statement/interface_statement.h"
54 #include "hphp/compiler/statement/class_variable.h"
55 #include "hphp/compiler/statement/class_constant.h"
56 #include "hphp/compiler/statement/method_statement.h"
57 #include "hphp/compiler/statement/statement_list.h"
58 #include "hphp/compiler/statement/block_statement.h"
59 #include "hphp/compiler/statement/if_branch_statement.h"
60 #include "hphp/compiler/statement/if_statement.h"
61 #include "hphp/compiler/statement/while_statement.h"
62 #include "hphp/compiler/statement/do_statement.h"
63 #include "hphp/compiler/statement/for_statement.h"
64 #include "hphp/compiler/statement/switch_statement.h"
65 #include "hphp/compiler/statement/case_statement.h"
66 #include "hphp/compiler/statement/break_statement.h"
67 #include "hphp/compiler/statement/continue_statement.h"
68 #include "hphp/compiler/statement/return_statement.h"
69 #include "hphp/compiler/statement/global_statement.h"
70 #include "hphp/compiler/statement/static_statement.h"
71 #include "hphp/compiler/statement/echo_statement.h"
72 #include "hphp/compiler/statement/unset_statement.h"
73 #include "hphp/compiler/statement/exp_statement.h"
74 #include "hphp/compiler/statement/foreach_statement.h"
75 #include "hphp/compiler/statement/catch_statement.h"
76 #include "hphp/compiler/statement/try_statement.h"
77 #include "hphp/compiler/statement/finally_statement.h"
78 #include "hphp/compiler/statement/throw_statement.h"
79 #include "hphp/compiler/statement/goto_statement.h"
80 #include "hphp/compiler/statement/label_statement.h"
81 #include "hphp/compiler/statement/use_trait_statement.h"
82 #include "hphp/compiler/statement/trait_prec_statement.h"
83 #include "hphp/compiler/statement/trait_alias_statement.h"
84 #include "hphp/compiler/statement/typedef_statement.h"
86 #include "hphp/compiler/analysis/function_scope.h"
88 #include "hphp/compiler/analysis/code_error.h"
89 #include "hphp/compiler/analysis/analysis_result.h"
91 #include "hphp/util/lock.h"
92 #include "hphp/util/logger.h"
94 #include "hphp/runtime/base/file_repository.h"
97 #include "hphp/facebook/src/compiler/fb_compiler_hooks.h"
98 #define RealSimpleFunctionCall FBSimpleFunctionCall
100 #define RealSimpleFunctionCall SimpleFunctionCall
103 #define NEW_EXP0(cls) \
104 cls##Ptr(new cls(BlockScopePtr(), getLocation()))
105 #define NEW_EXP(cls, e...) \
106 cls##Ptr(new cls(BlockScopePtr(), getLocation(), ##e))
107 #define NEW_STMT0(cls) \
108 cls##Ptr(new cls(BlockScopePtr(), getLocation()))
109 #define NEW_STMT(cls, e...) \
110 cls##Ptr(new cls(BlockScopePtr(), getLocation(), ##e))
112 #define PARSE_ERROR(fmt, args...) HPHP_PARSER_ERROR(fmt, this, ##args)
114 using namespace HPHP::Compiler
;
116 extern void prepare_generator(Parser
*_p
, Token
&stmt
, Token
¶ms
);
117 extern void create_generator(Parser
*_p
, Token
&out
, Token
¶ms
,
118 Token
&name
, const std::string
&genName
,
119 const char *clsname
, Token
*modifiers
,
120 Token
&origGenFunc
, bool isHhvm
,
125 SimpleFunctionCallPtr
NewSimpleFunctionCall(
126 EXPRESSION_CONSTRUCTOR_PARAMETERS
,
127 const std::string
&name
, bool hadBackslash
, ExpressionListPtr params
,
129 return SimpleFunctionCallPtr(
130 new RealSimpleFunctionCall(
131 EXPRESSION_CONSTRUCTOR_DERIVED_PARAMETER_VALUES
,
132 name
, hadBackslash
, params
, cls
));
136 ///////////////////////////////////////////////////////////////////////////////
139 StatementListPtr
Parser::ParseString(CStrRef input
, AnalysisResultPtr ar
,
140 const char *fileName
/* = NULL */,
141 bool lambdaMode
/* = false */) {
142 assert(!input
.empty());
143 if (!fileName
|| !*fileName
) fileName
= "string";
145 int len
= input
.size();
146 Scanner
scanner(input
.data(), len
, Option::GetScannerType(), fileName
, true);
147 Parser
parser(scanner
, fileName
, ar
, len
);
148 parser
.m_lambdaMode
= lambdaMode
;
149 if (parser
.parse()) {
150 return parser
.m_file
->getStmt();
152 Logger::Error("Error parsing %s: %s\n%s\n", fileName
,
153 parser
.getMessage().c_str(), input
.data());
154 return StatementListPtr();
157 ///////////////////////////////////////////////////////////////////////////////
159 Parser::Parser(Scanner
&scanner
, const char *fileName
,
160 AnalysisResultPtr ar
, int fileSize
/* = 0 */)
161 : ParserBase(scanner
, fileName
), m_ar(ar
), m_lambdaMode(false),
162 m_closureGenerator(false), m_nsState(SeenNothing
) {
163 string md5str
= Eval::FileRepository::unitMd5(scanner
.getMd5());
164 MD5 md5
= MD5(md5str
.c_str());
166 m_file
= FileScopePtr(new FileScope(m_fileName
, fileSize
, md5
));
169 m_staticVars
.push_back(StringToExpressionPtrVecMap());
172 Lock
lock(m_ar
->getMutex());
173 m_ar
->addFileScope(m_file
);
175 m_prependingStatements
.push_back(vector
<StatementPtr
>());
178 bool Parser::parse() {
181 throw ParseTimeFatalException(m_fileName
, line1(),
183 errString().c_str());
185 } catch (ParseTimeFatalException
&e
) {
186 m_file
->cleanupForError(m_ar
, e
.m_line
, e
.getMessage());
191 void Parser::error(const char* fmt
, ...) {
195 Util::string_vsnprintf(msg
, fmt
, ap
);
198 fatal(&m_loc
, msg
.c_str());
201 void Parser::fatal(Location
*loc
, const char *msg
) {
202 throw ParseTimeFatalException(loc
->file
, loc
->line0
,
206 string
Parser::errString() {
207 return m_error
.empty() ? getMessage() : m_error
;
210 bool Parser::enableXHP() {
211 return Option::EnableXHP
;
214 bool Parser::enableFinallyStatement() {
215 return Option::EnableFinallyStatement
;
218 void Parser::pushComment() {
219 m_comments
.push_back(m_scanner
.detachDocComment());
222 void Parser::pushComment(const std::string
& s
) {
223 m_comments
.push_back(s
);
226 std::string
Parser::popComment() {
227 std::string ret
= m_comments
.back();
228 m_comments
.pop_back();
232 void Parser::newScope() {
233 m_scopes
.push_back(BlockScopePtrVec());
236 void Parser::completeScope(BlockScopePtr inner
) {
237 always_assert(inner
);
238 BlockScopePtrVec
&sv
= m_scopes
.back();
239 for (int i
= 0, n
= sv
.size(); i
< n
; i
++) {
240 BlockScopePtr scope
= sv
[i
];
241 scope
->setOuterScope(inner
);
243 inner
->getStmt()->resetScope(inner
);
245 if (m_scopes
.size()) {
246 m_scopes
.back().push_back(inner
);
250 ///////////////////////////////////////////////////////////////////////////////
253 void Parser::onName(Token
&out
, Token
&name
, NameKind kind
) {
257 onScalar(out
, T_STRING
, name
);
259 case StaticClassExprName
:
267 void Parser::onStaticVariable(Token
&out
, Token
*exprs
, Token
&var
,
269 onVariable(out
, exprs
, var
, value
);
270 if (m_staticVars
.size()) {
271 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
272 m
[var
->text()].push_back(out
->exp
);
276 void Parser::onClassVariable(Token
&out
, Token
*exprs
, Token
&var
,
278 onVariable(out
, exprs
, var
, value
, false, m_scanner
.detachDocComment());
281 void Parser::onClassConstant(Token
&out
, Token
*exprs
, Token
&var
,
283 onVariable(out
, exprs
, var
, &value
, true, m_scanner
.detachDocComment());
286 void Parser::onVariable(Token
&out
, Token
*exprs
, Token
&var
, Token
*value
,
287 bool constant
/* = false */,
288 const std::string
&docComment
/* = "" */) {
289 ExpressionPtr expList
;
291 expList
= exprs
->exp
;
293 expList
= NEW_EXP0(ExpressionList
);
297 exp
= NEW_EXP(ConstantExpression
, var
->text(), false, docComment
);
299 exp
= NEW_EXP(SimpleVariable
, var
->text(), docComment
);
302 exp
= NEW_EXP(AssignmentExpression
, exp
, value
->exp
, false);
304 expList
->addElement(exp
);
308 void Parser::onSimpleVariable(Token
&out
, Token
&var
) {
309 out
->exp
= NEW_EXP(SimpleVariable
, var
->text());
312 void Parser::onDynamicVariable(Token
&out
, Token
&expr
, bool encap
) {
313 out
->exp
= getDynamicVariable(expr
->exp
, encap
);
316 void Parser::onIndirectRef(Token
&out
, Token
&refCount
, Token
&var
) {
318 for (int i
= 0; i
< refCount
->num(); i
++) {
319 out
->exp
= createDynamicVariable(out
->exp
);
323 void Parser::onStaticMember(Token
&out
, Token
&cls
, Token
&name
) {
324 if (name
->exp
->is(Expression::KindOfArrayElementExpression
) &&
325 dynamic_pointer_cast
<ArrayElementExpression
>(name
->exp
)->
326 appendClass(cls
->exp
, m_ar
, m_file
)) {
327 out
->exp
= name
->exp
;
329 StaticMemberExpressionPtr sme
= NEW_EXP(StaticMemberExpression
,
330 cls
->exp
, name
->exp
);
331 sme
->onParse(m_ar
, m_file
);
336 void Parser::onRefDim(Token
&out
, Token
&var
, Token
&offset
) {
338 var
->exp
= NEW_EXP(ConstantExpression
, var
->text(), var
->num() & 2);
341 UnaryOpExpressionPtr uop
;
343 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
344 PARSE_ERROR("Can't use function call result as array base"
345 " in write context");
346 } else if ((uop
= dynamic_pointer_cast
<UnaryOpExpression
>(var
->exp
))
347 && uop
->getOp() == T_ARRAY
) {
348 PARSE_ERROR("Can't use array() as base in write context");
351 out
->exp
= NEW_EXP(ArrayElementExpression
, var
->exp
, offset
->exp
);
354 ExpressionPtr
Parser::getDynamicVariable(ExpressionPtr exp
, bool encap
) {
356 ConstantExpressionPtr var
= dynamic_pointer_cast
<ConstantExpression
>(exp
);
358 return NEW_EXP(SimpleVariable
, var
->getName());
361 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(exp
);
363 return NEW_EXP(SimpleVariable
, var
->getString());
366 return createDynamicVariable(exp
);
369 ExpressionPtr
Parser::createDynamicVariable(ExpressionPtr exp
) {
370 m_file
->setAttribute(FileScope::ContainsDynamicVariable
);
371 return NEW_EXP(DynamicVariable
, exp
);
374 void Parser::onCallParam(Token
&out
, Token
*params
, Token
&expr
, bool ref
) {
376 out
->exp
= NEW_EXP0(ExpressionList
);
378 out
->exp
= params
->exp
;
381 expr
->exp
->setContext(Expression::RefParameter
);
382 expr
->exp
->setContext(Expression::RefValue
);
384 out
->exp
->addElement(expr
->exp
);
387 void Parser::onCall(Token
&out
, bool dynamic
, Token
&name
, Token
¶ms
,
388 Token
*cls
, bool fromCompiler
) {
389 ExpressionPtr clsExp
;
394 out
->exp
= NEW_EXP(DynamicFunctionCall
, name
->exp
,
395 dynamic_pointer_cast
<ExpressionList
>(params
->exp
),
397 assert(!fromCompiler
);
399 const string
&s
= name
.text();
400 if (s
== "func_num_args" || s
== "func_get_args" || s
== "func_get_arg") {
401 if (m_hasCallToGetArgs
.size() > 0) {
402 m_hasCallToGetArgs
.back() = true;
406 SimpleFunctionCallPtr call
407 (new RealSimpleFunctionCall
408 (BlockScopePtr(), getLocation(), name
->text(), name
->num() & 2,
409 dynamic_pointer_cast
<ExpressionList
>(params
->exp
), clsExp
));
411 call
->setFromCompiler();
415 call
->onParse(m_ar
, m_file
);
419 ///////////////////////////////////////////////////////////////////////////////
420 // object property and method calls
422 void Parser::onObjectProperty(Token
&out
, Token
&base
, Token
&prop
) {
424 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
426 out
->exp
= NEW_EXP(ObjectPropertyExpression
, base
->exp
, prop
->exp
);
429 void Parser::onObjectMethodCall(Token
&out
, Token
&base
, Token
&prop
,
432 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
434 ExpressionListPtr paramsExp
;
436 paramsExp
= dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
438 paramsExp
= NEW_EXP0(ExpressionList
);
440 out
->exp
= NEW_EXP(ObjectMethodExpression
, base
->exp
, prop
->exp
, paramsExp
);
443 ///////////////////////////////////////////////////////////////////////////////
444 // encapsed expressions
446 void Parser::onEncapsList(Token
&out
, int type
, Token
&list
) {
447 out
->exp
= NEW_EXP(EncapsListExpression
, type
,
448 dynamic_pointer_cast
<ExpressionList
>(list
->exp
));
451 void Parser::addEncap(Token
&out
, Token
*list
, Token
&expr
, int type
) {
452 ExpressionListPtr expList
;
453 if (list
&& list
->exp
) {
454 expList
= dynamic_pointer_cast
<ExpressionList
>(list
->exp
);
456 expList
= NEW_EXP0(ExpressionList
);
462 exp
= NEW_EXP(ScalarExpression
, T_ENCAPSED_AND_WHITESPACE
,
465 expList
->addElement(exp
);
469 void Parser::encapRefDim(Token
&out
, Token
&var
, Token
&offset
) {
471 switch (offset
->num()) {
473 dim
= NEW_EXP(ScalarExpression
, T_STRING
, offset
->text(), true);
476 dim
= NEW_EXP(ScalarExpression
, T_NUM_STRING
, offset
->text());
479 dim
= NEW_EXP(SimpleVariable
, offset
->text());
485 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
486 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, dim
);
489 void Parser::encapObjProp(Token
&out
, Token
&var
, Token
&name
) {
490 ExpressionPtr obj
= NEW_EXP(SimpleVariable
, var
->text());
492 ExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
->text());
493 out
->exp
= NEW_EXP(ObjectPropertyExpression
, obj
, prop
);
496 void Parser::encapArray(Token
&out
, Token
&var
, Token
&expr
) {
497 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
498 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, expr
->exp
);
501 ///////////////////////////////////////////////////////////////////////////////
504 void Parser::onConstantValue(Token
&out
, Token
&constant
) {
505 ConstantExpressionPtr con
= NEW_EXP(ConstantExpression
, constant
->text(),
506 constant
->num() & 2);
507 con
->onParse(m_ar
, m_file
);
511 void Parser::onScalar(Token
&out
, int type
, Token
&scalar
) {
512 if (type
== T_FILE
|| type
== T_DIR
) {
513 onUnaryOpExp(out
, scalar
, type
, true);
517 ScalarExpressionPtr exp
;
521 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
522 m_clsName
+ "::" + m_funcName
);
524 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
531 case T_COMPILER_HALT_OFFSET
:
534 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
537 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
538 m_inTrait
? m_clsName
: "");
541 exp
= NEW_EXP(ScalarExpression
, type
, m_namespace
);
543 case T_CONSTANT_ENCAPSED_STRING
:
544 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(), true);
549 if (type
== T_COMPILER_HALT_OFFSET
) {
550 // Keep track of this expression for later backpatching
551 // If it doesn't get backpatched (because there was no HALT_COMPILER
552 // then the constant will return (int)"__COMPILER_HALT_OFFSET__" (zero)
553 m_compilerHaltOffsetVec
.push_back(exp
);
558 void Parser::onExprListElem(Token
&out
, Token
*exprs
, Token
&expr
) {
559 ExpressionPtr expList
;
560 if (exprs
&& exprs
->exp
) {
561 expList
= exprs
->exp
;
563 expList
= NEW_EXP0(ExpressionList
);
565 expList
->addElement(expr
->exp
);
569 void Parser::onListAssignment(Token
&out
, Token
&vars
, Token
*expr
,
570 bool rhsFirst
/* = false */) {
571 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(vars
->exp
));
572 for (int i
= 0; i
< el
->getCount(); i
++) {
573 if (dynamic_pointer_cast
<FunctionCall
>((*el
)[i
])) {
574 PARSE_ERROR("Can't use return value in write context");
577 out
->exp
= NEW_EXP(ListAssignment
,
578 dynamic_pointer_cast
<ExpressionList
>(vars
->exp
),
579 expr
? expr
->exp
: ExpressionPtr(), rhsFirst
);
582 void Parser::onAListVar(Token
&out
, Token
*list
, Token
*var
) {
583 Token empty_list
, empty_var
;
585 empty_var
.exp
= ExpressionPtr();
589 empty_list
.exp
= NEW_EXP0(ExpressionList
);
592 onExprListElem(out
, list
, *var
);
595 void Parser::onAListSub(Token
&out
, Token
*list
, Token
&sublist
) {
596 onListAssignment(out
, sublist
, nullptr);
597 onExprListElem(out
, list
, out
);
600 void Parser::checkAssignThis(Token
&var
) {
601 if (SimpleVariablePtr simp
= dynamic_pointer_cast
<SimpleVariable
>(var
.exp
)) {
602 if (simp
->getName() == "this") {
603 PARSE_ERROR("Cannot re-assign $this");
608 void Parser::onAssign(Token
&out
, Token
&var
, Token
&expr
, bool ref
,
609 bool rhsFirst
/* = false */) {
610 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
611 PARSE_ERROR("Can't use return value in write context");
613 checkAssignThis(var
);
614 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, expr
->exp
, ref
, rhsFirst
);
617 void Parser::onAssignNew(Token
&out
, Token
&var
, Token
&name
, Token
&args
) {
618 checkAssignThis(var
);
620 NEW_EXP(NewObjectExpression
, name
->exp
,
621 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
622 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, exp
, true);
625 void Parser::onNewObject(Token
&out
, Token
&name
, Token
&args
) {
626 NewObjectExpressionPtr new_obj
=
627 NEW_EXP(NewObjectExpression
, name
->exp
,
628 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
629 new_obj
->onParse(m_ar
, m_file
);
633 void Parser::onUnaryOpExp(Token
&out
, Token
&operand
, int op
, bool front
) {
640 IncludeExpressionPtr exp
= NEW_EXP(IncludeExpression
, operand
->exp
, op
);
642 exp
->onParse(m_ar
, m_file
);
650 if (dynamic_pointer_cast
<FunctionCall
>(operand
->exp
)) {
651 PARSE_ERROR("Can't use return value in write context");
655 UnaryOpExpressionPtr exp
= NEW_EXP(UnaryOpExpression
, operand
->exp
, op
,
658 exp
->onParse(m_ar
, m_file
);
664 void Parser::onBinaryOpExp(Token
&out
, Token
&operand1
, Token
&operand2
,
666 BinaryOpExpressionPtr bop
=
667 NEW_EXP(BinaryOpExpression
, operand1
->exp
, operand2
->exp
, op
);
669 if (bop
->isAssignmentOp() &&
670 dynamic_pointer_cast
<FunctionCall
>(operand1
->exp
)) {
671 PARSE_ERROR("Can't use return value in write context");
676 // If the operands are simple enough we can fold this expression right
677 // here and keep the parse tree smaller.
678 if (ExpressionPtr optExp
= bop
->foldConst(m_ar
)) out
->exp
= optExp
;
681 void Parser::onQOp(Token
&out
, Token
&exprCond
, Token
*expYes
, Token
&expNo
) {
682 out
->exp
= NEW_EXP(QOpExpression
, exprCond
->exp
,
683 expYes
? expYes
->exp
: ExpressionPtr(), expNo
->exp
);
686 void Parser::onArray(Token
&out
, Token
&pairs
, int op
/* = T_ARRAY */) {
687 if (op
!= T_ARRAY
&& !m_scanner
.hipHopSyntaxEnabled()) {
688 PARSE_ERROR("Typed collection is not enabled");
691 onUnaryOpExp(out
, pairs
, T_ARRAY
, true);
694 void Parser::onArrayPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
,
696 if (!value
->exp
) return;
698 ExpressionPtr expList
;
699 if (pairs
&& pairs
->exp
) {
700 expList
= pairs
->exp
;
702 expList
= NEW_EXP0(ExpressionList
);
704 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
705 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, ref
));
709 void Parser::onEmptyCollection(Token
&out
) {
710 out
->exp
= NEW_EXP0(ExpressionList
);
714 Parser::onCollectionPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
) {
715 if (!value
->exp
) return;
717 ExpressionPtr expList
;
718 if (pairs
&& pairs
->exp
) {
719 expList
= pairs
->exp
;
721 expList
= NEW_EXP0(ExpressionList
);
723 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
724 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, false,
729 void Parser::onUserAttribute(Token
&out
, Token
*attrList
, Token
&name
,
731 ExpressionPtr expList
;
732 if (attrList
&& attrList
->exp
) {
733 expList
= attrList
->exp
;
735 expList
= NEW_EXP0(ExpressionList
);
737 expList
->addElement(NEW_EXP(UserAttribute
, name
->text(), value
->exp
));
741 void Parser::onClassConst(Token
&out
, Token
&cls
, Token
&name
, bool text
) {
743 cls
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, cls
->text());
745 ClassConstantExpressionPtr con
=
746 NEW_EXP(ClassConstantExpression
, cls
->exp
, name
->text());
747 con
->onParse(m_ar
, m_file
);
751 ///////////////////////////////////////////////////////////////////////////////
752 // function/method declaration
754 void Parser::onFunctionStart(Token
&name
, bool doPushComment
/* = true */) {
755 m_file
->pushAttribute();
760 m_funcContexts
.push_back(FunctionContext());
761 m_prependingStatements
.push_back(vector
<StatementPtr
>());
762 m_funcName
= name
.text();
763 m_hasCallToGetArgs
.push_back(false);
764 m_staticVars
.push_back(StringToExpressionPtrVecMap());
767 void Parser::onMethodStart(Token
&name
, Token
&mods
,
768 bool doPushComment
/* = true */) {
769 onFunctionStart(name
, doPushComment
);
772 void Parser::fixStaticVars() {
773 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
774 for (StringToExpressionPtrVecMap::iterator it
= m
.begin(), end
= m
.end();
776 const ExpressionPtrVec
&v
= it
->second
;
779 for (int i
= v
.size(); i
--; ) {
780 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(v
[i
]));
781 for (int j
= el
->getCount(); j
--; ) {
782 ExpressionPtr s
= (*el
)[j
];
783 SimpleVariablePtr v
= dynamic_pointer_cast
<SimpleVariable
>(
784 s
->is(Expression::KindOfAssignmentExpression
) ?
785 static_pointer_cast
<AssignmentExpression
>(s
)->getVariable() : s
);
786 if (v
->getName() == it
->first
) {
790 el
->removeElement(j
);
791 el
->insertElement(last
->clone(), j
);
798 m_staticVars
.pop_back();
801 void Parser::onFunction(Token
&out
, Token
*modifiers
, Token
&ret
, Token
&ref
,
802 Token
&name
, Token
¶ms
, Token
&stmt
, Token
*attr
) {
803 ModifierExpressionPtr exp
= modifiers
?
804 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
805 : NEW_EXP0(ModifierExpression
);
808 stmt
->stmt
= NEW_STMT0(StatementList
);
811 ExpressionListPtr old_params
=
812 dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
813 int attribute
= m_file
->popAttribute();
814 string comment
= popComment();
815 LocationPtr loc
= popFuncLocation();
817 FunctionContext funcContext
= m_funcContexts
.back();
818 m_funcContexts
.pop_back();
819 m_prependingStatements
.pop_back();
821 funcContext
.checkFinalAssertions();
823 bool hasCallToGetArgs
= m_hasCallToGetArgs
.back();
824 m_hasCallToGetArgs
.pop_back();
828 FunctionStatementPtr func
;
830 string funcName
= name
->text();
831 if (funcName
.empty()) {
832 funcName
= newClosureName(m_clsName
, m_containingFuncName
);
833 } else if (m_lambdaMode
) {
834 funcName
+= "{lambda}";
837 if (funcContext
.isGenerator
) {
838 string genName
= newContinuationName(funcName
);
841 prepare_generator(this, stmt
, new_params
);
843 func
= NEW_STMT(FunctionStatement
, exp
, ref
->num(), genName
,
844 dynamic_pointer_cast
<ExpressionList
>(new_params
->exp
),
845 ret
.typeAnnotationName(),
846 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
),
847 attribute
, comment
, ExpressionListPtr());
849 func
->getLocation()->line0
= loc
->line0
;
850 func
->getLocation()->char0
= loc
->char0
;
852 func
->onParse(m_ar
, m_file
);
854 completeScope(func
->getFunctionScope());
855 if (func
->ignored()) {
856 out
->stmt
= NEW_STMT0(StatementList
);
858 assert(!m_prependingStatements
.empty());
859 vector
<StatementPtr
> &prepending
= m_prependingStatements
.back();
860 prepending
.push_back(func
);
862 if (name
->text().empty()) m_closureGenerator
= true;
863 // create_generator() expects us to push the docComment back
864 // onto the comment stack so that it can make sure that the
865 // the MethodStatement it's building will get the docComment
866 pushComment(comment
);
868 create_generator(this, out
, params
, name
, genName
, nullptr, nullptr,
870 (!Option::WholeProgram
|| !Option::ParseTimeOpts
),
872 m_closureGenerator
= false;
873 MethodStatementPtr origStmt
=
874 boost::dynamic_pointer_cast
<MethodStatement
>(origGenFunc
->stmt
);
876 func
->setOrigGeneratorFunc(origStmt
);
877 origStmt
->setGeneratorFunc(func
);
878 origStmt
->setHasCallToGetArgs(hasCallToGetArgs
);
879 func
->setHasCallToGetArgs(hasCallToGetArgs
);
883 ExpressionListPtr attrList
;
884 if (attr
&& attr
->exp
) {
885 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
888 func
= NEW_STMT(FunctionStatement
, exp
, ref
->num(), funcName
, old_params
,
889 ret
.typeAnnotationName(),
890 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
),
891 attribute
, comment
, attrList
);
895 func
->onParse(m_ar
, m_file
);
897 completeScope(func
->getFunctionScope());
898 if (m_closureGenerator
) {
899 func
->getFunctionScope()->setClosureGenerator();
901 func
->getLocation()->line0
= loc
->line0
;
902 func
->getLocation()->char0
= loc
->char0
;
903 if (func
->ignored()) {
904 out
->stmt
= NEW_STMT0(StatementList
);
909 void Parser::onParam(Token
&out
, Token
*params
, Token
&type
, Token
&var
,
910 bool ref
, Token
*defValue
, Token
*attr
, Token
*modifier
) {
911 ExpressionPtr expList
;
913 expList
= params
->exp
;
915 expList
= NEW_EXP0(ExpressionList
);
917 ExpressionListPtr attrList
;
918 if (attr
&& attr
->exp
) {
919 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
922 TypeAnnotationPtr typeAnnotation
= type
.typeAnnotation
;
923 expList
->addElement(NEW_EXP(ParameterExpression
, typeAnnotation
,
924 m_scanner
.hipHopSyntaxEnabled(), var
->text(),
925 ref
, (modifier
) ? modifier
->num() : 0,
926 defValue
? defValue
->exp
: ExpressionPtr(),
931 void Parser::onClassStart(int type
, Token
&name
) {
932 const Type::TypePtrMap
& typeHintTypes
=
933 Type::GetTypeHintTypes(m_scanner
.hipHopSyntaxEnabled());
934 if (name
.text() == "self" || name
.text() == "parent" ||
935 typeHintTypes
.find(name
.text()) != typeHintTypes
.end()) {
936 PARSE_ERROR("Cannot use '%s' as class name as it is reserved",
937 name
.text().c_str());
942 m_clsName
= name
.text();
943 m_inTrait
= type
== T_TRAIT
;
946 void Parser::onClass(Token
&out
, int type
, Token
&name
, Token
&base
,
947 Token
&baseInterface
, Token
&stmt
, Token
*attr
) {
948 StatementListPtr stmtList
;
950 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
952 ExpressionListPtr attrList
;
953 if (attr
&& attr
->exp
) {
954 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
957 ClassStatementPtr cls
= NEW_STMT
958 (ClassStatement
, type
, name
->text(), base
->text(),
959 dynamic_pointer_cast
<ExpressionList
>(baseInterface
->exp
),
960 popComment(), stmtList
, attrList
);
962 // look for argument promotion in ctor
963 ExpressionListPtr promote
= NEW_EXP(ExpressionList
);
964 cls
->checkArgumentsToPromote(promote
, type
);
965 for (int i
= 0, count
= promote
->getCount(); i
< count
; i
++) {
967 dynamic_pointer_cast
<ParameterExpression
>((*promote
)[i
]);
968 TokenID mod
= param
->getModifier();
969 std::string name
= param
->getName();
970 std::string type
= param
->hasUserType() ?
971 param
->getUserTypeHint() : "";
973 // create the class variable and change the location to
974 // point to the paramenter location for error reporting
975 LocationPtr location
= param
->getLocation();
976 ModifierExpressionPtr modifier
= NEW_EXP0(ModifierExpression
);
978 modifier
->setLocation(location
);
979 SimpleVariablePtr svar
= NEW_EXP(SimpleVariable
, name
);
980 svar
->setLocation(location
);
981 ExpressionListPtr expList
= NEW_EXP0(ExpressionList
);
982 expList
->addElement(svar
);
983 expList
->setLocation(location
);
984 ClassVariablePtr var
= NEW_STMT(ClassVariable
, modifier
, type
, expList
);
985 var
->setLocation(location
);
986 cls
->getStmts()->addElement(var
);
991 cls
->onParse(m_ar
, m_file
);
993 completeScope(cls
->getClassScope());
994 if (cls
->ignored()) {
995 out
->stmt
= NEW_STMT0(StatementList
);
999 registerAlias(name
.text());
1002 void Parser::onInterface(Token
&out
, Token
&name
, Token
&base
, Token
&stmt
,
1004 StatementListPtr stmtList
;
1006 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1008 ExpressionListPtr attrList
;
1009 if (attr
&& attr
->exp
) {
1010 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1013 InterfaceStatementPtr intf
= NEW_STMT
1014 (InterfaceStatement
, name
->text(),
1015 dynamic_pointer_cast
<ExpressionList
>(base
->exp
), popComment(), stmtList
,
1019 intf
->onParse(m_ar
, m_file
);
1021 completeScope(intf
->getClassScope());
1024 void Parser::onInterfaceName(Token
&out
, Token
*names
, Token
&name
) {
1025 ExpressionPtr expList
;
1027 expList
= names
->exp
;
1029 expList
= NEW_EXP0(ExpressionList
);
1031 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1035 void Parser::onTraitUse(Token
&out
, Token
&traits
, Token
&rules
) {
1037 rules
->stmt
= NEW_STMT0(StatementList
);
1039 out
->stmt
= NEW_STMT(UseTraitStatement
,
1040 dynamic_pointer_cast
<ExpressionList
>(traits
->exp
),
1041 dynamic_pointer_cast
<StatementList
>(rules
->stmt
));
1044 void Parser::onTraitName(Token
&out
, Token
*names
, Token
&name
) {
1045 ExpressionPtr expList
;
1047 expList
= names
->exp
;
1049 expList
= NEW_EXP0(ExpressionList
);
1051 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1055 void Parser::onTraitRule(Token
&out
, Token
&stmtList
, Token
&newStmt
) {
1056 if (!stmtList
->stmt
) {
1057 out
->stmt
= NEW_STMT0(StatementList
);
1059 out
->stmt
= stmtList
->stmt
;
1061 assert(newStmt
->stmt
);
1062 out
->stmt
->addElement(newStmt
->stmt
);
1065 void Parser::onTraitPrecRule(Token
&out
, Token
&traitName
, Token
&methodName
,
1066 Token
&otherTraits
) {
1067 assert(otherTraits
->exp
);
1068 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1070 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1071 methodName
->text());
1072 out
->stmt
= NEW_STMT(TraitPrecStatement
, expTraitName
, expMethodName
,
1073 dynamic_pointer_cast
<ExpressionList
>(otherTraits
->exp
));
1076 void Parser::onTraitAliasRuleStart(Token
&out
, Token
&traitName
,
1077 Token
&methodName
) {
1078 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1080 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1081 methodName
->text());
1083 ModifierExpressionPtr expModifiers
= NEW_EXP0(ModifierExpression
);
1085 ScalarExpressionPtr expNewMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1086 methodName
->text());
1088 out
->stmt
= NEW_STMT(TraitAliasStatement
, expTraitName
, expMethodName
,
1089 expModifiers
, expNewMethodName
);
1092 void Parser::onTraitAliasRuleModify(Token
&out
, Token
&rule
,
1093 Token
&accessModifiers
,
1094 Token
&newMethodName
) {
1095 TraitAliasStatementPtr ruleStmt
=
1096 dynamic_pointer_cast
<TraitAliasStatement
>(rule
->stmt
);
1100 if (!newMethodName
->text().empty()) {
1101 ScalarExpressionPtr expNewMethodName
=
1102 NEW_EXP(ScalarExpression
, T_STRING
, newMethodName
->text());
1103 ruleStmt
->setNewMethodName(expNewMethodName
);
1106 if (accessModifiers
->exp
) {
1107 ruleStmt
->setModifiers(dynamic_pointer_cast
<ModifierExpression
>
1108 (accessModifiers
->exp
));
1111 out
->stmt
= ruleStmt
;
1114 void Parser::onClassVariableStart(Token
&out
, Token
*modifiers
, Token
&decl
,
1117 ModifierExpressionPtr exp
= modifiers
->exp
?
1118 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
1119 : NEW_EXP0(ModifierExpression
);
1121 out
->stmt
= NEW_STMT
1122 (ClassVariable
, exp
,
1123 (type
) ? type
->typeAnnotationName() : "",
1124 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1127 NEW_STMT(ClassConstant
,
1128 (type
) ? type
->typeAnnotationName() : "",
1129 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1133 void Parser::onMethod(Token
&out
, Token
&modifiers
, Token
&ret
, Token
&ref
,
1134 Token
&name
, Token
¶ms
, Token
&stmt
,
1135 Token
*attr
, bool reloc
/* = true */) {
1136 ModifierExpressionPtr exp
= modifiers
->exp
?
1137 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
1138 : NEW_EXP0(ModifierExpression
);
1140 StatementListPtr stmts
;
1141 if (!stmt
->stmt
&& stmt
->num() == 1) {
1142 stmts
= NEW_STMT0(StatementList
);
1144 stmts
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1147 ExpressionListPtr old_params
=
1148 dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
1150 // look for argument promotion in ctor and add to function body
1151 string funcName
= name
->text();
1152 if (old_params
&& funcName
== "__construct") {
1153 bool isAbstract
= (exp
) ? exp
->isAbstract() : false;
1154 for (int i
= 0, count
= old_params
->getCount(); i
< count
; i
++) {
1155 ParameterExpressionPtr param
=
1156 dynamic_pointer_cast
<ParameterExpression
>((*old_params
)[i
]);
1157 TokenID mod
= param
->getModifier();
1160 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1161 "parameter modifiers not allowed on "
1162 "abstract __construct");
1165 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1166 "parameter modifiers not allowed on "
1167 "__construct without a body");
1169 if (param
->annotation()) {
1170 std::vector
<std::string
> typeNames
;
1171 param
->annotation()->getAllSimpleNames(typeNames
);
1172 for (auto& typeName
: typeNames
) {
1173 if (isTypeVarInImmediateScope(typeName
)) {
1174 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1175 "parameter modifiers not supported with "
1176 "type variable annotation");
1180 std::string name
= param
->getName();
1181 SimpleVariablePtr value
= NEW_EXP(SimpleVariable
, name
);
1182 ScalarExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
);
1183 SimpleVariablePtr self
= NEW_EXP(SimpleVariable
, "this");
1184 ObjectPropertyExpressionPtr objProp
=
1185 NEW_EXP(ObjectPropertyExpression
, self
, prop
);
1186 AssignmentExpressionPtr assign
=
1187 NEW_EXP(AssignmentExpression
, objProp
, value
, false);
1188 ExpStatementPtr stmt
= NEW_STMT(ExpStatement
, assign
);
1189 stmts
->insertElement(stmt
);
1194 int attribute
= m_file
->popAttribute();
1195 string comment
= popComment();
1196 LocationPtr loc
= popFuncLocation();
1198 FunctionContext funcContext
= m_funcContexts
.back();
1199 m_funcContexts
.pop_back();
1200 m_prependingStatements
.pop_back();
1202 funcContext
.checkFinalAssertions();
1204 bool hasCallToGetArgs
= m_hasCallToGetArgs
.back();
1205 m_hasCallToGetArgs
.pop_back();
1209 MethodStatementPtr mth
;
1211 if (funcName
.empty()) {
1212 funcName
= newClosureName(m_clsName
, m_containingFuncName
);
1215 if (funcContext
.isGenerator
) {
1216 string genName
= newContinuationName(funcName
);
1218 // see traits/2067.php
1219 genName
= newContinuationName(funcName
+ "@" + m_clsName
);
1223 prepare_generator(this, stmt
, new_params
);
1224 ModifierExpressionPtr exp2
= Construct::Clone(exp
);
1225 mth
= NEW_STMT(MethodStatement
, exp2
, ref
->num(), genName
,
1226 dynamic_pointer_cast
<ExpressionList
>(new_params
->exp
),
1227 ret
.typeAnnotationName(),
1228 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
),
1229 attribute
, comment
, ExpressionListPtr());
1232 mth
->getLocation()->line0
= loc
->line0
;
1233 mth
->getLocation()->char0
= loc
->char0
;
1236 completeScope(mth
->onInitialParse(m_ar
, m_file
));
1238 // create_generator() expects us to push the docComment back
1239 // onto the comment stack so that it can make sure that the
1240 // the MethodStatement it's building will get the docComment
1241 pushComment(comment
);
1243 create_generator(this, out
, params
, name
, genName
, m_clsName
.c_str(),
1244 &modifiers
, origGenFunc
,
1245 (!Option::WholeProgram
|| !Option::ParseTimeOpts
),
1247 MethodStatementPtr origStmt
=
1248 boost::dynamic_pointer_cast
<MethodStatement
>(origGenFunc
->stmt
);
1250 mth
->setOrigGeneratorFunc(origStmt
);
1251 origStmt
->setGeneratorFunc(mth
);
1252 origStmt
->setHasCallToGetArgs(hasCallToGetArgs
);
1253 mth
->setHasCallToGetArgs(hasCallToGetArgs
);
1255 ExpressionListPtr attrList
;
1256 if (attr
&& attr
->exp
) {
1257 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1259 mth
= NEW_STMT(MethodStatement
, exp
, ref
->num(), funcName
,
1261 ret
.typeAnnotationName(),
1262 stmts
, attribute
, comment
,
1266 mth
->getLocation()->line0
= loc
->line0
;
1267 mth
->getLocation()->char0
= loc
->char0
;
1269 completeScope(mth
->onInitialParse(m_ar
, m_file
));
1273 void Parser::onMemberModifier(Token
&out
, Token
*modifiers
, Token
&modifier
) {
1274 ModifierExpressionPtr expList
;
1276 expList
= dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
);
1278 expList
= NEW_EXP0(ModifierExpression
);
1280 expList
->add(modifier
->num());
1284 ///////////////////////////////////////////////////////////////////////////////
1287 void Parser::initParseTree() {
1288 m_tree
= NEW_STMT0(StatementList
);
1291 void Parser::finiParseTree() {
1292 if (m_staticVars
.size()) fixStaticVars();
1293 FunctionScopePtr pseudoMain
= m_file
->setTree(m_ar
, m_tree
);
1294 completeScope(pseudoMain
);
1295 pseudoMain
->setOuterScope(m_file
);
1296 m_file
->setOuterScope(m_ar
);
1297 m_ar
->parseExtraCode(m_file
->getName());
1298 LocationPtr loc
= getLocation();
1299 loc
->line0
= loc
->char0
= 1;
1300 pseudoMain
->getStmt()->setLocation(loc
);
1303 void Parser::onHaltCompiler() {
1304 if (m_nsState
== InsideNamespace
&& !m_nsFileScope
) {
1305 error("__HALT_COMPILER() can only be used from the outermost scope");
1308 // Backpatch instances of __COMPILER_HALT_OFFSET__
1309 for(auto &cho
: m_compilerHaltOffsetVec
) {
1310 cho
->setCompilerHaltOffset(m_scanner
.getLocation()->cursor
);
1314 void Parser::onStatementListStart(Token
&out
) {
1318 void Parser::addTopStatement(Token
&new_stmt
) {
1319 addStatement(m_tree
, new_stmt
->stmt
);
1322 void Parser::addStatement(Token
&out
, Token
&stmts
, Token
&new_stmt
) {
1324 out
->stmt
= NEW_STMT0(StatementList
);
1326 out
->stmt
= stmts
->stmt
;
1328 addStatement(out
->stmt
, new_stmt
->stmt
);
1331 void Parser::addStatement(StatementPtr stmt
, StatementPtr new_stmt
) {
1332 assert(!m_prependingStatements
.empty());
1333 vector
<StatementPtr
> &prepending
= m_prependingStatements
.back();
1334 if (!prepending
.empty()) {
1335 assert(prepending
.size() == 1);
1336 for (unsigned i
= 0; i
< prepending
.size(); i
++) {
1337 stmt
->addElement(prepending
[i
]);
1342 stmt
->addElement(new_stmt
);
1346 void Parser::finishStatement(Token
&out
, Token
&stmts
) {
1348 out
->stmt
= NEW_STMT0(StatementList
);
1350 out
->stmt
= stmts
->stmt
;
1354 void Parser::onBlock(Token
&out
, Token
&stmts
) {
1356 stmts
->stmt
= NEW_STMT0(StatementList
);
1357 } else if (!stmts
->stmt
->is(Statement::KindOfStatementList
)) {
1358 out
->stmt
= NEW_STMT0(StatementList
);
1359 out
->stmt
->addElement(stmts
->stmt
);
1360 stmts
->stmt
= out
->stmt
;
1362 out
->stmt
= NEW_STMT(BlockStatement
,
1363 dynamic_pointer_cast
<StatementList
>(stmts
->stmt
));
1366 void Parser::onIf(Token
&out
, Token
&cond
, Token
&stmt
, Token
&elseifs
,
1368 StatementPtr stmtList
;
1369 if (!elseifs
->stmt
) {
1370 stmtList
= NEW_STMT0(StatementList
);
1372 stmtList
= elseifs
->stmt
;
1374 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1375 stmt
->stmt
= NEW_STMT(BlockStatement
,
1376 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1378 stmtList
->insertElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1379 if (elseStmt
->stmt
) {
1380 if (elseStmt
->stmt
->is(Statement::KindOfStatementList
)) {
1381 elseStmt
->stmt
= NEW_STMT
1382 (BlockStatement
, dynamic_pointer_cast
<StatementList
>(elseStmt
->stmt
));
1384 stmtList
->addElement(NEW_STMT(IfBranchStatement
, ExpressionPtr(),
1387 out
->stmt
= NEW_STMT(IfStatement
,
1388 dynamic_pointer_cast
<StatementList
>(stmtList
));
1391 void Parser::onElseIf(Token
&out
, Token
&elseifs
, Token
&cond
, Token
&stmt
) {
1392 if (!elseifs
->stmt
) {
1393 out
->stmt
= NEW_STMT0(StatementList
);
1395 out
->stmt
= elseifs
->stmt
;
1397 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1398 stmt
->stmt
= NEW_STMT(BlockStatement
,
1399 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1401 out
->stmt
->addElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1404 void Parser::onWhile(Token
&out
, Token
&cond
, Token
&stmt
) {
1405 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1406 stmt
->stmt
= NEW_STMT(BlockStatement
,
1407 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1409 out
->stmt
= NEW_STMT(WhileStatement
, cond
->exp
, stmt
->stmt
);
1412 void Parser::onDo(Token
&out
, Token
&stmt
, Token
&cond
) {
1413 out
->stmt
= NEW_STMT(DoStatement
, stmt
->stmt
, cond
->exp
);
1416 void Parser::onFor(Token
&out
, Token
&expr1
, Token
&expr2
, Token
&expr3
,
1418 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1419 stmt
->stmt
= NEW_STMT(BlockStatement
,
1420 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1422 out
->stmt
= NEW_STMT(ForStatement
, expr1
->exp
, expr2
->exp
, expr3
->exp
,
1426 void Parser::onSwitch(Token
&out
, Token
&expr
, Token
&cases
) {
1427 out
->stmt
= NEW_STMT(SwitchStatement
, expr
->exp
,
1428 dynamic_pointer_cast
<StatementList
>(cases
->stmt
));
1431 void Parser::onCase(Token
&out
, Token
&cases
, Token
*cond
, Token
&stmt
) {
1433 out
->stmt
= NEW_STMT0(StatementList
);
1435 out
->stmt
= cases
->stmt
;
1437 out
->stmt
->addElement(NEW_STMT(CaseStatement
,
1438 cond
? cond
->exp
: ExpressionPtr(),
1442 void Parser::onBreak(Token
&out
, Token
*expr
) {
1444 int64_t depth
= strtoll(expr
->text().c_str(), nullptr, 0);
1446 PARSE_ERROR("'break' operator accepts only positive numbers");
1448 out
->stmt
= NEW_STMT(BreakStatement
, static_cast<uint64_t>(depth
));
1450 out
->stmt
= NEW_STMT(BreakStatement
, 1UL);
1454 void Parser::onContinue(Token
&out
, Token
*expr
) {
1456 int64_t depth
= strtoll(expr
->text().c_str(), nullptr, 0);
1458 PARSE_ERROR("'continue' operator accepts only positive numbers");
1460 out
->stmt
= NEW_STMT(ContinueStatement
, static_cast<uint64_t>(depth
));
1462 out
->stmt
= NEW_STMT(ContinueStatement
, 1UL);
1466 void Parser::onReturn(Token
&out
, Token
*expr
) {
1467 out
->stmt
= NEW_STMT(ReturnStatement
, expr
? expr
->exp
: ExpressionPtr());
1468 if (!m_funcContexts
.empty()) {
1469 if (!m_funcContexts
.back().setIsNotGenerator()) {
1470 Compiler::Error(InvalidYield
, out
->stmt
);
1471 PARSE_ERROR("Cannot mix 'return' and 'yield' in the same function");
1476 static void invalidYield(LocationPtr loc
) {
1477 ExpressionPtr
exp(new SimpleFunctionCall(BlockScopePtr(), loc
, "yield",
1479 ExpressionListPtr(),
1481 Compiler::Error(Compiler::InvalidYield
, exp
);
1484 bool Parser::setIsGenerator() {
1485 if (m_funcContexts
.empty()) {
1486 invalidYield(getLocation());
1487 PARSE_ERROR("Yield can only be used inside a function");
1491 if (!m_funcContexts
.back().setIsGenerator()) {
1492 invalidYield(getLocation());
1493 PARSE_ERROR("Cannot mix 'return' and 'yield' in the same function");
1497 if (!m_clsName
.empty()) {
1498 if (strcasecmp(m_funcName
.c_str(), m_clsName
.c_str()) == 0) {
1499 invalidYield(getLocation());
1500 PARSE_ERROR("'yield' is not allowed in potential constructors");
1504 if (m_funcName
[0] == '_' && m_funcName
[1] == '_') {
1505 const char *fname
= m_funcName
.c_str() + 2;
1506 if (!strcasecmp(fname
, "construct") ||
1507 !strcasecmp(fname
, "destruct") ||
1508 !strcasecmp(fname
, "get") ||
1509 !strcasecmp(fname
, "set") ||
1510 !strcasecmp(fname
, "isset") ||
1511 !strcasecmp(fname
, "unset") ||
1512 !strcasecmp(fname
, "call") ||
1513 !strcasecmp(fname
, "callstatic") ||
1514 !strcasecmp(fname
, "invoke")) {
1515 invalidYield(getLocation());
1516 PARSE_ERROR("'yield' is not allowed in constructor, destructor, or "
1526 void Parser::onYield(Token
&out
, Token
&expr
) {
1527 if (!setIsGenerator()) {
1531 out
->exp
= NEW_EXP(YieldExpression
, ExpressionPtr(), expr
->exp
);
1534 void Parser::onYieldPair(Token
&out
, Token
&key
, Token
&val
) {
1535 if (!setIsGenerator()) {
1539 out
->exp
= NEW_EXP(YieldExpression
, key
->exp
, val
->exp
);
1542 void Parser::onYieldBreak(Token
&out
) {
1543 if (!setIsGenerator()) {
1547 out
->stmt
= NEW_STMT(ReturnStatement
, ExpressionPtr());
1550 void Parser::onGlobal(Token
&out
, Token
&expr
) {
1551 out
->stmt
= NEW_STMT(GlobalStatement
,
1552 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1555 void Parser::onGlobalVar(Token
&out
, Token
*exprs
, Token
&expr
) {
1556 ExpressionPtr expList
;
1557 if (exprs
&& exprs
->exp
) {
1558 expList
= exprs
->exp
;
1560 expList
= NEW_EXP0(ExpressionList
);
1562 switch (expr
->num()) {
1564 expList
->addElement(NEW_EXP(SimpleVariable
, expr
->text()));
1567 expList
->addElement(createDynamicVariable(expr
->exp
));
1575 void Parser::onStatic(Token
&out
, Token
&expr
) {
1576 out
->stmt
= NEW_STMT(StaticStatement
,
1577 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1580 void Parser::onEcho(Token
&out
, Token
&expr
, bool html
) {
1582 LocationPtr loc
= getLocation();
1583 if (loc
->line1
== 2 && loc
->char1
== 0 && expr
->text()[0] == '#') {
1584 // skipping linux interpreter declaration
1585 out
->stmt
= NEW_STMT0(StatementList
);
1587 ExpressionPtr exp
= NEW_EXP(ScalarExpression
, T_STRING
, expr
->text(),
1589 ExpressionListPtr expList
= NEW_EXP(ExpressionList
);
1590 expList
->addElement(exp
);
1591 out
->stmt
= NEW_STMT(EchoStatement
, expList
);
1594 out
->stmt
= NEW_STMT(EchoStatement
,
1595 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1599 void Parser::onUnset(Token
&out
, Token
&expr
) {
1600 out
->stmt
= NEW_STMT(UnsetStatement
,
1601 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1602 m_file
->setAttribute(FileScope::ContainsUnset
);
1605 void Parser::onExpStatement(Token
&out
, Token
&expr
) {
1606 ExpStatementPtr
exp(NEW_STMT(ExpStatement
, expr
->exp
));
1608 exp
->onParse(m_ar
, m_file
);
1611 void Parser::onForEach(Token
&out
, Token
&arr
, Token
&name
, Token
&value
,
1613 if (value
->exp
&& name
->num()) {
1614 PARSE_ERROR("Key element cannot be a reference");
1617 checkAssignThis(name
);
1618 checkAssignThis(value
);
1619 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1620 stmt
->stmt
= NEW_STMT(BlockStatement
,
1621 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1623 out
->stmt
= NEW_STMT(ForEachStatement
, arr
->exp
, name
->exp
, name
->num() == 1,
1624 value
->exp
, value
->num() == 1, stmt
->stmt
);
1627 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&className
, Token
&var
,
1628 Token
&catchStmt
, Token
&catches
, Token
&finallyStmt
) {
1629 StatementPtr stmtList
;
1630 if (catches
->stmt
) {
1631 stmtList
= catches
->stmt
;
1633 stmtList
= NEW_STMT0(StatementList
);
1635 stmtList
->insertElement(NEW_STMT(CatchStatement
, className
->text(),
1636 var
->text(), catchStmt
->stmt
));
1637 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1638 dynamic_pointer_cast
<StatementList
>(stmtList
),
1642 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&finallyStmt
) {
1643 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1644 dynamic_pointer_cast
<StatementList
>(NEW_STMT0(StatementList
)),
1648 void Parser::onCatch(Token
&out
, Token
&catches
, Token
&className
, Token
&var
,
1650 StatementPtr stmtList
;
1651 if (catches
->stmt
) {
1652 stmtList
= catches
->stmt
;
1654 stmtList
= NEW_STMT0(StatementList
);
1656 stmtList
->addElement(NEW_STMT(CatchStatement
, className
->text(),
1657 var
->text(), stmt
->stmt
));
1658 out
->stmt
= stmtList
;
1661 void Parser::onFinally(Token
&out
, Token
&stmt
) {
1662 out
->stmt
= NEW_STMT(FinallyStatement
, stmt
->stmt
);
1665 void Parser::onThrow(Token
&out
, Token
&expr
) {
1666 out
->stmt
= NEW_STMT(ThrowStatement
, expr
->exp
);
1669 void Parser::onClosureStart(Token
&name
) {
1670 if (!m_funcName
.empty()) {
1671 m_containingFuncName
= m_funcName
;
1675 onFunctionStart(name
, true);
1678 void Parser::onClosure(Token
&out
, Token
&ret
, Token
&ref
, Token
¶ms
,
1679 Token
&cparams
, Token
&stmts
, bool is_static
) {
1680 Token func
, name
, modifiers
;
1682 ModifierExpressionPtr modifier_exp
= NEW_EXP0(ModifierExpression
);
1683 modifiers
->exp
= modifier_exp
;
1685 modifier_exp
->add(T_STATIC
);
1687 onFunction(func
, &modifiers
, ret
, ref
, name
, params
, stmts
, 0);
1689 ClosureExpressionPtr closure
= NEW_EXP(
1691 dynamic_pointer_cast
<FunctionStatement
>(func
->stmt
),
1692 dynamic_pointer_cast
<ExpressionList
>(cparams
->exp
));
1693 closure
->getClosureFunction()->setContainingClosure(closure
);
1698 void Parser::onClosureParam(Token
&out
, Token
*params
, Token
¶m
,
1700 ExpressionPtr expList
;
1702 expList
= params
->exp
;
1704 expList
= NEW_EXP0(ExpressionList
);
1706 expList
->addElement(NEW_EXP(ParameterExpression
, TypeAnnotationPtr(),
1707 m_scanner
.hipHopSyntaxEnabled(), param
->text(),
1708 ref
, 0, ExpressionPtr(), ExpressionPtr()));
1712 void Parser::onLabel(Token
&out
, Token
&label
) {
1713 out
->stmt
= NEW_STMT(LabelStatement
, label
.text());
1716 void Parser::onGoto(Token
&out
, Token
&label
, bool limited
) {
1717 out
->stmt
= NEW_STMT(GotoStatement
, label
.text());
1720 void Parser::onTypedef(Token
& out
, const Token
& name
, const Token
& type
) {
1721 // Note: we don't always get TypeAnnotations (e.g. for shape types
1723 auto const annot
= type
.typeAnnotation
1724 ? type
.typeAnnotation
1725 : boost::make_shared
<TypeAnnotation
>(type
.text(), TypeAnnotationPtr());
1727 auto td_stmt
= NEW_STMT(TypedefStatement
, name
.text(), annot
);
1728 td_stmt
->onParse(m_ar
, m_file
);
1729 out
->stmt
= td_stmt
;
1732 void Parser::onTypeAnnotation(Token
& out
, const Token
& name
,
1733 const Token
& typeArgs
) {
1734 out
.set(name
.num(), name
.text());
1735 out
.typeAnnotation
= TypeAnnotationPtr(
1736 new TypeAnnotation(name
.text(), typeArgs
.typeAnnotation
));
1737 if (isTypeVar(name
.text())) {
1738 out
.typeAnnotation
->setTypeVar();
1742 void Parser::onTypeList(Token
& type1
, const Token
& type2
) {
1743 if (!type1
.typeAnnotation
) {
1744 PARSE_ERROR("Missing type in type list");
1746 if (type2
.num() != 0 && !type1
.typeAnnotation
) {
1747 PARSE_ERROR("Missing type in type list");
1749 if (type2
.typeAnnotation
) {
1750 type1
.typeAnnotation
->appendToTypeList(type2
.typeAnnotation
);
1754 void Parser::onTypeSpecialization(Token
& type
, char specialization
) {
1755 if (type
.typeAnnotation
) {
1756 switch (specialization
) {
1758 type
.typeAnnotation
->setNullable();
1761 type
.typeAnnotation
->setSoft();
1764 type
.typeAnnotation
->setTuple();
1767 type
.typeAnnotation
->setFunction();
1770 type
.typeAnnotation
->setXHP();
1776 ///////////////////////////////////////////////////////////////////////////////
1777 // namespace support
1779 void Parser::nns(int token
) {
1780 if (m_nsState
== SeenNamespaceStatement
&& token
!= ';') {
1781 error("No code may exist outside of namespace {}: %s",
1782 getMessage().c_str());
1785 if (m_nsState
== SeenNothing
&& token
!= T_DECLARE
) {
1786 m_nsState
= SeenNonNamespaceStatement
;
1790 void Parser::onNamespaceStart(const std::string
&ns
,
1791 bool file_scope
/* =false */) {
1792 if (m_nsState
== SeenNonNamespaceStatement
) {
1793 error("Namespace declaration statement has to be the very first "
1794 "statement in the script: %s", getMessage().c_str());
1797 if (m_nsState
!= SeenNothing
&& file_scope
!= m_nsFileScope
) {
1798 error("Cannot mix bracketed namespace declarations with unbracketed "
1799 "namespace declarations");
1802 m_nsState
= InsideNamespace
;
1803 m_nsFileScope
= file_scope
;
1810 void Parser::onNamespaceEnd() {
1811 m_nsState
= SeenNamespaceStatement
;
1814 void Parser::onUse(const std::string
&ns
, const std::string
&as
) {
1817 size_t pos
= ns
.rfind(NAMESPACE_SEP
);
1818 if (pos
== string::npos
) {
1821 key
= ns
.substr(pos
+ 1);
1824 if (m_aliases
.find(key
) != m_aliases
.end() && m_aliases
[key
] != ns
) {
1825 error("Cannot use %s as %s because the name is already in use: %s",
1826 ns
.c_str(), key
.c_str(), getMessage().c_str());
1829 m_aliases
[key
] = ns
;
1832 std::string
Parser::nsDecl(const std::string
&name
) {
1833 if (m_namespace
.empty()) {
1836 return m_namespace
+ NAMESPACE_SEP
+ name
;
1839 std::string
Parser::resolve(const std::string
&ns
, bool cls
) {
1841 size_t pos
= ns
.find(NAMESPACE_SEP
);
1842 if (pos
!= string::npos
) {
1843 alias
= ns
.substr(0, pos
);
1846 hphp_string_imap
<std::string
>::const_iterator iter
= m_aliases
.find(alias
);
1847 if (iter
!= m_aliases
.end()) {
1848 // Was it a namespace alias?
1849 if (pos
!= string::npos
) {
1850 return iter
->second
+ ns
.substr(pos
);
1852 // Only classes can appear directly in "use" statements
1854 return iter
->second
;
1858 // Classes don't fallback to the global namespace.
1860 if (!strcasecmp("self", ns
.c_str()) ||
1861 !strcasecmp("parent", ns
.c_str())) {
1867 // if qualified name, prepend current namespace
1868 if (pos
!= string::npos
) {
1872 // unqualified name in global namespace
1873 if (m_namespace
.empty()) {
1877 if (!strcasecmp("true", ns
.c_str()) ||
1878 !strcasecmp("false", ns
.c_str()) ||
1879 !strcasecmp("null", ns
.c_str())) {
1885 void Parser::invalidateGoto(TStatementPtr stmt
, GotoError error
) {
1886 GotoStatement
*gs
= (GotoStatement
*) stmt
;
1888 gs
->invalidate(error
);
1891 void Parser::invalidateLabel(TStatementPtr stmt
) {
1892 LabelStatement
*ls
= (LabelStatement
*) stmt
;
1897 TStatementPtr
Parser::extractStatement(ScannerToken
*stmt
) {
1898 Token
*t
= (Token
*) stmt
;
1899 return t
->stmt
.get();
1902 ///////////////////////////////////////////////////////////////////////////////
1904 bool Parser::hasType(Token
&type
) {
1905 if (!type
.text().empty()) {
1906 if (!m_scanner
.hipHopSyntaxEnabled()) {
1907 PARSE_ERROR("Type hint is not enabled");
1915 void Parser::registerAlias(std::string name
) {
1916 size_t pos
= name
.rfind(NAMESPACE_SEP
);
1917 if (pos
!= string::npos
) {
1918 string key
= name
.substr(pos
+ 1);
1919 m_aliases
[key
] = name
;
1923 ///////////////////////////////////////////////////////////////////////////////