2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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"
19 #include "hphp/compiler/type_annotation.h"
20 #include "hphp/parser/hphp.tab.hpp"
21 #include "hphp/compiler/analysis/file_scope.h"
23 #include "hphp/compiler/expression/expression_list.h"
24 #include "hphp/compiler/expression/assignment_expression.h"
25 #include "hphp/compiler/expression/simple_variable.h"
26 #include "hphp/compiler/expression/dynamic_variable.h"
27 #include "hphp/compiler/expression/static_member_expression.h"
28 #include "hphp/compiler/expression/array_element_expression.h"
29 #include "hphp/compiler/expression/dynamic_function_call.h"
30 #include "hphp/compiler/expression/simple_function_call.h"
31 #include "hphp/compiler/expression/scalar_expression.h"
32 #include "hphp/compiler/expression/object_property_expression.h"
33 #include "hphp/compiler/expression/object_method_expression.h"
34 #include "hphp/compiler/expression/list_assignment.h"
35 #include "hphp/compiler/expression/new_object_expression.h"
36 #include "hphp/compiler/expression/include_expression.h"
37 #include "hphp/compiler/expression/unary_op_expression.h"
38 #include "hphp/compiler/expression/binary_op_expression.h"
39 #include "hphp/compiler/expression/qop_expression.h"
40 #include "hphp/compiler/expression/array_pair_expression.h"
41 #include "hphp/compiler/expression/class_constant_expression.h"
42 #include "hphp/compiler/expression/parameter_expression.h"
43 #include "hphp/compiler/expression/modifier_expression.h"
44 #include "hphp/compiler/expression/constant_expression.h"
45 #include "hphp/compiler/expression/encaps_list_expression.h"
46 #include "hphp/compiler/expression/closure_expression.h"
47 #include "hphp/compiler/expression/yield_expression.h"
48 #include "hphp/compiler/expression/await_expression.h"
49 #include "hphp/compiler/expression/user_attribute.h"
50 #include "hphp/compiler/expression/query_expression.h"
51 #include "hphp/compiler/expression/simple_query_clause.h"
52 #include "hphp/compiler/expression/join_clause.h"
53 #include "hphp/compiler/expression/group_clause.h"
54 #include "hphp/compiler/expression/ordering.h"
56 #include "hphp/compiler/statement/function_statement.h"
57 #include "hphp/compiler/statement/class_statement.h"
58 #include "hphp/compiler/statement/interface_statement.h"
59 #include "hphp/compiler/statement/class_variable.h"
60 #include "hphp/compiler/statement/class_constant.h"
61 #include "hphp/compiler/statement/method_statement.h"
62 #include "hphp/compiler/statement/statement_list.h"
63 #include "hphp/compiler/statement/block_statement.h"
64 #include "hphp/compiler/statement/if_branch_statement.h"
65 #include "hphp/compiler/statement/if_statement.h"
66 #include "hphp/compiler/statement/while_statement.h"
67 #include "hphp/compiler/statement/do_statement.h"
68 #include "hphp/compiler/statement/for_statement.h"
69 #include "hphp/compiler/statement/switch_statement.h"
70 #include "hphp/compiler/statement/case_statement.h"
71 #include "hphp/compiler/statement/break_statement.h"
72 #include "hphp/compiler/statement/continue_statement.h"
73 #include "hphp/compiler/statement/return_statement.h"
74 #include "hphp/compiler/statement/global_statement.h"
75 #include "hphp/compiler/statement/static_statement.h"
76 #include "hphp/compiler/statement/echo_statement.h"
77 #include "hphp/compiler/statement/unset_statement.h"
78 #include "hphp/compiler/statement/exp_statement.h"
79 #include "hphp/compiler/statement/foreach_statement.h"
80 #include "hphp/compiler/statement/catch_statement.h"
81 #include "hphp/compiler/statement/try_statement.h"
82 #include "hphp/compiler/statement/finally_statement.h"
83 #include "hphp/compiler/statement/throw_statement.h"
84 #include "hphp/compiler/statement/goto_statement.h"
85 #include "hphp/compiler/statement/label_statement.h"
86 #include "hphp/compiler/statement/use_trait_statement.h"
87 #include "hphp/compiler/statement/class_require_statement.h"
88 #include "hphp/compiler/statement/trait_prec_statement.h"
89 #include "hphp/compiler/statement/trait_alias_statement.h"
90 #include "hphp/compiler/statement/typedef_statement.h"
92 #include "hphp/compiler/analysis/function_scope.h"
94 #include "hphp/compiler/analysis/code_error.h"
95 #include "hphp/compiler/analysis/analysis_result.h"
97 #include "hphp/util/lock.h"
98 #include "hphp/util/logger.h"
99 #include "hphp/util/text-util.h"
100 #include "hphp/util/string-vsnprintf.h"
102 #include "hphp/runtime/base/unit-cache.h"
105 #include "hphp/facebook/src/compiler/fb_compiler_hooks.h"
106 #define RealSimpleFunctionCall FBSimpleFunctionCall
108 #define RealSimpleFunctionCall SimpleFunctionCall
111 #define NEW_EXP0(cls) \
112 cls##Ptr(new cls(BlockScopePtr(), \
114 #define NEW_EXP(cls, e...) \
115 cls##Ptr(new cls(BlockScopePtr(), \
117 #define NEW_STMT0(cls) \
118 cls##Ptr(new cls(BlockScopePtr(), getLabelScope(), \
120 #define NEW_STMT(cls, e...) \
121 cls##Ptr(new cls(BlockScopePtr(), getLabelScope(), \
124 #define PARSE_ERROR(fmt, args...) HPHP_PARSER_ERROR(fmt, this, ##args)
126 using namespace HPHP::Compiler
;
130 SimpleFunctionCallPtr
NewSimpleFunctionCall(
131 EXPRESSION_CONSTRUCTOR_PARAMETERS
,
132 const std::string
&name
, bool hadBackslash
, ExpressionListPtr params
,
134 return SimpleFunctionCallPtr(
135 new RealSimpleFunctionCall(
136 EXPRESSION_CONSTRUCTOR_DERIVED_PARAMETER_VALUES
,
137 name
, hadBackslash
, params
, cls
));
140 static std::string
fully_qualified_name_as_alias_key(const std::string
&fqn
,
141 const std::string
&as
) {
144 size_t pos
= fqn
.rfind(NAMESPACE_SEP
);
145 if (pos
== string::npos
) {
148 key
= fqn
.substr(pos
+ 1);
156 ///////////////////////////////////////////////////////////////////////////////
159 StatementListPtr
Parser::ParseString(const String
& input
, AnalysisResultPtr ar
,
160 const char *fileName
/* = NULL */,
161 bool lambdaMode
/* = false */) {
162 assert(!input
.empty());
163 if (!fileName
|| !*fileName
) fileName
= "string";
165 int len
= input
.size();
166 Scanner
scanner(input
.data(), len
, Option::GetScannerType(), fileName
, true);
167 Parser
parser(scanner
, fileName
, ar
, len
);
168 parser
.m_lambdaMode
= lambdaMode
;
169 if (parser
.parse()) {
170 return parser
.m_file
->getStmt();
172 Logger::Error("Error parsing %s: %s\n%s\n", fileName
,
173 parser
.getMessage().c_str(), input
.data());
174 return StatementListPtr();
177 ///////////////////////////////////////////////////////////////////////////////
179 Parser::Parser(Scanner
&scanner
, const char *fileName
,
180 AnalysisResultPtr ar
, int fileSize
/* = 0 */)
181 : ParserBase(scanner
, fileName
), m_ar(ar
), m_lambdaMode(false),
182 m_closureGenerator(false), m_nsState(SeenNothing
),
183 m_nsAliasTable(getAutoAliasedClasses(), [&] { return isAutoAliasOn(); }) {
184 auto const md5str
= mangleUnitMd5(scanner
.getMd5());
185 MD5 md5
= MD5(md5str
.c_str());
187 m_file
= FileScopePtr(new FileScope(m_fileName
, fileSize
, md5
));
190 m_staticVars
.push_back(StringToExpressionPtrVecMap());
193 Lock
lock(m_ar
->getMutex());
194 m_ar
->addFileScope(m_file
);
197 bool Parser::parse() {
200 throw ParseTimeFatalException(m_fileName
, line1(),
202 errString().c_str());
204 if (scanner().isHHFile()) {
208 } catch (const ParseTimeFatalException
& e
) {
209 m_file
->cleanupForError(m_ar
);
210 if (e
.m_parseFatal
) {
211 m_file
->makeParseFatal(m_ar
, e
.getMessage(), e
.m_line
);
213 m_file
->makeFatal(m_ar
, e
.getMessage(), e
.m_line
);
219 void Parser::error(const char* fmt
, ...) {
223 string_vsnprintf(msg
, fmt
, ap
);
226 fatal(&m_loc
, msg
.c_str());
229 void Parser::parseFatal(const Location
* loc
, const char* msg
) {
230 // we can't use loc->file, as the bison parser doesn't track that in YYLTYPE
231 auto file
= m_file
->getName().c_str();
232 auto exn
= ParseTimeFatalException(file
, loc
->line0
, "%s", msg
);
237 void Parser::fatal(const Location
* loc
, const char* msg
) {
238 throw ParseTimeFatalException(loc
->file
, loc
->line0
, "%s", msg
);
241 string
Parser::errString() {
242 return m_error
.empty() ? getMessage() : m_error
;
245 void Parser::pushComment() {
246 m_comments
.push_back(m_scanner
.detachDocComment());
249 void Parser::pushComment(const std::string
& s
) {
250 m_comments
.push_back(s
);
253 std::string
Parser::popComment() {
254 std::string ret
= m_comments
.back();
255 m_comments
.pop_back();
259 void Parser::newScope() {
260 m_scopes
.push_back(BlockScopePtrVec());
263 void Parser::completeScope(BlockScopePtr inner
) {
264 always_assert(inner
);
265 BlockScopePtrVec
&sv
= m_scopes
.back();
266 for (int i
= 0, n
= sv
.size(); i
< n
; i
++) {
267 BlockScopePtr scope
= sv
[i
];
268 scope
->setOuterScope(inner
);
270 inner
->getStmt()->resetScope(inner
);
272 if (m_scopes
.size()) {
273 m_scopes
.back().push_back(inner
);
277 LabelScopePtr
Parser::getLabelScope() const {
278 assert(!m_labelScopes
.empty());
279 assert(!m_labelScopes
.back().empty());
280 assert(m_labelScopes
.back().back() != nullptr);
281 return m_labelScopes
.back().back();
284 void Parser::onNewLabelScope(bool fresh
) {
286 m_labelScopes
.push_back(LabelScopePtrVec());
288 assert(!m_labelScopes
.empty());
289 LabelScopePtr
labelScope(new LabelScope());
290 m_labelScopes
.back().push_back(labelScope
);
293 void Parser::onScopeLabel(const Token
& stmt
, const Token
& label
) {
294 assert(!m_labelScopes
.empty());
295 assert(!m_labelScopes
.back().empty());
296 for (auto& scope
: m_labelScopes
.back()) {
297 scope
->addLabel(stmt
.stmt
, label
.text());
301 void Parser::onCompleteLabelScope(bool fresh
) {
302 assert(!m_labelScopes
.empty());
303 assert(!m_labelScopes
.back().empty());
304 m_labelScopes
.back().pop_back();
306 m_labelScopes
.pop_back();
310 ///////////////////////////////////////////////////////////////////////////////
313 void Parser::onName(Token
&out
, Token
&name
, NameKind kind
) {
317 onScalar(out
, T_STRING
, name
);
319 case StaticClassExprName
:
327 void Parser::onStaticVariable(Token
&out
, Token
*exprs
, Token
&var
,
329 onVariable(out
, exprs
, var
, value
);
330 if (m_staticVars
.size()) {
331 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
332 m
[var
->text()].push_back(out
->exp
);
336 void Parser::onClassVariable(Token
&out
, Token
*exprs
, Token
&var
,
338 onVariable(out
, exprs
, var
, value
, false, m_scanner
.detachDocComment());
341 void Parser::onClassConstant(Token
&out
, Token
*exprs
, Token
&var
,
343 onVariable(out
, exprs
, var
, &value
, true, m_scanner
.detachDocComment());
346 void Parser::onVariable(Token
&out
, Token
*exprs
, Token
&var
, Token
*value
,
347 bool constant
/* = false */,
348 const std::string
&docComment
/* = "" */) {
349 ExpressionPtr expList
;
351 expList
= exprs
->exp
;
353 expList
= NEW_EXP0(ExpressionList
);
357 exp
= NEW_EXP(ConstantExpression
, var
->text(), false, docComment
);
359 exp
= NEW_EXP(SimpleVariable
, var
->text(), docComment
);
362 exp
= NEW_EXP(AssignmentExpression
, exp
, value
->exp
, false);
364 expList
->addElement(exp
);
368 void Parser::onSimpleVariable(Token
&out
, Token
&var
) {
369 out
->exp
= NEW_EXP(SimpleVariable
, var
->text());
372 void Parser::onDynamicVariable(Token
&out
, Token
&expr
, bool encap
) {
373 out
->exp
= getDynamicVariable(expr
->exp
, encap
);
376 void Parser::onIndirectRef(Token
&out
, Token
&refCount
, Token
&var
) {
378 for (int i
= 0; i
< refCount
->num(); i
++) {
379 out
->exp
= createDynamicVariable(out
->exp
);
383 void Parser::onStaticMember(Token
&out
, Token
&cls
, Token
&name
) {
384 if (name
->exp
->is(Expression::KindOfArrayElementExpression
) &&
385 dynamic_pointer_cast
<ArrayElementExpression
>(name
->exp
)->
386 appendClass(cls
->exp
, m_ar
, m_file
)) {
387 out
->exp
= name
->exp
;
389 StaticMemberExpressionPtr sme
= NEW_EXP(StaticMemberExpression
,
390 cls
->exp
, name
->exp
);
391 sme
->onParse(m_ar
, m_file
);
396 void Parser::onRefDim(Token
&out
, Token
&var
, Token
&offset
) {
398 var
->exp
= NEW_EXP(ConstantExpression
, var
->text(), var
->num() & 2);
401 UnaryOpExpressionPtr uop
;
403 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
404 PARSE_ERROR("Can't use function call result as array base"
405 " in write context");
406 } else if ((uop
= dynamic_pointer_cast
<UnaryOpExpression
>(var
->exp
))
407 && uop
->getOp() == T_ARRAY
) {
408 PARSE_ERROR("Can't use array() as base in write context");
411 out
->exp
= NEW_EXP(ArrayElementExpression
, var
->exp
, offset
->exp
);
414 ExpressionPtr
Parser::getDynamicVariable(ExpressionPtr exp
, bool encap
) {
416 ConstantExpressionPtr var
= dynamic_pointer_cast
<ConstantExpression
>(exp
);
418 return NEW_EXP(SimpleVariable
, var
->getName());
421 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(exp
);
423 return NEW_EXP(SimpleVariable
, var
->getString());
426 return createDynamicVariable(exp
);
429 ExpressionPtr
Parser::createDynamicVariable(ExpressionPtr exp
) {
430 m_file
->setAttribute(FileScope::ContainsDynamicVariable
);
431 return NEW_EXP(DynamicVariable
, exp
);
434 void Parser::onCallParam(Token
&out
, Token
*params
, Token
&expr
,
435 bool ref
, bool unpack
) {
437 out
->exp
= NEW_EXP0(ExpressionList
);
439 out
->exp
= params
->exp
;
442 expr
->exp
->setContext(Expression::RefParameter
);
443 expr
->exp
->setContext(Expression::RefValue
);
446 (dynamic_pointer_cast
<ExpressionList
>(out
->exp
))->setContainsUnpack();
447 expr
->exp
->setContext(Expression::UnpackParameter
);
449 out
->exp
->addElement(expr
->exp
);
452 void Parser::onCall(Token
&out
, bool dynamic
, Token
&name
, Token
¶ms
,
454 ExpressionPtr clsExp
;
459 out
->exp
= NEW_EXP(DynamicFunctionCall
, name
->exp
,
460 dynamic_pointer_cast
<ExpressionList
>(params
->exp
),
463 string funcName
= name
.text();
464 // strip out namespaces for func_get_args and friends check
465 size_t lastBackslash
= funcName
.find_last_of(NAMESPACE_SEP
);
466 string stripped
= lastBackslash
== string::npos
468 : funcName
.substr(lastBackslash
+1);
469 bool hadBackslash
= name
->num() & 2;
471 if (!cls
&& !hadBackslash
) {
472 if (stripped
== "func_num_args" ||
473 stripped
== "func_get_args" ||
474 stripped
== "func_get_arg") {
476 if (m_hasCallToGetArgs
.size() > 0) {
477 m_hasCallToGetArgs
.back() = true;
480 // Auto import a few functions from the HH namespace
481 // TODO(#4245628): merge those into m_fnAliasTable
482 if (isAutoAliasOn() &&
483 (stripped
== "fun" ||
484 stripped
== "meth_caller" ||
485 stripped
== "class_meth" ||
486 stripped
== "inst_meth" ||
487 stripped
== "invariant_callback_register" ||
488 stripped
== "invariant" ||
489 stripped
== "invariant_violation" ||
490 stripped
== "xenon_get_data" ||
491 stripped
== "objprof_get_data" ||
492 stripped
== "server_warmup_status"
494 funcName
= "HH\\" + stripped
;
497 auto alias
= m_fnAliasTable
.find(stripped
);
498 if (alias
!= m_fnAliasTable
.end()) {
499 funcName
= alias
->second
;
503 SimpleFunctionCallPtr call
504 (new RealSimpleFunctionCall
505 (BlockScopePtr(), getLocation(),
506 funcName
, hadBackslash
,
507 dynamic_pointer_cast
<ExpressionList
>(params
->exp
), clsExp
));
508 if (m_scanner
.isHHSyntaxEnabled() && !(name
->num() & 2)) {
509 // If the function name is without any backslashes or
510 // namespace qualification then we treat this as a candidate
511 // for optimization via bytecode promotion.
512 // "idx" is the only function in that class for now but it's
513 // cheaper to set the bit that to check for the function name
514 call
->setOptimizable();
518 call
->onParse(m_ar
, m_file
);
522 ///////////////////////////////////////////////////////////////////////////////
523 // object property and method calls
525 void Parser::onObjectProperty(Token
&out
, Token
&base
, Token
&prop
) {
527 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
529 out
->exp
= NEW_EXP(ObjectPropertyExpression
, base
->exp
, prop
->exp
);
532 void Parser::onObjectMethodCall(Token
&out
, Token
&base
, Token
&prop
,
535 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
537 ExpressionListPtr paramsExp
;
539 paramsExp
= dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
541 paramsExp
= NEW_EXP0(ExpressionList
);
543 out
->exp
= NEW_EXP(ObjectMethodExpression
, base
->exp
, prop
->exp
, paramsExp
);
546 ///////////////////////////////////////////////////////////////////////////////
547 // encapsed expressions
549 void Parser::onEncapsList(Token
&out
, int type
, Token
&list
) {
550 out
->exp
= NEW_EXP(EncapsListExpression
, type
,
551 dynamic_pointer_cast
<ExpressionList
>(list
->exp
));
554 void Parser::addEncap(Token
&out
, Token
*list
, Token
&expr
, int type
) {
555 ExpressionListPtr expList
;
556 if (list
&& list
->exp
) {
557 expList
= dynamic_pointer_cast
<ExpressionList
>(list
->exp
);
559 expList
= NEW_EXP0(ExpressionList
);
565 exp
= NEW_EXP(ScalarExpression
, T_ENCAPSED_AND_WHITESPACE
,
568 expList
->addElement(exp
);
572 void Parser::encapRefDim(Token
&out
, Token
&var
, Token
&offset
) {
574 switch (offset
->num()) {
576 dim
= NEW_EXP(ScalarExpression
, T_STRING
, offset
->text(), true);
579 dim
= NEW_EXP(ScalarExpression
, T_NUM_STRING
, offset
->text());
582 dim
= NEW_EXP(SimpleVariable
, offset
->text());
588 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
589 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, dim
);
592 void Parser::encapObjProp(Token
&out
, Token
&var
, Token
&name
) {
593 ExpressionPtr obj
= NEW_EXP(SimpleVariable
, var
->text());
595 ExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
->text());
596 out
->exp
= NEW_EXP(ObjectPropertyExpression
, obj
, prop
);
599 void Parser::encapArray(Token
&out
, Token
&var
, Token
&expr
) {
600 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
601 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, expr
->exp
);
604 ///////////////////////////////////////////////////////////////////////////////
607 void Parser::onConstantValue(Token
&out
, Token
&constant
) {
608 const auto& alias
= m_cnstAliasTable
.find(constant
.text());
609 if (alias
!= m_cnstAliasTable
.end()) {
610 constant
.setText(alias
->second
);
613 ConstantExpressionPtr con
= NEW_EXP(ConstantExpression
, constant
->text(),
614 constant
->num() & 2);
615 con
->onParse(m_ar
, m_file
);
619 void Parser::onScalar(Token
&out
, int type
, Token
&scalar
) {
620 if (type
== T_FILE
|| type
== T_DIR
) {
621 onUnaryOpExp(out
, scalar
, type
, true);
625 ScalarExpressionPtr exp
;
629 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
630 m_clsName
+ "::" + m_funcName
);
632 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
637 // Inside traits we already did the magic for static::class so lets
639 out
->exp
= NEW_EXP(SimpleFunctionCall
, "get_class", true,
640 ExpressionListPtr(), ExpressionPtr());
649 case T_COMPILER_HALT_OFFSET
:
651 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
654 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
655 m_inTrait
? m_clsName
: "");
658 exp
= NEW_EXP(ScalarExpression
, type
, m_namespace
);
660 case T_CONSTANT_ENCAPSED_STRING
:
661 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(), true);
666 if (type
== T_COMPILER_HALT_OFFSET
) {
667 // Keep track of this expression for later backpatching
668 // If it doesn't get backpatched (because there was no HALT_COMPILER
669 // then the constant will return (int)"__COMPILER_HALT_OFFSET__" (zero)
670 m_compilerHaltOffsetVec
.push_back(exp
);
675 void Parser::onExprListElem(Token
&out
, Token
*exprs
, Token
&expr
) {
676 ExpressionPtr expList
;
677 if (exprs
&& exprs
->exp
) {
678 expList
= exprs
->exp
;
680 expList
= NEW_EXP0(ExpressionList
);
682 expList
->addElement(expr
->exp
);
686 void Parser::onListAssignment(Token
&out
, Token
&vars
, Token
*expr
,
687 bool rhsFirst
/* = false */) {
688 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(vars
->exp
));
689 for (int i
= 0; i
< el
->getCount(); i
++) {
690 if (dynamic_pointer_cast
<FunctionCall
>((*el
)[i
])) {
691 PARSE_ERROR("Can't use return value in write context");
694 out
->exp
= NEW_EXP(ListAssignment
,
695 dynamic_pointer_cast
<ExpressionList
>(vars
->exp
),
696 expr
? expr
->exp
: ExpressionPtr(), rhsFirst
);
699 void Parser::onAListVar(Token
&out
, Token
*list
, Token
*var
) {
700 Token empty_list
, empty_var
;
702 empty_var
.exp
= ExpressionPtr();
706 empty_list
.exp
= NEW_EXP0(ExpressionList
);
709 onExprListElem(out
, list
, *var
);
712 void Parser::onAListSub(Token
&out
, Token
*list
, Token
&sublist
) {
713 onListAssignment(out
, sublist
, nullptr);
714 onExprListElem(out
, list
, out
);
717 void Parser::checkAssignThis(Token
&var
) {
718 if (SimpleVariablePtr simp
= dynamic_pointer_cast
<SimpleVariable
>(var
.exp
)) {
719 if (simp
->getName() == "this") {
720 PARSE_ERROR("Cannot re-assign $this");
725 void Parser::onAssign(Token
&out
, Token
&var
, Token
&expr
, bool ref
,
726 bool rhsFirst
/* = false */) {
727 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
728 PARSE_ERROR("Can't use return value in write context");
730 checkAssignThis(var
);
731 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, expr
->exp
, ref
, rhsFirst
);
734 void Parser::onAssignNew(Token
&out
, Token
&var
, Token
&name
, Token
&args
) {
735 checkAssignThis(var
);
737 NEW_EXP(NewObjectExpression
, name
->exp
,
738 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
739 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, exp
, true);
742 void Parser::onNewObject(Token
&out
, Token
&name
, Token
&args
) {
743 NewObjectExpressionPtr new_obj
=
744 NEW_EXP(NewObjectExpression
, name
->exp
,
745 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
746 new_obj
->onParse(m_ar
, m_file
);
750 void Parser::onUnaryOpExp(Token
&out
, Token
&operand
, int op
, bool front
) {
757 IncludeExpressionPtr exp
= NEW_EXP(IncludeExpression
, operand
->exp
, op
);
759 exp
->onParse(m_ar
, m_file
);
766 if (dynamic_pointer_cast
<FunctionCall
>(operand
->exp
)) {
767 PARSE_ERROR("Can't use return value in write context");
771 UnaryOpExpressionPtr exp
= NEW_EXP(UnaryOpExpression
, operand
->exp
, op
,
774 exp
->onParse(m_ar
, m_file
);
780 void Parser::onBinaryOpExp(Token
&out
, Token
&operand1
, Token
&operand2
,
782 BinaryOpExpressionPtr bop
=
783 NEW_EXP(BinaryOpExpression
, operand1
->exp
, operand2
->exp
, op
);
785 if (bop
->isAssignmentOp() &&
786 dynamic_pointer_cast
<FunctionCall
>(operand1
->exp
)) {
787 PARSE_ERROR("Can't use return value in write context");
792 // If the operands are simple enough we can fold this expression right
793 // here and keep the parse tree smaller.
794 if (ExpressionPtr optExp
= bop
->foldConst(m_ar
)) out
->exp
= optExp
;
797 void Parser::onQOp(Token
&out
, Token
&exprCond
, Token
*expYes
, Token
&expNo
) {
798 out
->exp
= NEW_EXP(QOpExpression
, exprCond
->exp
,
799 expYes
? expYes
->exp
: ExpressionPtr(), expNo
->exp
);
802 void Parser::onArray(Token
&out
, Token
&pairs
, int op
/* = T_ARRAY */) {
803 if (op
!= T_ARRAY
&& !m_scanner
.isHHSyntaxEnabled()) {
804 PARSE_ERROR("Typed collection is not enabled");
806 onUnaryOpExp(out
, pairs
, T_ARRAY
, true);
809 void Parser::onArrayPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
,
811 if (!value
->exp
) return;
813 ExpressionPtr expList
;
814 if (pairs
&& pairs
->exp
) {
815 expList
= pairs
->exp
;
817 expList
= NEW_EXP0(ExpressionList
);
819 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
820 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, ref
));
824 void Parser::onEmptyCollection(Token
&out
) {
825 out
->exp
= NEW_EXP0(ExpressionList
);
829 Parser::onCollectionPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
) {
830 if (!value
->exp
) return;
832 ExpressionPtr expList
;
833 if (pairs
&& pairs
->exp
) {
834 expList
= pairs
->exp
;
836 expList
= NEW_EXP0(ExpressionList
);
838 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
839 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, false,
844 void Parser::onEmptyCheckedArray(Token
&out
) {
845 out
->exp
= NEW_EXP0(ExpressionList
);
849 Parser::onCheckedArrayPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
) {
850 if (!value
->exp
) return;
852 ExpressionPtr expList
;
853 if (pairs
&& pairs
->exp
) {
854 expList
= pairs
->exp
;
856 expList
= NEW_EXP0(ExpressionList
);
858 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
859 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, false));
863 void Parser::onCheckedArray(Token
&out
, Token
&pairs
, int op
) {
864 if (!m_scanner
.isHHSyntaxEnabled()) {
865 PARSE_ERROR("varray, miarray, and msarray are not enabled");
867 onUnaryOpExp(out
, pairs
, op
, true);
870 void Parser::onUserAttribute(Token
&out
, Token
*attrList
, Token
&name
,
872 ExpressionPtr expList
;
873 if (attrList
&& attrList
->exp
) {
874 expList
= attrList
->exp
;
876 expList
= NEW_EXP0(ExpressionList
);
878 expList
->addElement(NEW_EXP(UserAttribute
, name
->text(), value
->exp
));
882 void Parser::onConst(Token
&out
, Token
&name
, Token
&value
) {
883 // Convert to a define call
884 Token sname
; onScalar(sname
, T_CONSTANT_ENCAPSED_STRING
, name
);
886 Token fname
; fname
.setText("define");
887 Token params1
; onCallParam(params1
, nullptr, sname
, false, false);
888 Token params2
; onCallParam(params2
, ¶ms1
, value
, false, false);
889 Token call
; onCall(call
, false, fname
, params2
, nullptr);
890 Token expr
; onExpStatement(expr
, call
);
892 addTopStatement(expr
);
894 m_cnstTable
.insert(name
.text());
897 void Parser::onClassConst(Token
&out
, Token
&cls
, Token
&name
, bool text
) {
899 cls
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, cls
->text());
901 ClassConstantExpressionPtr con
=
902 NEW_EXP(ClassConstantExpression
, cls
->exp
, name
->text());
903 con
->onParse(m_ar
, m_file
);
907 void Parser::onClassClass(Token
&out
, Token
&cls
, Token
&name
,
908 bool inStaticContext
) {
909 if (inStaticContext
) {
910 if (cls
->same("parent") || cls
->same("static")) {
912 "%s::class cannot be used for compile-time class name resolution",
917 if (cls
->exp
&& !cls
->exp
->is(Expression::KindOfScalarExpression
)) {
918 PARSE_ERROR("::class can only be used on scalars");
920 if (cls
->same("self") || cls
->same("parent") || cls
->same("static")) {
921 if (cls
->same("self") && m_inTrait
) {
922 // Sooo... self:: works dynamically for everything in a trait except
923 // for self::CLASS where it returns the trait name. Great...
924 onScalar(out
, T_TRAIT_C
, cls
);
926 onClassConst(out
, cls
, name
, inStaticContext
);
929 onScalar(out
, T_STRING
, cls
);
933 ///////////////////////////////////////////////////////////////////////////////
934 // function/method declaration
936 void Parser::onFunctionStart(Token
&name
, bool doPushComment
/* = true */) {
937 m_file
->pushAttribute();
942 m_funcContexts
.push_back(FunctionContext());
943 m_funcName
= name
.text();
944 m_hasCallToGetArgs
.push_back(false);
945 m_staticVars
.push_back(StringToExpressionPtrVecMap());
948 void Parser::onMethodStart(Token
&name
, Token
&mods
,
949 bool doPushComment
/* = true */) {
950 onFunctionStart(name
, doPushComment
);
953 void Parser::fixStaticVars() {
954 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
955 for (StringToExpressionPtrVecMap::iterator it
= m
.begin(), end
= m
.end();
957 const ExpressionPtrVec
&v
= it
->second
;
960 for (int i
= v
.size(); i
--; ) {
961 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(v
[i
]));
962 for (int j
= el
->getCount(); j
--; ) {
963 ExpressionPtr s
= (*el
)[j
];
964 SimpleVariablePtr v
= dynamic_pointer_cast
<SimpleVariable
>(
965 s
->is(Expression::KindOfAssignmentExpression
) ?
966 static_pointer_cast
<AssignmentExpression
>(s
)->getVariable() : s
);
967 if (v
->getName() == it
->first
) {
971 el
->removeElement(j
);
972 el
->insertElement(last
->clone(), j
);
979 m_staticVars
.pop_back();
982 void Parser::checkFunctionContext(string funcName
,
983 FunctionContext
& funcContext
,
984 ModifierExpressionPtr modifiers
,
986 funcContext
.checkFinalAssertions();
988 // let async modifier be mandatory
989 if (funcContext
.isAsync
&& !modifiers
->isAsync()) {
991 PARSE_ERROR("Function '%s' contains 'await' but is not declared as async.",
995 if (modifiers
->isAsync() && returnsRef
) {
996 PARSE_ERROR("Asynchronous function '%s' cannot return reference.",
1000 if (modifiers
->isAsync() && !canBeAsyncOrGenerator(funcName
, m_clsName
)) {
1001 PARSE_ERROR("cannot declare constructors, destructors, and "
1002 "magic methods such as '%s' as async",
1007 void Parser::prepareConstructorParameters(StatementListPtr stmts
,
1008 ExpressionListPtr params
,
1010 for (int i
= 0, count
= params
->getCount(); i
< count
; i
++) {
1011 ParameterExpressionPtr param
=
1012 dynamic_pointer_cast
<ParameterExpression
>((*params
)[i
]);
1013 TokenID mod
= param
->getModifier();
1014 if (mod
== 0) continue;
1017 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1018 "parameter modifiers not allowed on "
1019 "abstract __construct");
1022 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1023 "parameter modifiers not allowed on "
1024 "__construct without a body");
1026 if (param
->annotation()) {
1027 std::vector
<std::string
> typeNames
;
1028 param
->annotation()->getAllSimpleNames(typeNames
);
1029 for (auto& typeName
: typeNames
) {
1030 if (isTypeVarInImmediateScope(typeName
)) {
1031 param
->parseTimeFatal(Compiler::InvalidAttribute
,
1032 "parameter modifiers not supported with "
1033 "type variable annotation");
1037 std::string name
= param
->getName();
1038 SimpleVariablePtr value
= NEW_EXP(SimpleVariable
, name
);
1039 ScalarExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
);
1040 SimpleVariablePtr self
= NEW_EXP(SimpleVariable
, "this");
1041 ObjectPropertyExpressionPtr objProp
=
1042 NEW_EXP(ObjectPropertyExpression
, self
, prop
);
1043 AssignmentExpressionPtr assign
=
1044 NEW_EXP(AssignmentExpression
, objProp
, value
, false);
1045 ExpStatementPtr stmt
= NEW_STMT(ExpStatement
, assign
);
1046 stmts
->insertElement(stmt
);
1050 string
Parser::getFunctionName(FunctionType type
, Token
* name
) {
1052 case FunctionType::Closure
:
1053 return newClosureName(m_clsName
, m_containingFuncName
);
1054 case FunctionType::Function
:
1056 if (!m_lambdaMode
) {
1057 return name
->text();
1059 return name
->text() + "{lambda}";
1061 case FunctionType::Method
:
1063 return name
->text();
1068 StatementPtr
Parser::onFunctionHelper(FunctionType type
,
1069 Token
*modifiers
, Token
&ret
,
1070 Token
&ref
, Token
*name
, Token
¶ms
,
1071 Token
&stmt
, Token
*attr
, bool reloc
) {
1072 // prepare and validate function modifiers
1073 ModifierExpressionPtr modifiersExp
= modifiers
&& modifiers
->exp
?
1074 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
1075 : NEW_EXP0(ModifierExpression
);
1076 modifiersExp
->setHasPrivacy(type
== FunctionType::Method
);
1077 if (type
== FunctionType::Closure
&& !modifiersExp
->validForClosure()) {
1078 PARSE_ERROR("Invalid modifier on closure function.");
1080 if (type
== FunctionType::Function
) {
1081 if (!modifiersExp
->validForFunction()) {
1082 PARSE_ERROR("Invalid modifier on function %s.", name
->text().c_str());
1085 m_fnTable
.insert(name
->text());
1088 StatementListPtr stmts
= stmt
->stmt
|| stmt
->num() != 1 ?
1089 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
)
1090 : NEW_STMT0(StatementList
);
1092 ExpressionListPtr old_params
=
1093 dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
1095 string funcName
= getFunctionName(type
, name
);
1097 if (type
== FunctionType::Method
&& old_params
&&
1098 funcName
== "__construct") {
1099 prepareConstructorParameters(stmts
, old_params
,
1100 modifiersExp
->isAbstract());
1105 int attribute
= m_file
->popAttribute();
1106 string comment
= popComment();
1108 ExpressionListPtr attrList
;
1109 if (attr
&& attr
->exp
) {
1110 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1113 // create function/method statement
1114 FunctionStatementPtr func
;
1115 MethodStatementPtr mth
;
1116 if (type
== FunctionType::Method
) {
1117 mth
= NEW_STMT(MethodStatement
, modifiersExp
,
1118 ref
->num(), funcName
, old_params
,
1119 ret
.typeAnnotation
, stmts
,
1120 attribute
, comment
, attrList
);
1121 completeScope(mth
->onInitialParse(m_ar
, m_file
));
1123 func
= NEW_STMT(FunctionStatement
, modifiersExp
,
1124 ref
->num(), funcName
, old_params
,
1125 ret
.typeAnnotation
, stmts
,
1126 attribute
, comment
, attrList
);
1128 func
->onParse(m_ar
, m_file
);
1129 completeScope(func
->getFunctionScope());
1130 if (func
->ignored()) {
1131 return NEW_STMT0(StatementList
);
1136 // check and set generator/async flags
1137 FunctionContext funcContext
= m_funcContexts
.back();
1138 checkFunctionContext(funcName
, funcContext
, modifiersExp
, ref
->num());
1139 mth
->getFunctionScope()->setGenerator(funcContext
.isGenerator
);
1140 mth
->getFunctionScope()->setAsync(modifiersExp
->isAsync());
1141 m_funcContexts
.pop_back();
1143 mth
->setHasCallToGetArgs(m_hasCallToGetArgs
.back());
1144 m_hasCallToGetArgs
.pop_back();
1146 LocationPtr loc
= popFuncLocation();
1148 mth
->getLocation()->line0
= loc
->line0
;
1149 mth
->getLocation()->char0
= loc
->char0
;
1155 void Parser::onFunction(Token
&out
, Token
*modifiers
, Token
&ret
, Token
&ref
,
1156 Token
&name
, Token
¶ms
, Token
&stmt
, Token
*attr
) {
1157 out
->stmt
= onFunctionHelper(FunctionType::Function
,
1158 modifiers
, ret
, ref
, &name
, params
, stmt
, attr
, true);
1161 void Parser::onMethod(Token
&out
, Token
&modifiers
, Token
&ret
, Token
&ref
,
1162 Token
&name
, Token
¶ms
, Token
&stmt
,
1163 Token
*attr
, bool reloc
/* = true */) {
1164 out
->stmt
= onFunctionHelper(FunctionType::Method
,
1165 &modifiers
, ret
, ref
, &name
, params
, stmt
, attr
, reloc
);
1168 void Parser::onVariadicParam(Token
&out
, Token
*params
,
1169 Token
&type
, Token
&var
,
1170 bool ref
, Token
*attr
, Token
*modifier
) {
1171 if (!type
.text().empty()) {
1172 PARSE_ERROR("Parameter $%s is variadic and has a type constraint (%s)"
1173 "; variadic params with type constraints are not supported",
1174 var
.text().c_str(), type
.text().c_str());
1177 PARSE_ERROR("Parameter $%s is both variadic and by reference"
1178 "; this is unsupported",
1179 var
.text().c_str());
1182 ExpressionPtr expList
;
1184 expList
= params
->exp
;
1186 expList
= NEW_EXP0(ExpressionList
);
1188 ExpressionListPtr attrList
;
1189 if (attr
&& attr
->exp
) {
1190 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1193 TypeAnnotationPtr typeAnnotation
= type
.typeAnnotation
;
1194 expList
->addElement(NEW_EXP(ParameterExpression
, typeAnnotation
,
1195 m_scanner
.isHHSyntaxEnabled(), var
->text(),
1196 ref
, (modifier
) ? modifier
->num() : 0,
1199 /* variadic */ true));
1203 void Parser::onParam(Token
&out
, Token
*params
, Token
&type
, Token
&var
,
1204 bool ref
, Token
*defValue
, Token
*attr
, Token
*modifier
) {
1205 ExpressionPtr expList
;
1207 expList
= params
->exp
;
1209 expList
= NEW_EXP0(ExpressionList
);
1211 ExpressionListPtr attrList
;
1212 if (attr
&& attr
->exp
) {
1213 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1216 TypeAnnotationPtr typeAnnotation
= type
.typeAnnotation
;
1217 expList
->addElement(NEW_EXP(ParameterExpression
, typeAnnotation
,
1218 m_scanner
.isHHSyntaxEnabled(), var
->text(),
1219 ref
, (modifier
) ? modifier
->num() : 0,
1220 defValue
? defValue
->exp
: ExpressionPtr(),
1225 void Parser::onClassStart(int type
, Token
&name
) {
1226 const Type::TypePtrMap
& typeHintTypes
=
1227 Type::GetTypeHintTypes(m_scanner
.isHHSyntaxEnabled());
1228 if (0 == strcasecmp("self", name
.text().c_str()) ||
1229 0 == strcasecmp("parent", name
.text().c_str()) ||
1230 typeHintTypes
.find(name
.text()) != typeHintTypes
.end()) {
1231 PARSE_ERROR("Cannot use '%s' as class name as it is reserved",
1232 name
.text().c_str());
1237 m_clsName
= name
.text();
1238 m_inTrait
= type
== T_TRAIT
;
1241 void Parser::onClass(Token
&out
, int type
, Token
&name
, Token
&base
,
1242 Token
&baseInterface
, Token
&stmt
, Token
*attr
,
1244 StatementListPtr stmtList
;
1246 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1248 ExpressionListPtr attrList
;
1249 if (attr
&& attr
->exp
) {
1250 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1252 TypeAnnotationPtr enumBaseTy
;
1254 enumBaseTy
= enumBase
->typeAnnotation
;
1257 ClassStatementPtr cls
= NEW_STMT
1258 (ClassStatement
, type
, name
->text(), base
->text(),
1259 dynamic_pointer_cast
<ExpressionList
>(baseInterface
->exp
),
1260 popComment(), stmtList
, attrList
, enumBaseTy
);
1262 // look for argument promotion in ctor
1263 ExpressionListPtr promote
= NEW_EXP(ExpressionList
);
1264 cls
->checkArgumentsToPromote(promote
, type
);
1265 auto count
= promote
->getCount();
1266 cls
->setPromotedParameterCount(count
);
1267 for (int i
= 0; i
< count
; i
++) {
1269 dynamic_pointer_cast
<ParameterExpression
>((*promote
)[i
]);
1270 TokenID mod
= param
->getModifier();
1271 std::string name
= param
->getName();
1272 std::string type
= param
->hasUserType() ?
1273 param
->getUserTypeHint() : "";
1275 // create the class variable and change the location to
1276 // point to the parameter location for error reporting
1277 LocationPtr location
= param
->getLocation();
1278 ModifierExpressionPtr modifier
= NEW_EXP0(ModifierExpression
);
1280 modifier
->setLocation(location
);
1281 SimpleVariablePtr svar
= NEW_EXP(SimpleVariable
, name
);
1282 svar
->setLocation(location
);
1283 ExpressionListPtr expList
= NEW_EXP0(ExpressionList
);
1284 expList
->addElement(svar
);
1285 expList
->setLocation(location
);
1286 ClassVariablePtr var
= NEW_STMT(ClassVariable
, modifier
, type
, expList
);
1287 var
->setLocation(location
);
1288 cls
->getStmts()->addElement(var
);
1293 cls
->onParse(m_ar
, m_file
);
1295 completeScope(cls
->getClassScope());
1296 if (cls
->ignored()) {
1297 out
->stmt
= NEW_STMT0(StatementList
);
1301 registerAlias(name
.text());
1304 void Parser::onEnum(Token
&out
, Token
&name
, Token
&baseTy
,
1305 Token
&stmt
, Token
*attr
) {
1306 Token dummyBase
, dummyInterface
;
1307 dummyBase
.setText("HH\\BuiltinEnum");
1308 onClass(out
, T_ENUM
, name
, dummyBase
, dummyInterface
, stmt
, attr
, &baseTy
);
1311 void Parser::onInterface(Token
&out
, Token
&name
, Token
&base
, Token
&stmt
,
1313 StatementListPtr stmtList
;
1315 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1317 ExpressionListPtr attrList
;
1318 if (attr
&& attr
->exp
) {
1319 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1322 InterfaceStatementPtr intf
= NEW_STMT
1323 (InterfaceStatement
, name
->text(),
1324 dynamic_pointer_cast
<ExpressionList
>(base
->exp
), popComment(), stmtList
,
1328 intf
->onParse(m_ar
, m_file
);
1330 completeScope(intf
->getClassScope());
1333 void Parser::onInterfaceName(Token
&out
, Token
*names
, Token
&name
) {
1334 ExpressionPtr expList
;
1336 expList
= names
->exp
;
1338 expList
= NEW_EXP0(ExpressionList
);
1340 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1344 void Parser::onClassRequire(Token
&out
, Token
&name
, bool isExtends
) {
1345 out
->stmt
= NEW_STMT(ClassRequireStatement
, name
->text(), isExtends
);
1348 void Parser::onTraitUse(Token
&out
, Token
&traits
, Token
&rules
) {
1350 rules
->stmt
= NEW_STMT0(StatementList
);
1352 out
->stmt
= NEW_STMT(UseTraitStatement
,
1353 dynamic_pointer_cast
<ExpressionList
>(traits
->exp
),
1354 dynamic_pointer_cast
<StatementList
>(rules
->stmt
));
1357 void Parser::onTraitName(Token
&out
, Token
*names
, Token
&name
) {
1358 ExpressionPtr expList
;
1360 expList
= names
->exp
;
1362 expList
= NEW_EXP0(ExpressionList
);
1364 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1368 void Parser::onTraitRule(Token
&out
, Token
&stmtList
, Token
&newStmt
) {
1369 if (!stmtList
->stmt
) {
1370 out
->stmt
= NEW_STMT0(StatementList
);
1372 out
->stmt
= stmtList
->stmt
;
1374 assert(newStmt
->stmt
);
1375 out
->stmt
->addElement(newStmt
->stmt
);
1378 void Parser::onTraitPrecRule(Token
&out
, Token
&traitName
, Token
&methodName
,
1379 Token
&otherTraits
) {
1380 assert(otherTraits
->exp
);
1381 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1383 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1384 methodName
->text());
1385 out
->stmt
= NEW_STMT(TraitPrecStatement
, expTraitName
, expMethodName
,
1386 dynamic_pointer_cast
<ExpressionList
>(otherTraits
->exp
));
1389 void Parser::onTraitAliasRuleStart(Token
&out
, Token
&traitName
,
1390 Token
&methodName
) {
1391 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1393 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1394 methodName
->text());
1396 ModifierExpressionPtr expModifiers
= NEW_EXP0(ModifierExpression
);
1398 ScalarExpressionPtr expNewMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1399 methodName
->text());
1401 out
->stmt
= NEW_STMT(TraitAliasStatement
, expTraitName
, expMethodName
,
1402 expModifiers
, expNewMethodName
);
1405 void Parser::onTraitAliasRuleModify(Token
&out
, Token
&rule
,
1406 Token
&accessModifiers
,
1407 Token
&newMethodName
) {
1408 TraitAliasStatementPtr ruleStmt
=
1409 dynamic_pointer_cast
<TraitAliasStatement
>(rule
->stmt
);
1413 if (!newMethodName
->text().empty()) {
1414 ScalarExpressionPtr expNewMethodName
=
1415 NEW_EXP(ScalarExpression
, T_STRING
, newMethodName
->text());
1416 ruleStmt
->setNewMethodName(expNewMethodName
);
1419 if (accessModifiers
->exp
) {
1421 dynamic_pointer_cast
<ModifierExpression
>(accessModifiers
->exp
);
1422 if (!modifiersExp
->validForTraitAliasRule()) {
1423 PARSE_ERROR("Only access and visibility modifiers are allowed"
1424 " in trait alias rule");
1426 ruleStmt
->setModifiers(modifiersExp
);
1429 out
->stmt
= ruleStmt
;
1432 void Parser::onClassVariableStart(Token
&out
, Token
*modifiers
, Token
&decl
,
1435 ModifierExpressionPtr exp
= modifiers
->exp
?
1436 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
1437 : NEW_EXP0(ModifierExpression
);
1439 out
->stmt
= NEW_STMT
1440 (ClassVariable
, exp
,
1441 (type
) ? type
->typeAnnotationName() : "",
1442 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1445 NEW_STMT(ClassConstant
,
1446 (type
) ? type
->typeAnnotationName() : "",
1447 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1451 void Parser::onMemberModifier(Token
&out
, Token
*modifiers
, Token
&modifier
) {
1452 ModifierExpressionPtr expList
;
1454 expList
= dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
);
1456 expList
= NEW_EXP0(ModifierExpression
);
1458 expList
->add(modifier
->num());
1462 ///////////////////////////////////////////////////////////////////////////////
1465 void Parser::initParseTree() {
1466 m_tree
= NEW_STMT0(StatementList
);
1469 void Parser::finiParseTree() {
1470 if (m_staticVars
.size()) fixStaticVars();
1471 FunctionScopePtr pseudoMain
= m_file
->setTree(m_ar
, m_tree
);
1472 completeScope(pseudoMain
);
1473 pseudoMain
->setOuterScope(m_file
);
1474 m_file
->setOuterScope(m_ar
);
1475 m_ar
->parseExtraCode(m_file
->getName());
1476 LocationPtr loc
= getLocation();
1477 loc
->line0
= loc
->char0
= 1;
1478 pseudoMain
->getStmt()->setLocation(loc
);
1481 void Parser::onHaltCompiler() {
1482 if (m_nsState
== InsideNamespace
&& !m_nsFileScope
) {
1483 error("__HALT_COMPILER() can only be used from the outermost scope");
1486 // Backpatch instances of __COMPILER_HALT_OFFSET__
1487 for(auto &cho
: m_compilerHaltOffsetVec
) {
1488 cho
->setCompilerHaltOffset(m_scanner
.getLocation()->cursor
);
1492 void Parser::onStatementListStart(Token
&out
) {
1496 void Parser::addTopStatement(Token
&new_stmt
) {
1497 addStatement(m_tree
, new_stmt
->stmt
);
1500 void Parser::addStatement(Token
&out
, Token
&stmts
, Token
&new_stmt
) {
1502 out
->stmt
= NEW_STMT0(StatementList
);
1504 out
->stmt
= stmts
->stmt
;
1506 addStatement(out
->stmt
, new_stmt
->stmt
);
1509 void Parser::addStatement(StatementPtr stmt
, StatementPtr new_stmt
) {
1511 stmt
->addElement(new_stmt
);
1515 void Parser::finishStatement(Token
&out
, Token
&stmts
) {
1517 out
->stmt
= NEW_STMT0(StatementList
);
1519 out
->stmt
= stmts
->stmt
;
1523 void Parser::onBlock(Token
&out
, Token
&stmts
) {
1525 stmts
->stmt
= NEW_STMT0(StatementList
);
1526 } else if (!stmts
->stmt
->is(Statement::KindOfStatementList
)) {
1527 out
->stmt
= NEW_STMT0(StatementList
);
1528 out
->stmt
->addElement(stmts
->stmt
);
1529 stmts
->stmt
= out
->stmt
;
1531 out
->stmt
= NEW_STMT(BlockStatement
,
1532 dynamic_pointer_cast
<StatementList
>(stmts
->stmt
));
1535 void Parser::onIf(Token
&out
, Token
&cond
, Token
&stmt
, Token
&elseifs
,
1537 StatementPtr stmtList
;
1538 if (!elseifs
->stmt
) {
1539 stmtList
= NEW_STMT0(StatementList
);
1541 stmtList
= elseifs
->stmt
;
1543 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1544 stmt
->stmt
= NEW_STMT(BlockStatement
,
1545 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1547 stmtList
->insertElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1548 if (elseStmt
->stmt
) {
1549 if (elseStmt
->stmt
->is(Statement::KindOfStatementList
)) {
1550 elseStmt
->stmt
= NEW_STMT
1551 (BlockStatement
, dynamic_pointer_cast
<StatementList
>(elseStmt
->stmt
));
1553 stmtList
->addElement(NEW_STMT(IfBranchStatement
, ExpressionPtr(),
1556 out
->stmt
= NEW_STMT(IfStatement
,
1557 dynamic_pointer_cast
<StatementList
>(stmtList
));
1560 void Parser::onElseIf(Token
&out
, Token
&elseifs
, Token
&cond
, Token
&stmt
) {
1561 if (!elseifs
->stmt
) {
1562 out
->stmt
= NEW_STMT0(StatementList
);
1564 out
->stmt
= elseifs
->stmt
;
1566 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1567 stmt
->stmt
= NEW_STMT(BlockStatement
,
1568 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1570 out
->stmt
->addElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1573 void Parser::onWhile(Token
&out
, Token
&cond
, Token
&stmt
) {
1574 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1575 stmt
->stmt
= NEW_STMT(BlockStatement
,
1576 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1578 out
->stmt
= NEW_STMT(WhileStatement
, cond
->exp
, stmt
->stmt
);
1581 void Parser::onDo(Token
&out
, Token
&stmt
, Token
&cond
) {
1582 out
->stmt
= NEW_STMT(DoStatement
, stmt
->stmt
, cond
->exp
);
1585 void Parser::onFor(Token
&out
, Token
&expr1
, Token
&expr2
, Token
&expr3
,
1587 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1588 stmt
->stmt
= NEW_STMT(BlockStatement
,
1589 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1591 out
->stmt
= NEW_STMT(ForStatement
, expr1
->exp
, expr2
->exp
, expr3
->exp
,
1595 void Parser::onSwitch(Token
&out
, Token
&expr
, Token
&cases
) {
1596 out
->stmt
= NEW_STMT(SwitchStatement
, expr
->exp
,
1597 dynamic_pointer_cast
<StatementList
>(cases
->stmt
));
1600 void Parser::onCase(Token
&out
, Token
&cases
, Token
*cond
, Token
&stmt
) {
1602 out
->stmt
= NEW_STMT0(StatementList
);
1604 out
->stmt
= cases
->stmt
;
1606 out
->stmt
->addElement(NEW_STMT(CaseStatement
,
1607 cond
? cond
->exp
: ExpressionPtr(),
1611 void Parser::onBreakContinue(Token
&out
, bool isBreak
, Token
* expr
) {
1616 if (!expr
->exp
->getScalarValue(v
)) {
1617 PARSE_ERROR("'%s' operator with non-constant operand is no longer "
1618 "supported", (isBreak
? "break" : "continue"));
1620 if (!v
.isInteger() || v
.toInt64() <= 0) {
1621 PARSE_ERROR("'%s' operator accepts only positive numbers",
1622 (isBreak
? "break" : "continue"));
1624 depth
= static_cast<uint64_t>(v
.toInt64());
1628 out
->stmt
= NEW_STMT(BreakStatement
, depth
);
1630 out
->stmt
= NEW_STMT(ContinueStatement
, depth
);
1634 void Parser::setHasNonEmptyReturn(ConstructPtr blame
) {
1635 if (m_funcContexts
.empty()) {
1639 FunctionContext
& fc
= m_funcContexts
.back();
1640 if (fc
.isGenerator
) {
1641 Compiler::Error(Compiler::InvalidYield
, blame
);
1642 PARSE_ERROR("Generators cannot return values using \"return\"");
1645 fc
.hasNonEmptyReturn
= true;
1648 void Parser::onReturn(Token
&out
, Token
*expr
) {
1649 out
->stmt
= NEW_STMT(ReturnStatement
, expr
? expr
->exp
: ExpressionPtr());
1651 setHasNonEmptyReturn(out
->stmt
);
1655 void Parser::invalidYield() {
1656 ExpressionPtr
exp(new SimpleFunctionCall(BlockScopePtr(),
1660 ExpressionListPtr(),
1662 Compiler::Error(Compiler::InvalidYield
, exp
);
1665 bool Parser::canBeAsyncOrGenerator(string funcName
, string clsName
) {
1666 if (clsName
.empty()) {
1669 if (strcasecmp(funcName
.c_str(), clsName
.c_str()) == 0) {
1672 if (strncmp(funcName
.c_str(), "__", 2) == 0) {
1673 const char *fname
= funcName
.c_str() + 2;
1674 if (!strcasecmp(fname
, "construct") ||
1675 !strcasecmp(fname
, "destruct") ||
1676 !strcasecmp(fname
, "get") ||
1677 !strcasecmp(fname
, "set") ||
1678 !strcasecmp(fname
, "isset") ||
1679 !strcasecmp(fname
, "unset") ||
1680 !strcasecmp(fname
, "call") ||
1681 !strcasecmp(fname
, "callstatic") ||
1682 !strcasecmp(fname
, "invoke")) {
1689 void Parser::setIsGenerator() {
1690 if (m_funcContexts
.empty()) {
1692 PARSE_ERROR("Yield can only be used inside a function");
1695 FunctionContext
& fc
= m_funcContexts
.back();
1696 if (fc
.hasNonEmptyReturn
) {
1698 PARSE_ERROR("Generators cannot return values using \"return\"");
1700 if (!canBeAsyncOrGenerator(m_funcName
, m_clsName
)) {
1702 PARSE_ERROR("'yield' is not allowed in constructor, destructor, or "
1706 fc
.isGenerator
= true;
1709 void Parser::onYield(Token
&out
, Token
&expr
) {
1711 out
->exp
= NEW_EXP(YieldExpression
, ExpressionPtr(), expr
->exp
);
1714 void Parser::onYieldPair(Token
&out
, Token
&key
, Token
&val
) {
1716 out
->exp
= NEW_EXP(YieldExpression
, key
->exp
, val
->exp
);
1719 void Parser::onYieldBreak(Token
&out
) {
1721 out
->stmt
= NEW_STMT(ReturnStatement
, ExpressionPtr());
1724 void Parser::invalidAwait() {
1725 ExpressionPtr
exp(new SimpleFunctionCall(BlockScopePtr(),
1729 ExpressionListPtr(),
1731 Compiler::Error(Compiler::InvalidAwait
, exp
);
1734 void Parser::setIsAsync() {
1735 if (m_funcContexts
.empty()) {
1737 PARSE_ERROR("'await' can only be used inside a function");
1740 if (!canBeAsyncOrGenerator(m_funcName
, m_clsName
)) {
1742 PARSE_ERROR("'await' is not allowed in constructors, destructors, or "
1746 FunctionContext
& fc
= m_funcContexts
.back();
1751 void Parser::onAwait(Token
&out
, Token
&expr
) {
1753 out
->exp
= NEW_EXP(AwaitExpression
, expr
->exp
);
1756 void Parser::onGlobal(Token
&out
, Token
&expr
) {
1757 out
->stmt
= NEW_STMT(GlobalStatement
,
1758 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1761 void Parser::onGlobalVar(Token
&out
, Token
*exprs
, Token
&expr
) {
1762 ExpressionPtr expList
;
1763 if (exprs
&& exprs
->exp
) {
1764 expList
= exprs
->exp
;
1766 expList
= NEW_EXP0(ExpressionList
);
1768 switch (expr
->num()) {
1770 expList
->addElement(NEW_EXP(SimpleVariable
, expr
->text()));
1773 expList
->addElement(createDynamicVariable(expr
->exp
));
1781 void Parser::onStatic(Token
&out
, Token
&expr
) {
1782 out
->stmt
= NEW_STMT(StaticStatement
,
1783 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1786 void Parser::onEcho(Token
&out
, Token
&expr
, bool html
) {
1788 LocationPtr loc
= getLocation();
1789 if (loc
->line1
== 2 && loc
->char1
== 0 && expr
->text()[0] == '#') {
1790 // skipping linux interpreter declaration
1791 out
->stmt
= NEW_STMT0(StatementList
);
1793 ExpressionPtr exp
= NEW_EXP(ScalarExpression
, T_STRING
, expr
->text(),
1795 ExpressionListPtr expList
= NEW_EXP(ExpressionList
);
1796 expList
->addElement(exp
);
1797 out
->stmt
= NEW_STMT(EchoStatement
, expList
);
1800 out
->stmt
= NEW_STMT(EchoStatement
,
1801 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1805 void Parser::onUnset(Token
&out
, Token
&expr
) {
1806 out
->stmt
= NEW_STMT(UnsetStatement
,
1807 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1808 m_file
->setAttribute(FileScope::ContainsUnset
);
1811 void Parser::onExpStatement(Token
&out
, Token
&expr
) {
1812 ExpStatementPtr
exp(NEW_STMT(ExpStatement
, expr
->exp
));
1814 exp
->onParse(m_ar
, m_file
);
1817 void Parser::onForEach(Token
&out
, Token
&arr
, Token
&name
, Token
&value
,
1818 Token
&stmt
, bool awaitAs
) {
1819 if (dynamic_pointer_cast
<FunctionCall
>(name
->exp
) ||
1820 dynamic_pointer_cast
<FunctionCall
>(value
->exp
)) {
1821 PARSE_ERROR("Can't use return value in write context");
1823 if (value
->exp
&& name
->num()) {
1824 PARSE_ERROR("Key element cannot be a reference");
1827 if (name
->num() || value
->num()) {
1828 PARSE_ERROR("Value element cannot be a reference if await as is used");
1832 checkAssignThis(name
);
1833 checkAssignThis(value
);
1834 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1835 stmt
->stmt
= NEW_STMT(BlockStatement
,
1836 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1838 out
->stmt
= NEW_STMT(ForEachStatement
, arr
->exp
, name
->exp
, name
->num() == 1,
1839 value
->exp
, value
->num() == 1, awaitAs
, stmt
->stmt
);
1842 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&className
, Token
&var
,
1843 Token
&catchStmt
, Token
&catches
, Token
&finallyStmt
) {
1844 StatementPtr stmtList
;
1845 if (catches
->stmt
) {
1846 stmtList
= catches
->stmt
;
1848 stmtList
= NEW_STMT0(StatementList
);
1850 stmtList
->insertElement(NEW_STMT(CatchStatement
, className
->text(),
1851 var
->text(), catchStmt
->stmt
));
1852 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1853 dynamic_pointer_cast
<StatementList
>(stmtList
),
1855 if (tryStmt
->stmt
) {
1856 out
->stmt
->setLabelScope(stmtList
->getLabelScope());
1860 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&finallyStmt
) {
1861 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1862 dynamic_pointer_cast
<StatementList
>(NEW_STMT0(StatementList
)),
1864 if (tryStmt
->stmt
) {
1865 out
->stmt
->setLabelScope(tryStmt
->stmt
->getLabelScope());
1869 void Parser::onCatch(Token
&out
, Token
&catches
, Token
&className
, Token
&var
,
1871 StatementPtr stmtList
;
1872 if (catches
->stmt
) {
1873 stmtList
= catches
->stmt
;
1875 stmtList
= NEW_STMT0(StatementList
);
1877 stmtList
->addElement(NEW_STMT(CatchStatement
, className
->text(),
1878 var
->text(), stmt
->stmt
));
1879 out
->stmt
= stmtList
;
1882 void Parser::onFinally(Token
&out
, Token
&stmt
) {
1883 out
->stmt
= NEW_STMT(FinallyStatement
, stmt
->stmt
);
1884 // TODO (#3271396) This can be greatly improved. In particular
1885 // even when a finally block exists inside a function it is often
1886 // the case that the unnamed locals state & ret are not needed.
1887 // See task description for further details.
1888 m_file
->setAttribute(FileScope::NeedsFinallyLocals
);
1891 void Parser::onThrow(Token
&out
, Token
&expr
) {
1892 out
->stmt
= NEW_STMT(ThrowStatement
, expr
->exp
);
1895 void Parser::onClosureStart(Token
&name
) {
1896 if (!m_funcName
.empty()) {
1897 m_containingFuncName
= m_funcName
;
1901 onFunctionStart(name
, true);
1904 Token
Parser::onClosure(ClosureType type
,
1914 auto stmt
= onFunctionHelper(
1915 FunctionType::Closure
,
1926 ExpressionListPtr vars
= dynamic_pointer_cast
<ExpressionList
>(cparams
->exp
);
1928 for (int i
= vars
->getCount() - 1; i
>= 0; i
--) {
1929 ParameterExpressionPtr
param(
1930 dynamic_pointer_cast
<ParameterExpression
>((*vars
)[i
]));
1931 if (param
->getName() == "this") {
1932 PARSE_ERROR("Cannot use $this as lexical variable");
1937 ClosureExpressionPtr closure
= NEW_EXP(
1940 dynamic_pointer_cast
<FunctionStatement
>(stmt
),
1943 closure
->getClosureFunction()->setContainingClosure(closure
);
1949 Token
Parser::onExprForLambda(const Token
& expr
) {
1950 auto stmt
= NEW_STMT(ReturnStatement
, expr
.exp
);
1952 ret
.stmt
= NEW_STMT0(StatementList
);
1953 ret
.stmt
->addElement(stmt
);
1957 void Parser::onClosureParam(Token
&out
, Token
*params
, Token
¶m
,
1959 ExpressionPtr expList
;
1961 expList
= params
->exp
;
1963 expList
= NEW_EXP0(ExpressionList
);
1965 expList
->addElement(NEW_EXP(ParameterExpression
, TypeAnnotationPtr(),
1966 m_scanner
.isHHSyntaxEnabled(), param
->text(),
1967 ref
, 0, ExpressionPtr(), ExpressionPtr()));
1971 void Parser::onLabel(Token
&out
, Token
&label
) {
1972 out
->stmt
= NEW_STMT(LabelStatement
, label
.text());
1975 void Parser::onGoto(Token
&out
, Token
&label
, bool limited
) {
1976 out
->stmt
= NEW_STMT(GotoStatement
, label
.text());
1979 void Parser::onTypedef(Token
& out
, const Token
& name
, const Token
& type
) {
1980 // Note: we don't always get TypeAnnotations (e.g. for shape types
1982 auto const annot
= type
.typeAnnotation
1983 ? type
.typeAnnotation
1984 : std::make_shared
<TypeAnnotation
>(type
.text(), TypeAnnotationPtr());
1986 auto td_stmt
= NEW_STMT(TypedefStatement
, name
.text(), annot
);
1987 td_stmt
->onParse(m_ar
, m_file
);
1988 out
->stmt
= td_stmt
;
1991 void Parser::onTypeAnnotation(Token
& out
, const Token
& name
,
1992 const Token
& typeArgs
) {
1993 out
.set(name
.num(), name
.text());
1994 out
.typeAnnotation
= TypeAnnotationPtr(
1995 new TypeAnnotation(name
.text(), typeArgs
.typeAnnotation
));
1997 // Namespaced identifiers (num & 1) can never be type variables.
1998 if ((name
.num() & 1) && isTypeVar(name
.text())) {
1999 out
.typeAnnotation
->setTypeVar();
2003 void Parser::onTypeList(Token
& type1
, const Token
& type2
) {
2004 if (!type1
.typeAnnotation
) {
2005 PARSE_ERROR("Missing type in type list");
2007 if (type2
.num() != 0 && !type1
.typeAnnotation
) {
2008 PARSE_ERROR("Missing type in type list");
2010 if (type2
.typeAnnotation
) {
2011 type1
.typeAnnotation
->appendToTypeList(type2
.typeAnnotation
);
2015 void Parser::onTypeSpecialization(Token
& type
, char specialization
) {
2016 if (type
.typeAnnotation
) {
2017 switch (specialization
) {
2019 type
.typeAnnotation
->setNullable();
2022 type
.typeAnnotation
->setSoft();
2025 type
.typeAnnotation
->setTuple();
2028 type
.typeAnnotation
->setFunction();
2031 type
.typeAnnotation
->setXHP();
2037 void Parser::onQuery(Token
&out
, Token
&head
, Token
&body
) {
2038 auto qe
= NEW_EXP(QueryExpression
, head
.exp
, body
.exp
);
2039 qe
->doRewrites(m_ar
, m_file
);
2043 void appendList(ExpressionListPtr expList
, Token
*exps
) {
2044 if (exps
!= nullptr) {
2045 assert(exps
->exp
->is(Expression::KindOfExpressionList
));
2046 ExpressionListPtr
el(static_pointer_cast
<ExpressionList
>(exps
->exp
));
2047 for (unsigned int i
= 0; i
< el
->getCount(); i
++) {
2048 if ((*el
)[i
]) expList
->addElement((*el
)[i
]);
2053 void Parser::onQueryBody(
2054 Token
&out
, Token
*clauses
, Token
&select
, Token
*cont
) {
2055 ExpressionListPtr
expList(NEW_EXP0(ExpressionList
));
2056 appendList(expList
, clauses
);
2057 expList
->addElement(select
.exp
);
2058 if (cont
!= nullptr) expList
->addElement(cont
->exp
);
2062 void Parser::onQueryBodyClause(Token
&out
, Token
*clauses
, Token
&clause
) {
2063 ExpressionPtr expList
;
2064 if (clauses
&& clauses
->exp
) {
2065 expList
= clauses
->exp
;
2067 expList
= NEW_EXP0(ExpressionList
);
2069 expList
->addElement(clause
->exp
);
2073 void Parser::onFromClause(Token
&out
, Token
&var
, Token
&coll
) {
2074 out
->exp
= NEW_EXP(FromClause
, var
.text(), coll
.exp
);
2077 void Parser::onLetClause(Token
&out
, Token
&var
, Token
&expr
) {
2078 out
->exp
= NEW_EXP(LetClause
, var
.text(), expr
.exp
);
2081 void Parser::onWhereClause(Token
&out
, Token
&expr
) {
2082 out
->exp
= NEW_EXP(WhereClause
, expr
.exp
);
2085 void Parser::onJoinClause(Token
&out
, Token
&var
, Token
&coll
,
2086 Token
&left
, Token
&right
) {
2087 out
->exp
= NEW_EXP(JoinClause
, var
.text(), coll
.exp
,
2088 left
.exp
, right
.exp
, "");
2091 void Parser::onJoinIntoClause(Token
&out
, Token
&var
, Token
&coll
,
2092 Token
&left
, Token
&right
, Token
&group
) {
2093 out
->exp
= NEW_EXP(JoinClause
, var
.text(), coll
.exp
,
2094 left
.exp
, right
.exp
, group
.text());
2097 void Parser::onOrderbyClause(Token
&out
, Token
&orderings
) {
2098 out
->exp
= NEW_EXP(OrderbyClause
, orderings
.exp
);
2101 void Parser::onOrdering(Token
&out
, Token
*orderings
, Token
&ordering
) {
2102 ExpressionPtr expList
;
2103 if (orderings
&& orderings
->exp
) {
2104 expList
= orderings
->exp
;
2106 expList
= NEW_EXP0(ExpressionList
);
2108 expList
->addElement(ordering
->exp
);
2112 void Parser::onOrderingExpr(Token
&out
, Token
&expr
, Token
*direction
) {
2113 out
->exp
= NEW_EXP(Ordering
, expr
.exp
, (direction
) ? direction
->text() : "");
2116 void Parser::onSelectClause(Token
&out
, Token
&expr
) {
2117 out
->exp
= NEW_EXP(SelectClause
, expr
.exp
);
2120 void Parser::onGroupClause(Token
&out
, Token
&coll
, Token
&key
) {
2121 out
->exp
= NEW_EXP(GroupClause
, coll
.exp
, key
.exp
);
2124 void Parser::onIntoClause(Token
&out
, Token
&var
, Token
&query
) {
2125 out
->exp
= NEW_EXP(IntoClause
, var
.text(), query
.exp
);
2128 ///////////////////////////////////////////////////////////////////////////////
2129 // namespace support
2131 //////////////////// AliasTable /////////////////////
2133 Parser::AliasTable::AliasTable(const hphp_string_imap
<std::string
>& autoAliases
,
2134 std::function
<bool ()> autoOracle
)
2135 : m_autoAliases(autoAliases
), m_autoOracle(autoOracle
) {
2136 if (!m_autoOracle
) {
2141 void Parser::AliasTable::setFalseOracle() {
2142 m_autoOracle
= [] () { return false; };
2145 std::string
Parser::AliasTable::getName(std::string alias
) {
2146 auto it
= m_aliases
.find(alias
);
2147 if (it
!= m_aliases
.end()) {
2148 return it
->second
.name
;
2150 auto autoIt
= m_autoAliases
.find(alias
);
2151 if (autoIt
!= m_autoAliases
.end()) {
2152 set(alias
, autoIt
->second
, AliasTable::AliasType::USE
);
2153 return autoIt
->second
;
2158 std::string
Parser::AliasTable::getDefName(std::string alias
) {
2159 auto it
= m_aliases
.find(alias
);
2160 if (it
!= m_aliases
.end() && it
->second
.type
== AliasType::DEF
) {
2161 return it
->second
.name
;
2166 std::string
Parser::AliasTable::getUseName(std::string alias
) {
2167 auto it
= m_aliases
.find(alias
);
2168 if (it
!= m_aliases
.end() && it
->second
.type
== AliasType::USE
) {
2169 return it
->second
.name
;
2174 bool Parser::AliasTable::isAliased(std::string alias
) {
2175 if (isUseType(alias
)) {
2178 return m_autoOracle() && m_autoAliases
.find(alias
) != m_autoAliases
.end();
2181 bool Parser::AliasTable::isAutoType(std::string alias
) {
2182 return m_autoOracle() && m_autoAliases
.find(alias
) != m_autoAliases
.end();
2185 bool Parser::AliasTable::isUseType(std::string alias
) {
2186 auto it
= m_aliases
.find(alias
);
2187 return it
!= m_aliases
.end() && it
->second
.type
== AliasType::USE
;
2190 bool Parser::AliasTable::isDefType(std::string alias
) {
2191 auto it
= m_aliases
.find(alias
);
2192 return it
!= m_aliases
.end() && it
->second
.type
== AliasType::DEF
;
2195 void Parser::AliasTable::set(std::string alias
,
2198 m_aliases
[alias
] = (NameEntry
){name
, type
};
2202 * To be called when we enter a fresh namespace.
2204 void Parser::AliasTable::clear() {
2208 //////////////////////////////////////////////////////
2212 * We auto-alias classes only on HH mode.
2214 bool Parser::isAutoAliasOn() {
2215 return m_scanner
.isHHSyntaxEnabled();
2218 hphp_string_imap
<std::string
> Parser::getAutoAliasedClassesHelper() {
2219 hphp_string_imap
<std::string
> autoAliases
;
2220 typedef AliasTable::AliasEntry AliasEntry
;
2221 std::vector
<AliasEntry
> aliases
{
2222 (AliasEntry
){"AsyncIterator", "HH\\AsyncIterator"},
2223 (AliasEntry
){"AsyncKeyedIterator", "HH\\AsyncKeyedIterator"},
2224 (AliasEntry
){"Traversable", "HH\\Traversable"},
2225 (AliasEntry
){"Container", "HH\\Container"},
2226 (AliasEntry
){"KeyedTraversable", "HH\\KeyedTraversable"},
2227 (AliasEntry
){"KeyedContainer", "HH\\KeyedContainer"},
2228 (AliasEntry
){"Iterator", "HH\\Iterator"},
2229 (AliasEntry
){"KeyedIterator", "HH\\KeyedIterator"},
2230 (AliasEntry
){"Iterable", "HH\\Iterable"},
2231 (AliasEntry
){"KeyedIterable", "HH\\KeyedIterable"},
2232 (AliasEntry
){"Collection", "HH\\Collection"},
2233 (AliasEntry
){"Vector", "HH\\Vector"},
2234 (AliasEntry
){"Map", "HH\\Map"},
2235 (AliasEntry
){"StableMap", "HH\\Map"}, // Merging with Map
2236 (AliasEntry
){"Set", "HH\\Set"},
2237 (AliasEntry
){"Pair", "HH\\Pair"},
2238 (AliasEntry
){"ImmVector", "HH\\ImmVector"},
2239 (AliasEntry
){"ImmMap", "HH\\ImmMap"},
2240 (AliasEntry
){"ImmSet", "HH\\ImmSet"},
2241 (AliasEntry
){"InvariantException", "HH\\InvariantException"},
2243 (AliasEntry
){"bool", "HH\\bool"},
2244 (AliasEntry
){"boolean", "HH\\bool"},
2245 (AliasEntry
){"int", "HH\\int"},
2246 (AliasEntry
){"integer", "HH\\int"},
2247 (AliasEntry
){"float", "HH\\float"},
2248 (AliasEntry
){"double", "HH\\float"},
2249 (AliasEntry
){"real", "HH\\float"},
2250 (AliasEntry
){"num", "HH\\num"},
2251 (AliasEntry
){"string", "HH\\string"},
2252 (AliasEntry
){"classname", "HH\\string"}, // for ::class
2253 (AliasEntry
){"resource", "HH\\resource"},
2254 (AliasEntry
){"mixed", "HH\\mixed"},
2255 (AliasEntry
){"void", "HH\\void"},
2256 (AliasEntry
){"this", "HH\\this"},
2258 for (auto entry
: aliases
) {
2259 autoAliases
[entry
.alias
] = entry
.name
;
2264 const hphp_string_imap
<std::string
>& Parser::getAutoAliasedClasses() {
2265 static auto autoAliases
= getAutoAliasedClassesHelper();
2269 void Parser::nns(int token
, const std::string
& text
) {
2270 if (m_nsState
== SeenNamespaceStatement
&& token
!= ';') {
2271 error("No code may exist outside of namespace {}: %s",
2272 getMessage().c_str());
2276 if (m_nsState
== SeenNothing
&& !text
.empty() && token
!= T_DECLARE
&&
2278 m_nsState
= SeenNonNamespaceStatement
;
2282 void Parser::onNamespaceStart(const std::string
&ns
,
2283 bool file_scope
/* =false */) {
2284 if (m_nsState
== SeenNonNamespaceStatement
) {
2285 error("Namespace declaration statement has to be the very first "
2286 "statement in the script: %s", getMessage().c_str());
2289 if (m_nsState
!= SeenNothing
&& file_scope
!= m_nsFileScope
) {
2290 error("Cannot mix bracketed namespace declarations with unbracketed "
2291 "namespace declarations");
2294 m_nsState
= InsideNamespace
;
2295 m_nsFileScope
= file_scope
;
2298 m_nsAliasTable
.clear();
2299 m_fnAliasTable
.clear();
2300 m_cnstAliasTable
.clear();
2303 void Parser::onNamespaceEnd() {
2304 m_nsState
= SeenNamespaceStatement
;
2307 void Parser::onUse(const std::string
&ns
, const std::string
&as
) {
2308 string key
= fully_qualified_name_as_alias_key(ns
, as
);
2310 // It's not an error if the alias already exists but is auto-imported.
2311 // In that case, it gets replaced. It prompts an error if it is not
2312 // auto-imported and 'use' statement is trying to replace it.
2313 if (m_nsAliasTable
.isUseType(key
)) {
2314 error("Cannot use %s as %s because the name is already in use: %s",
2315 ns
.c_str(), key
.c_str(), getMessage().c_str());
2318 if (m_nsAliasTable
.isDefType(key
)) {
2319 auto defName
= m_nsAliasTable
.getDefName(key
);
2320 if (strcasecmp(defName
.c_str(), ns
.c_str())) {
2321 error("Cannot use %s as %s because the name is already in use: %s",
2322 ns
.c_str(), key
.c_str(), getMessage().c_str());
2327 m_nsAliasTable
.set(key
, ns
, AliasTable::AliasType::USE
);
2330 void Parser::onUseFunction(const std::string
&fn
, const std::string
&as
) {
2331 string key
= fully_qualified_name_as_alias_key(fn
, as
);
2333 if (m_fnTable
.count(key
) || m_fnAliasTable
.count(key
)) {
2335 "Cannot use function %s as %s because the name is already in use in %s",
2336 fn
.c_str(), key
.c_str(), getMessage().c_str());
2339 m_fnAliasTable
[key
] = fn
;
2342 void Parser::onUseConst(const std::string
&cnst
, const std::string
&as
) {
2343 string key
= fully_qualified_name_as_alias_key(cnst
, as
);
2345 if (m_cnstTable
.count(key
) || m_cnstAliasTable
.count(key
)) {
2347 "Cannot use const %s as %s because the name is already in use in %s",
2348 cnst
.c_str(), key
.c_str(), getMessage().c_str());
2351 m_cnstAliasTable
[key
] = cnst
;
2354 std::string
Parser::nsDecl(const std::string
&name
) {
2355 if (m_namespace
.empty()) {
2358 return m_namespace
+ NAMESPACE_SEP
+ name
;
2361 std::string
Parser::resolve(const std::string
&ns
, bool cls
) {
2362 size_t pos
= ns
.find(NAMESPACE_SEP
);
2363 string alias
= (pos
!= string::npos
) ? ns
.substr(0, pos
) : ns
;
2365 // Don't expand type variables into the current namespace.
2366 if (isTypeVar(ns
)) {
2370 if (m_nsAliasTable
.isAliased(alias
)) {
2371 auto name
= m_nsAliasTable
.getName(alias
);
2372 // Was it a namespace alias?
2373 if (pos
!= string::npos
) {
2374 return name
+ ns
.substr(pos
);
2376 // Only classes can appear directly in "use" statements
2382 // Classes don't fallback to the global namespace.
2384 if (!strcasecmp("self", ns
.c_str()) ||
2385 !strcasecmp("parent", ns
.c_str())) {
2391 // if qualified name, prepend current namespace
2392 if (pos
!= string::npos
) {
2396 // unqualified name in global namespace
2397 if (m_namespace
.empty()) {
2401 if (!strcasecmp("true", ns
.c_str()) ||
2402 !strcasecmp("false", ns
.c_str()) ||
2403 !strcasecmp("null", ns
.c_str())) {
2409 void Parser::invalidateGoto(TStatementPtr stmt
, GotoError error
) {
2410 GotoStatement
*gs
= (GotoStatement
*) stmt
;
2412 gs
->invalidate(error
);
2415 void Parser::invalidateLabel(TStatementPtr stmt
) {
2416 LabelStatement
*ls
= (LabelStatement
*) stmt
;
2421 TStatementPtr
Parser::extractStatement(ScannerToken
*stmt
) {
2422 Token
*t
= (Token
*) stmt
;
2423 return t
->stmt
.get();
2426 ///////////////////////////////////////////////////////////////////////////////
2428 bool Parser::hasType(Token
&type
) {
2429 if (!type
.text().empty()) {
2430 if (!m_scanner
.isHHSyntaxEnabled()) {
2431 PARSE_ERROR("Type hint is not enabled");
2438 void Parser::registerAlias(std::string name
) {
2439 size_t pos
= name
.rfind(NAMESPACE_SEP
);
2440 if (pos
!= string::npos
) {
2441 string key
= name
.substr(pos
+ 1);
2442 if (m_nsAliasTable
.isUseType(key
)) {
2443 auto useName
= m_nsAliasTable
.getUseName(key
);
2444 if (strcasecmp(useName
.c_str(), name
.c_str())) {
2445 error("Cannot declare class %s because the name is already in use: %s",
2446 name
.c_str(), getMessage().c_str());
2450 m_nsAliasTable
.set(key
, name
, AliasTable::AliasType::DEF
);
2455 ///////////////////////////////////////////////////////////////////////////////