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/trait_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/file-repository.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
));
141 ///////////////////////////////////////////////////////////////////////////////
144 StatementListPtr
Parser::ParseString(const String
& input
, AnalysisResultPtr ar
,
145 const char *fileName
/* = NULL */,
146 bool lambdaMode
/* = false */) {
147 assert(!input
.empty());
148 if (!fileName
|| !*fileName
) fileName
= "string";
150 int len
= input
.size();
151 Scanner
scanner(input
.data(), len
, Option::GetScannerType(), fileName
, true);
152 Parser
parser(scanner
, fileName
, ar
, len
);
153 parser
.m_lambdaMode
= lambdaMode
;
154 if (parser
.parse()) {
155 return parser
.m_file
->getStmt();
157 Logger::Error("Error parsing %s: %s\n%s\n", fileName
,
158 parser
.getMessage().c_str(), input
.data());
159 return StatementListPtr();
162 ///////////////////////////////////////////////////////////////////////////////
164 Parser::Parser(Scanner
&scanner
, const char *fileName
,
165 AnalysisResultPtr ar
, int fileSize
/* = 0 */)
166 : ParserBase(scanner
, fileName
), m_ar(ar
), m_lambdaMode(false),
167 m_closureGenerator(false), m_nsState(SeenNothing
),
168 m_aliasTable(getAutoAliasedClasses(), [&] { return isAutoAliasOn(); }) {
169 string md5str
= Eval::FileRepository::unitMd5(scanner
.getMd5());
170 MD5 md5
= MD5(md5str
.c_str());
172 m_file
= FileScopePtr(new FileScope(m_fileName
, fileSize
, md5
));
175 m_staticVars
.push_back(StringToExpressionPtrVecMap());
178 Lock
lock(m_ar
->getMutex());
179 m_ar
->addFileScope(m_file
);
182 bool Parser::parse() {
185 throw ParseTimeFatalException(m_fileName
, line1(),
187 errString().c_str());
190 } catch (const ParseTimeFatalException
& e
) {
191 m_file
->cleanupForError(m_ar
);
192 if (e
.m_parseFatal
) {
193 m_file
->makeParseFatal(m_ar
, e
.getMessage(), e
.m_line
);
195 m_file
->makeFatal(m_ar
, e
.getMessage(), e
.m_line
);
201 void Parser::error(const char* fmt
, ...) {
205 string_vsnprintf(msg
, fmt
, ap
);
208 fatal(&m_loc
, msg
.c_str());
211 void Parser::parseFatal(const Location
* loc
, const char* msg
) {
212 // we can't use loc->file, as the bison parser doesn't track that in YYLTYPE
213 auto file
= m_file
->getName().c_str();
214 auto exn
= ParseTimeFatalException(file
, loc
->line0
, "%s", msg
);
219 void Parser::fatal(const Location
* loc
, const char* msg
) {
220 throw ParseTimeFatalException(loc
->file
, loc
->line0
, "%s", msg
);
223 string
Parser::errString() {
224 return m_error
.empty() ? getMessage() : m_error
;
227 void Parser::pushComment() {
228 m_comments
.push_back(m_scanner
.detachDocComment());
231 void Parser::pushComment(const std::string
& s
) {
232 m_comments
.push_back(s
);
235 std::string
Parser::popComment() {
236 std::string ret
= m_comments
.back();
237 m_comments
.pop_back();
241 void Parser::newScope() {
242 m_scopes
.push_back(BlockScopePtrVec());
245 void Parser::completeScope(BlockScopePtr inner
) {
246 always_assert(inner
);
247 BlockScopePtrVec
&sv
= m_scopes
.back();
248 for (int i
= 0, n
= sv
.size(); i
< n
; i
++) {
249 BlockScopePtr scope
= sv
[i
];
250 scope
->setOuterScope(inner
);
252 inner
->getStmt()->resetScope(inner
);
254 if (m_scopes
.size()) {
255 m_scopes
.back().push_back(inner
);
259 LabelScopePtr
Parser::getLabelScope() const {
260 assert(!m_labelScopes
.empty());
261 assert(!m_labelScopes
.back().empty());
262 assert(m_labelScopes
.back().back() != nullptr);
263 return m_labelScopes
.back().back();
266 void Parser::onNewLabelScope(bool fresh
) {
268 m_labelScopes
.push_back(LabelScopePtrVec());
270 assert(!m_labelScopes
.empty());
271 LabelScopePtr
labelScope(new LabelScope());
272 m_labelScopes
.back().push_back(labelScope
);
275 void Parser::onScopeLabel(const Token
& stmt
, const Token
& label
) {
276 assert(!m_labelScopes
.empty());
277 assert(!m_labelScopes
.back().empty());
278 for (auto& scope
: m_labelScopes
.back()) {
279 scope
->addLabel(stmt
.stmt
, label
.text());
283 void Parser::onCompleteLabelScope(bool fresh
) {
284 assert(!m_labelScopes
.empty());
285 assert(!m_labelScopes
.back().empty());
286 m_labelScopes
.back().pop_back();
288 m_labelScopes
.pop_back();
292 ///////////////////////////////////////////////////////////////////////////////
295 void Parser::onName(Token
&out
, Token
&name
, NameKind kind
) {
299 onScalar(out
, T_STRING
, name
);
301 case StaticClassExprName
:
309 void Parser::onStaticVariable(Token
&out
, Token
*exprs
, Token
&var
,
311 onVariable(out
, exprs
, var
, value
);
312 if (m_staticVars
.size()) {
313 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
314 m
[var
->text()].push_back(out
->exp
);
318 void Parser::onClassVariable(Token
&out
, Token
*exprs
, Token
&var
,
320 onVariable(out
, exprs
, var
, value
, false, m_scanner
.detachDocComment());
323 void Parser::onClassConstant(Token
&out
, Token
*exprs
, Token
&var
,
325 onVariable(out
, exprs
, var
, &value
, true, m_scanner
.detachDocComment());
328 void Parser::onVariable(Token
&out
, Token
*exprs
, Token
&var
, Token
*value
,
329 bool constant
/* = false */,
330 const std::string
&docComment
/* = "" */) {
331 ExpressionPtr expList
;
333 expList
= exprs
->exp
;
335 expList
= NEW_EXP0(ExpressionList
);
339 exp
= NEW_EXP(ConstantExpression
, var
->text(), false, docComment
);
341 exp
= NEW_EXP(SimpleVariable
, var
->text(), docComment
);
344 exp
= NEW_EXP(AssignmentExpression
, exp
, value
->exp
, false);
346 expList
->addElement(exp
);
350 void Parser::onSimpleVariable(Token
&out
, Token
&var
) {
351 out
->exp
= NEW_EXP(SimpleVariable
, var
->text());
354 void Parser::onDynamicVariable(Token
&out
, Token
&expr
, bool encap
) {
355 out
->exp
= getDynamicVariable(expr
->exp
, encap
);
358 void Parser::onIndirectRef(Token
&out
, Token
&refCount
, Token
&var
) {
360 for (int i
= 0; i
< refCount
->num(); i
++) {
361 out
->exp
= createDynamicVariable(out
->exp
);
365 void Parser::onStaticMember(Token
&out
, Token
&cls
, Token
&name
) {
366 if (name
->exp
->is(Expression::KindOfArrayElementExpression
) &&
367 dynamic_pointer_cast
<ArrayElementExpression
>(name
->exp
)->
368 appendClass(cls
->exp
, m_ar
, m_file
)) {
369 out
->exp
= name
->exp
;
371 StaticMemberExpressionPtr sme
= NEW_EXP(StaticMemberExpression
,
372 cls
->exp
, name
->exp
);
373 sme
->onParse(m_ar
, m_file
);
378 void Parser::onRefDim(Token
&out
, Token
&var
, Token
&offset
) {
380 var
->exp
= NEW_EXP(ConstantExpression
, var
->text(), var
->num() & 2);
383 UnaryOpExpressionPtr uop
;
385 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
386 PARSE_ERROR("Can't use function call result as array base"
387 " in write context");
388 } else if ((uop
= dynamic_pointer_cast
<UnaryOpExpression
>(var
->exp
))
389 && uop
->getOp() == T_ARRAY
) {
390 PARSE_ERROR("Can't use array() as base in write context");
393 out
->exp
= NEW_EXP(ArrayElementExpression
, var
->exp
, offset
->exp
);
396 ExpressionPtr
Parser::getDynamicVariable(ExpressionPtr exp
, bool encap
) {
398 ConstantExpressionPtr var
= dynamic_pointer_cast
<ConstantExpression
>(exp
);
400 return NEW_EXP(SimpleVariable
, var
->getName());
403 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(exp
);
405 return NEW_EXP(SimpleVariable
, var
->getString());
408 return createDynamicVariable(exp
);
411 ExpressionPtr
Parser::createDynamicVariable(ExpressionPtr exp
) {
412 m_file
->setAttribute(FileScope::ContainsDynamicVariable
);
413 return NEW_EXP(DynamicVariable
, exp
);
416 void Parser::onCallParam(Token
&out
, Token
*params
, Token
&expr
, bool ref
) {
418 out
->exp
= NEW_EXP0(ExpressionList
);
420 out
->exp
= params
->exp
;
423 expr
->exp
->setContext(Expression::RefParameter
);
424 expr
->exp
->setContext(Expression::RefValue
);
426 out
->exp
->addElement(expr
->exp
);
429 void Parser::onCall(Token
&out
, bool dynamic
, Token
&name
, Token
¶ms
,
431 ExpressionPtr clsExp
;
436 out
->exp
= NEW_EXP(DynamicFunctionCall
, name
->exp
,
437 dynamic_pointer_cast
<ExpressionList
>(params
->exp
),
440 string funcName
= name
.text();
441 // strip out namespaces for func_get_args and friends check
442 size_t lastBackslash
= funcName
.find_last_of(NAMESPACE_SEP
);
443 const string stripped
= lastBackslash
== string::npos
445 : funcName
.substr(lastBackslash
+1);
446 bool hadBackslash
= name
->num() & 2;
448 if (!cls
&& !hadBackslash
) {
449 if (stripped
== "func_num_args" ||
450 stripped
== "func_get_args" ||
451 stripped
== "func_get_arg") {
453 if (m_hasCallToGetArgs
.size() > 0) {
454 m_hasCallToGetArgs
.back() = true;
457 // Auto import a few functions from the HH namespace
458 if (isAutoAliasOn() &&
459 (stripped
== "fun" ||
460 stripped
== "meth_caller" ||
461 stripped
== "class_meth" ||
462 stripped
== "inst_meth" ||
463 stripped
== "invariant_callback_register" ||
464 stripped
== "invariant" ||
465 stripped
== "invariant_violation" ||
468 funcName
= "HH\\" + stripped
;
472 SimpleFunctionCallPtr call
473 (new RealSimpleFunctionCall
474 (BlockScopePtr(), getLocation(),
475 funcName
, hadBackslash
,
476 dynamic_pointer_cast
<ExpressionList
>(params
->exp
), clsExp
));
477 if (m_scanner
.isHHSyntaxEnabled() && !(name
->num() & 2)) {
478 // If the function name is without any backslashes or
479 // namespace qualification then we treat this as a candidate
480 // for optimization via bytecode promotion.
481 // "idx" is the only function in that class for now but it's
482 // cheaper to set the bit that to check for the function name
483 call
->setOptimizable();
487 call
->onParse(m_ar
, m_file
);
491 ///////////////////////////////////////////////////////////////////////////////
492 // object property and method calls
494 void Parser::onObjectProperty(Token
&out
, Token
&base
, Token
&prop
) {
496 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
498 out
->exp
= NEW_EXP(ObjectPropertyExpression
, base
->exp
, prop
->exp
);
501 void Parser::onObjectMethodCall(Token
&out
, Token
&base
, Token
&prop
,
504 prop
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, prop
->text());
506 ExpressionListPtr paramsExp
;
508 paramsExp
= dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
510 paramsExp
= NEW_EXP0(ExpressionList
);
512 out
->exp
= NEW_EXP(ObjectMethodExpression
, base
->exp
, prop
->exp
, paramsExp
);
515 ///////////////////////////////////////////////////////////////////////////////
516 // encapsed expressions
518 void Parser::onEncapsList(Token
&out
, int type
, Token
&list
) {
519 out
->exp
= NEW_EXP(EncapsListExpression
, type
,
520 dynamic_pointer_cast
<ExpressionList
>(list
->exp
));
523 void Parser::addEncap(Token
&out
, Token
*list
, Token
&expr
, int type
) {
524 ExpressionListPtr expList
;
525 if (list
&& list
->exp
) {
526 expList
= dynamic_pointer_cast
<ExpressionList
>(list
->exp
);
528 expList
= NEW_EXP0(ExpressionList
);
534 exp
= NEW_EXP(ScalarExpression
, T_ENCAPSED_AND_WHITESPACE
,
537 expList
->addElement(exp
);
541 void Parser::encapRefDim(Token
&out
, Token
&var
, Token
&offset
) {
543 switch (offset
->num()) {
545 dim
= NEW_EXP(ScalarExpression
, T_STRING
, offset
->text(), true);
548 dim
= NEW_EXP(ScalarExpression
, T_NUM_STRING
, offset
->text());
551 dim
= NEW_EXP(SimpleVariable
, offset
->text());
557 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
558 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, dim
);
561 void Parser::encapObjProp(Token
&out
, Token
&var
, Token
&name
) {
562 ExpressionPtr obj
= NEW_EXP(SimpleVariable
, var
->text());
564 ExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
->text());
565 out
->exp
= NEW_EXP(ObjectPropertyExpression
, obj
, prop
);
568 void Parser::encapArray(Token
&out
, Token
&var
, Token
&expr
) {
569 ExpressionPtr arr
= NEW_EXP(SimpleVariable
, var
->text());
570 out
->exp
= NEW_EXP(ArrayElementExpression
, arr
, expr
->exp
);
573 ///////////////////////////////////////////////////////////////////////////////
576 void Parser::onConstantValue(Token
&out
, Token
&constant
) {
577 ConstantExpressionPtr con
= NEW_EXP(ConstantExpression
, constant
->text(),
578 constant
->num() & 2);
579 con
->onParse(m_ar
, m_file
);
583 void Parser::onScalar(Token
&out
, int type
, Token
&scalar
) {
584 if (type
== T_FILE
|| type
== T_DIR
) {
585 onUnaryOpExp(out
, scalar
, type
, true);
589 ScalarExpressionPtr exp
;
593 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
594 m_clsName
+ "::" + m_funcName
);
596 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
604 case T_COMPILER_HALT_OFFSET
:
607 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text());
610 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(),
611 m_inTrait
? m_clsName
: "");
614 exp
= NEW_EXP(ScalarExpression
, type
, m_namespace
);
616 case T_CONSTANT_ENCAPSED_STRING
:
617 exp
= NEW_EXP(ScalarExpression
, type
, scalar
->text(), true);
622 if (type
== T_COMPILER_HALT_OFFSET
) {
623 // Keep track of this expression for later backpatching
624 // If it doesn't get backpatched (because there was no HALT_COMPILER
625 // then the constant will return (int)"__COMPILER_HALT_OFFSET__" (zero)
626 m_compilerHaltOffsetVec
.push_back(exp
);
631 void Parser::onExprListElem(Token
&out
, Token
*exprs
, Token
&expr
) {
632 ExpressionPtr expList
;
633 if (exprs
&& exprs
->exp
) {
634 expList
= exprs
->exp
;
636 expList
= NEW_EXP0(ExpressionList
);
638 expList
->addElement(expr
->exp
);
642 void Parser::onListAssignment(Token
&out
, Token
&vars
, Token
*expr
,
643 bool rhsFirst
/* = false */) {
644 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(vars
->exp
));
645 for (int i
= 0; i
< el
->getCount(); i
++) {
646 if (dynamic_pointer_cast
<FunctionCall
>((*el
)[i
])) {
647 PARSE_ERROR("Can't use return value in write context");
650 out
->exp
= NEW_EXP(ListAssignment
,
651 dynamic_pointer_cast
<ExpressionList
>(vars
->exp
),
652 expr
? expr
->exp
: ExpressionPtr(), rhsFirst
);
655 void Parser::onAListVar(Token
&out
, Token
*list
, Token
*var
) {
656 Token empty_list
, empty_var
;
658 empty_var
.exp
= ExpressionPtr();
662 empty_list
.exp
= NEW_EXP0(ExpressionList
);
665 onExprListElem(out
, list
, *var
);
668 void Parser::onAListSub(Token
&out
, Token
*list
, Token
&sublist
) {
669 onListAssignment(out
, sublist
, nullptr);
670 onExprListElem(out
, list
, out
);
673 void Parser::checkAssignThis(Token
&var
) {
674 if (SimpleVariablePtr simp
= dynamic_pointer_cast
<SimpleVariable
>(var
.exp
)) {
675 if (simp
->getName() == "this") {
676 PARSE_ERROR("Cannot re-assign $this");
681 void Parser::onAssign(Token
&out
, Token
&var
, Token
&expr
, bool ref
,
682 bool rhsFirst
/* = false */) {
683 if (dynamic_pointer_cast
<FunctionCall
>(var
->exp
)) {
684 PARSE_ERROR("Can't use return value in write context");
686 checkAssignThis(var
);
687 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, expr
->exp
, ref
, rhsFirst
);
690 void Parser::onAssignNew(Token
&out
, Token
&var
, Token
&name
, Token
&args
) {
691 checkAssignThis(var
);
693 NEW_EXP(NewObjectExpression
, name
->exp
,
694 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
695 out
->exp
= NEW_EXP(AssignmentExpression
, var
->exp
, exp
, true);
698 void Parser::onNewObject(Token
&out
, Token
&name
, Token
&args
) {
699 NewObjectExpressionPtr new_obj
=
700 NEW_EXP(NewObjectExpression
, name
->exp
,
701 dynamic_pointer_cast
<ExpressionList
>(args
->exp
));
702 new_obj
->onParse(m_ar
, m_file
);
706 void Parser::onUnaryOpExp(Token
&out
, Token
&operand
, int op
, bool front
) {
713 IncludeExpressionPtr exp
= NEW_EXP(IncludeExpression
, operand
->exp
, op
);
715 exp
->onParse(m_ar
, m_file
);
722 if (dynamic_pointer_cast
<FunctionCall
>(operand
->exp
)) {
723 PARSE_ERROR("Can't use return value in write context");
727 UnaryOpExpressionPtr exp
= NEW_EXP(UnaryOpExpression
, operand
->exp
, op
,
730 exp
->onParse(m_ar
, m_file
);
736 void Parser::onBinaryOpExp(Token
&out
, Token
&operand1
, Token
&operand2
,
738 BinaryOpExpressionPtr bop
=
739 NEW_EXP(BinaryOpExpression
, operand1
->exp
, operand2
->exp
, op
);
741 if (bop
->isAssignmentOp() &&
742 dynamic_pointer_cast
<FunctionCall
>(operand1
->exp
)) {
743 PARSE_ERROR("Can't use return value in write context");
748 // If the operands are simple enough we can fold this expression right
749 // here and keep the parse tree smaller.
750 if (ExpressionPtr optExp
= bop
->foldConst(m_ar
)) out
->exp
= optExp
;
753 void Parser::onQOp(Token
&out
, Token
&exprCond
, Token
*expYes
, Token
&expNo
) {
754 out
->exp
= NEW_EXP(QOpExpression
, exprCond
->exp
,
755 expYes
? expYes
->exp
: ExpressionPtr(), expNo
->exp
);
758 void Parser::onArray(Token
&out
, Token
&pairs
, int op
/* = T_ARRAY */) {
759 if (op
!= T_ARRAY
&& !m_scanner
.isHHSyntaxEnabled()) {
760 PARSE_ERROR("Typed collection is not enabled");
763 onUnaryOpExp(out
, pairs
, T_ARRAY
, true);
766 void Parser::onArrayPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
,
768 if (!value
->exp
) return;
770 ExpressionPtr expList
;
771 if (pairs
&& pairs
->exp
) {
772 expList
= pairs
->exp
;
774 expList
= NEW_EXP0(ExpressionList
);
776 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
777 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, ref
));
781 void Parser::onEmptyCollection(Token
&out
) {
782 out
->exp
= NEW_EXP0(ExpressionList
);
786 Parser::onCollectionPair(Token
&out
, Token
*pairs
, Token
*name
, Token
&value
) {
787 if (!value
->exp
) return;
789 ExpressionPtr expList
;
790 if (pairs
&& pairs
->exp
) {
791 expList
= pairs
->exp
;
793 expList
= NEW_EXP0(ExpressionList
);
795 ExpressionPtr nameExp
= name
? name
->exp
: ExpressionPtr();
796 expList
->addElement(NEW_EXP(ArrayPairExpression
, nameExp
, value
->exp
, false,
801 void Parser::onUserAttribute(Token
&out
, Token
*attrList
, Token
&name
,
803 ExpressionPtr expList
;
804 if (attrList
&& attrList
->exp
) {
805 expList
= attrList
->exp
;
807 expList
= NEW_EXP0(ExpressionList
);
809 expList
->addElement(NEW_EXP(UserAttribute
, name
->text(), value
->exp
));
813 void Parser::onClassConst(Token
&out
, Token
&cls
, Token
&name
, bool text
) {
815 cls
->exp
= NEW_EXP(ScalarExpression
, T_STRING
, cls
->text());
817 ClassConstantExpressionPtr con
=
818 NEW_EXP(ClassConstantExpression
, cls
->exp
, name
->text());
819 con
->onParse(m_ar
, m_file
);
823 void Parser::onClassClass(Token
&out
, Token
&cls
, Token
&name
,
824 bool inStaticContext
) {
825 if (inStaticContext
) {
826 if (cls
->same("parent") || cls
->same("static")) {
828 "%s::class cannot be used for compile-time class name resolution",
834 if (cls
->exp
&& !cls
->exp
->is(Expression::KindOfScalarExpression
)) {
835 PARSE_ERROR("::class can only be used on scalars");
837 if (cls
->same("self") || cls
->same("parent") || cls
->same("static")) {
838 if (cls
->same("self") && m_inTrait
) {
839 // Sooo... self:: works dynamically for everything in a trait except
840 // for self::CLASS where it returns the trait name. Great...
841 onScalar(out
, T_TRAIT_C
, cls
);
843 onClassConst(out
, cls
, name
, inStaticContext
);
846 onScalar(out
, T_STRING
, cls
);
850 ///////////////////////////////////////////////////////////////////////////////
851 // function/method declaration
853 void Parser::onFunctionStart(Token
&name
, bool doPushComment
/* = true */) {
854 m_file
->pushAttribute();
859 m_funcContexts
.push_back(FunctionContext());
860 m_funcName
= name
.text();
861 m_hasCallToGetArgs
.push_back(false);
862 m_staticVars
.push_back(StringToExpressionPtrVecMap());
865 void Parser::onMethodStart(Token
&name
, Token
&mods
,
866 bool doPushComment
/* = true */) {
867 onFunctionStart(name
, doPushComment
);
870 void Parser::fixStaticVars() {
871 StringToExpressionPtrVecMap
&m
= m_staticVars
.back();
872 for (StringToExpressionPtrVecMap::iterator it
= m
.begin(), end
= m
.end();
874 const ExpressionPtrVec
&v
= it
->second
;
877 for (int i
= v
.size(); i
--; ) {
878 ExpressionListPtr
el(dynamic_pointer_cast
<ExpressionList
>(v
[i
]));
879 for (int j
= el
->getCount(); j
--; ) {
880 ExpressionPtr s
= (*el
)[j
];
881 SimpleVariablePtr v
= dynamic_pointer_cast
<SimpleVariable
>(
882 s
->is(Expression::KindOfAssignmentExpression
) ?
883 static_pointer_cast
<AssignmentExpression
>(s
)->getVariable() : s
);
884 if (v
->getName() == it
->first
) {
888 el
->removeElement(j
);
889 el
->insertElement(last
->clone(), j
);
896 m_staticVars
.pop_back();
899 void Parser::checkFunctionContext(string funcName
,
900 FunctionContext
& funcContext
,
901 ModifierExpressionPtr modifiers
,
903 funcContext
.checkFinalAssertions();
905 // let async modifier be mandatory
906 if (funcContext
.isAsync
&& !modifiers
->isAsync()) {
907 PARSE_ERROR("Function '%s' contains 'await' but is not declared as async.",
911 if (modifiers
->isAsync() && returnsRef
) {
912 PARSE_ERROR("Asynchronous function '%s' cannot return reference.",
916 if (modifiers
->isAsync() && funcContext
.isGenerator
) {
917 PARSE_ERROR("'yield' is not allowed in async functions.");
921 void Parser::prepareConstructorParameters(StatementListPtr stmts
,
922 ExpressionListPtr params
,
924 for (int i
= 0, count
= params
->getCount(); i
< count
; i
++) {
925 ParameterExpressionPtr param
=
926 dynamic_pointer_cast
<ParameterExpression
>((*params
)[i
]);
927 TokenID mod
= param
->getModifier();
928 if (mod
== 0) continue;
931 param
->parseTimeFatal(Compiler::InvalidAttribute
,
932 "parameter modifiers not allowed on "
933 "abstract __construct");
936 param
->parseTimeFatal(Compiler::InvalidAttribute
,
937 "parameter modifiers not allowed on "
938 "__construct without a body");
940 if (param
->annotation()) {
941 std::vector
<std::string
> typeNames
;
942 param
->annotation()->getAllSimpleNames(typeNames
);
943 for (auto& typeName
: typeNames
) {
944 if (isTypeVarInImmediateScope(typeName
)) {
945 param
->parseTimeFatal(Compiler::InvalidAttribute
,
946 "parameter modifiers not supported with "
947 "type variable annotation");
951 std::string name
= param
->getName();
952 SimpleVariablePtr value
= NEW_EXP(SimpleVariable
, name
);
953 ScalarExpressionPtr prop
= NEW_EXP(ScalarExpression
, T_STRING
, name
);
954 SimpleVariablePtr self
= NEW_EXP(SimpleVariable
, "this");
955 ObjectPropertyExpressionPtr objProp
=
956 NEW_EXP(ObjectPropertyExpression
, self
, prop
);
957 AssignmentExpressionPtr assign
=
958 NEW_EXP(AssignmentExpression
, objProp
, value
, false);
959 ExpStatementPtr stmt
= NEW_STMT(ExpStatement
, assign
);
960 stmts
->insertElement(stmt
);
964 string
Parser::getFunctionName(FunctionType type
, Token
* name
) {
966 case FunctionType::Closure
:
967 return newClosureName(m_clsName
, m_containingFuncName
);
968 case FunctionType::Function
:
973 return name
->text() + "{lambda}";
975 case FunctionType::Method
:
982 StatementPtr
Parser::onFunctionHelper(FunctionType type
,
983 Token
*modifiers
, Token
&ret
,
984 Token
&ref
, Token
*name
, Token
¶ms
,
985 Token
&stmt
, Token
*attr
, bool reloc
) {
986 // prepare and validate function modifiers
987 ModifierExpressionPtr modifiersExp
= modifiers
&& modifiers
->exp
?
988 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
989 : NEW_EXP0(ModifierExpression
);
990 modifiersExp
->setHasPrivacy(type
== FunctionType::Method
);
991 if (type
== FunctionType::Closure
&& !modifiersExp
->validForClosure()) {
992 PARSE_ERROR("Invalid modifier on closure funciton.");
994 if (type
== FunctionType::Function
&& !modifiersExp
->validForFunction()) {
995 PARSE_ERROR("Invalid modifier on function %s.", name
->text().c_str());
998 StatementListPtr stmts
= stmt
->stmt
|| stmt
->num() != 1 ?
999 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
)
1000 : NEW_STMT0(StatementList
);
1002 ExpressionListPtr old_params
=
1003 dynamic_pointer_cast
<ExpressionList
>(params
->exp
);
1005 string funcName
= getFunctionName(type
, name
);
1007 if (type
== FunctionType::Method
&& old_params
&&
1008 funcName
== "__construct") {
1009 prepareConstructorParameters(stmts
, old_params
,
1010 modifiersExp
->isAbstract());
1015 int attribute
= m_file
->popAttribute();
1016 string comment
= popComment();
1018 ExpressionListPtr attrList
;
1019 if (attr
&& attr
->exp
) {
1020 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1023 // create function/method statement
1024 FunctionStatementPtr func
;
1025 MethodStatementPtr mth
;
1026 if (type
== FunctionType::Method
) {
1027 mth
= NEW_STMT(MethodStatement
, modifiersExp
,
1028 ref
->num(), funcName
, old_params
,
1029 ret
.typeAnnotation
, stmts
,
1030 attribute
, comment
, attrList
);
1031 completeScope(mth
->onInitialParse(m_ar
, m_file
));
1033 func
= NEW_STMT(FunctionStatement
, modifiersExp
,
1034 ref
->num(), funcName
, old_params
,
1035 ret
.typeAnnotation
, stmts
,
1036 attribute
, comment
, attrList
);
1038 func
->onParse(m_ar
, m_file
);
1039 completeScope(func
->getFunctionScope());
1040 if (func
->ignored()) {
1041 return NEW_STMT0(StatementList
);
1046 // check and set generator/async flags
1047 FunctionContext funcContext
= m_funcContexts
.back();
1048 checkFunctionContext(funcName
, funcContext
, modifiersExp
, ref
->num());
1049 mth
->getFunctionScope()->setGenerator(funcContext
.isGenerator
);
1050 mth
->getFunctionScope()->setAsync(modifiersExp
->isAsync());
1051 m_funcContexts
.pop_back();
1053 mth
->setHasCallToGetArgs(m_hasCallToGetArgs
.back());
1054 m_hasCallToGetArgs
.pop_back();
1056 LocationPtr loc
= popFuncLocation();
1058 mth
->getLocation()->line0
= loc
->line0
;
1059 mth
->getLocation()->char0
= loc
->char0
;
1065 void Parser::onFunction(Token
&out
, Token
*modifiers
, Token
&ret
, Token
&ref
,
1066 Token
&name
, Token
¶ms
, Token
&stmt
, Token
*attr
) {
1067 out
->stmt
= onFunctionHelper(FunctionType::Function
,
1068 modifiers
, ret
, ref
, &name
, params
, stmt
, attr
, true);
1071 void Parser::onMethod(Token
&out
, Token
&modifiers
, Token
&ret
, Token
&ref
,
1072 Token
&name
, Token
¶ms
, Token
&stmt
,
1073 Token
*attr
, bool reloc
/* = true */) {
1074 out
->stmt
= onFunctionHelper(FunctionType::Method
,
1075 &modifiers
, ret
, ref
, &name
, params
, stmt
, attr
, reloc
);
1078 void Parser::onVariadicParam(Token
&out
, Token
*params
,
1079 Token
&type
, Token
&var
,
1080 bool ref
, Token
*attr
, Token
*modifier
) {
1083 void Parser::onParam(Token
&out
, Token
*params
, Token
&type
, Token
&var
,
1084 bool ref
, Token
*defValue
, Token
*attr
, Token
*modifier
) {
1085 ExpressionPtr expList
;
1087 expList
= params
->exp
;
1089 expList
= NEW_EXP0(ExpressionList
);
1091 ExpressionListPtr attrList
;
1092 if (attr
&& attr
->exp
) {
1093 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1096 TypeAnnotationPtr typeAnnotation
= type
.typeAnnotation
;
1097 expList
->addElement(NEW_EXP(ParameterExpression
, typeAnnotation
,
1098 m_scanner
.isHHSyntaxEnabled(), var
->text(),
1099 ref
, (modifier
) ? modifier
->num() : 0,
1100 defValue
? defValue
->exp
: ExpressionPtr(),
1105 void Parser::onClassStart(int type
, Token
&name
) {
1106 const Type::TypePtrMap
& typeHintTypes
=
1107 Type::GetTypeHintTypes(m_scanner
.isHHSyntaxEnabled());
1108 if (0 == strcasecmp("self", name
.text().c_str()) ||
1109 0 == strcasecmp("parent", name
.text().c_str()) ||
1110 typeHintTypes
.find(name
.text()) != typeHintTypes
.end()) {
1111 PARSE_ERROR("Cannot use '%s' as class name as it is reserved",
1112 name
.text().c_str());
1117 m_clsName
= name
.text();
1118 m_inTrait
= type
== T_TRAIT
;
1121 void Parser::onClass(Token
&out
, int type
, Token
&name
, Token
&base
,
1122 Token
&baseInterface
, Token
&stmt
, Token
*attr
) {
1123 StatementListPtr stmtList
;
1125 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1127 ExpressionListPtr attrList
;
1128 if (attr
&& attr
->exp
) {
1129 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1132 ClassStatementPtr cls
= NEW_STMT
1133 (ClassStatement
, type
, name
->text(), base
->text(),
1134 dynamic_pointer_cast
<ExpressionList
>(baseInterface
->exp
),
1135 popComment(), stmtList
, attrList
);
1137 // look for argument promotion in ctor
1138 ExpressionListPtr promote
= NEW_EXP(ExpressionList
);
1139 cls
->checkArgumentsToPromote(promote
, type
);
1140 auto count
= promote
->getCount();
1141 cls
->setPromotedParameterCount(count
);
1142 for (int i
= 0; i
< count
; i
++) {
1144 dynamic_pointer_cast
<ParameterExpression
>((*promote
)[i
]);
1145 TokenID mod
= param
->getModifier();
1146 std::string name
= param
->getName();
1147 std::string type
= param
->hasUserType() ?
1148 param
->getUserTypeHint() : "";
1150 // create the class variable and change the location to
1151 // point to the parameter location for error reporting
1152 LocationPtr location
= param
->getLocation();
1153 ModifierExpressionPtr modifier
= NEW_EXP0(ModifierExpression
);
1155 modifier
->setLocation(location
);
1156 SimpleVariablePtr svar
= NEW_EXP(SimpleVariable
, name
);
1157 svar
->setLocation(location
);
1158 ExpressionListPtr expList
= NEW_EXP0(ExpressionList
);
1159 expList
->addElement(svar
);
1160 expList
->setLocation(location
);
1161 ClassVariablePtr var
= NEW_STMT(ClassVariable
, modifier
, type
, expList
);
1162 var
->setLocation(location
);
1163 cls
->getStmts()->addElement(var
);
1168 cls
->onParse(m_ar
, m_file
);
1170 completeScope(cls
->getClassScope());
1171 if (cls
->ignored()) {
1172 out
->stmt
= NEW_STMT0(StatementList
);
1176 registerAlias(name
.text());
1179 void Parser::onInterface(Token
&out
, Token
&name
, Token
&base
, Token
&stmt
,
1181 StatementListPtr stmtList
;
1183 stmtList
= dynamic_pointer_cast
<StatementList
>(stmt
->stmt
);
1185 ExpressionListPtr attrList
;
1186 if (attr
&& attr
->exp
) {
1187 attrList
= dynamic_pointer_cast
<ExpressionList
>(attr
->exp
);
1190 InterfaceStatementPtr intf
= NEW_STMT
1191 (InterfaceStatement
, name
->text(),
1192 dynamic_pointer_cast
<ExpressionList
>(base
->exp
), popComment(), stmtList
,
1196 intf
->onParse(m_ar
, m_file
);
1198 completeScope(intf
->getClassScope());
1201 void Parser::onInterfaceName(Token
&out
, Token
*names
, Token
&name
) {
1202 ExpressionPtr expList
;
1204 expList
= names
->exp
;
1206 expList
= NEW_EXP0(ExpressionList
);
1208 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1212 void Parser::onTraitRequire(Token
&out
, Token
&name
, bool isExtends
) {
1213 out
->stmt
= NEW_STMT(TraitRequireStatement
, name
->text(), isExtends
);
1216 void Parser::onTraitUse(Token
&out
, Token
&traits
, Token
&rules
) {
1218 rules
->stmt
= NEW_STMT0(StatementList
);
1220 out
->stmt
= NEW_STMT(UseTraitStatement
,
1221 dynamic_pointer_cast
<ExpressionList
>(traits
->exp
),
1222 dynamic_pointer_cast
<StatementList
>(rules
->stmt
));
1225 void Parser::onTraitName(Token
&out
, Token
*names
, Token
&name
) {
1226 ExpressionPtr expList
;
1228 expList
= names
->exp
;
1230 expList
= NEW_EXP0(ExpressionList
);
1232 expList
->addElement(NEW_EXP(ScalarExpression
, T_STRING
, name
->text()));
1236 void Parser::onTraitRule(Token
&out
, Token
&stmtList
, Token
&newStmt
) {
1237 if (!stmtList
->stmt
) {
1238 out
->stmt
= NEW_STMT0(StatementList
);
1240 out
->stmt
= stmtList
->stmt
;
1242 assert(newStmt
->stmt
);
1243 out
->stmt
->addElement(newStmt
->stmt
);
1246 void Parser::onTraitPrecRule(Token
&out
, Token
&traitName
, Token
&methodName
,
1247 Token
&otherTraits
) {
1248 assert(otherTraits
->exp
);
1249 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1251 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1252 methodName
->text());
1253 out
->stmt
= NEW_STMT(TraitPrecStatement
, expTraitName
, expMethodName
,
1254 dynamic_pointer_cast
<ExpressionList
>(otherTraits
->exp
));
1257 void Parser::onTraitAliasRuleStart(Token
&out
, Token
&traitName
,
1258 Token
&methodName
) {
1259 ScalarExpressionPtr expTraitName
= NEW_EXP(ScalarExpression
, T_STRING
,
1261 ScalarExpressionPtr expMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1262 methodName
->text());
1264 ModifierExpressionPtr expModifiers
= NEW_EXP0(ModifierExpression
);
1266 ScalarExpressionPtr expNewMethodName
= NEW_EXP(ScalarExpression
, T_STRING
,
1267 methodName
->text());
1269 out
->stmt
= NEW_STMT(TraitAliasStatement
, expTraitName
, expMethodName
,
1270 expModifiers
, expNewMethodName
);
1273 void Parser::onTraitAliasRuleModify(Token
&out
, Token
&rule
,
1274 Token
&accessModifiers
,
1275 Token
&newMethodName
) {
1276 TraitAliasStatementPtr ruleStmt
=
1277 dynamic_pointer_cast
<TraitAliasStatement
>(rule
->stmt
);
1281 if (!newMethodName
->text().empty()) {
1282 ScalarExpressionPtr expNewMethodName
=
1283 NEW_EXP(ScalarExpression
, T_STRING
, newMethodName
->text());
1284 ruleStmt
->setNewMethodName(expNewMethodName
);
1287 if (accessModifiers
->exp
) {
1289 dynamic_pointer_cast
<ModifierExpression
>(accessModifiers
->exp
);
1290 if (!modifiersExp
->validForTraitAliasRule()) {
1291 PARSE_ERROR("Only access and visibility modifiers are allowed"
1292 " in trait alias rule");
1294 ruleStmt
->setModifiers(modifiersExp
);
1297 out
->stmt
= ruleStmt
;
1300 void Parser::onClassVariableStart(Token
&out
, Token
*modifiers
, Token
&decl
,
1303 ModifierExpressionPtr exp
= modifiers
->exp
?
1304 dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
)
1305 : NEW_EXP0(ModifierExpression
);
1307 out
->stmt
= NEW_STMT
1308 (ClassVariable
, exp
,
1309 (type
) ? type
->typeAnnotationName() : "",
1310 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1313 NEW_STMT(ClassConstant
,
1314 (type
) ? type
->typeAnnotationName() : "",
1315 dynamic_pointer_cast
<ExpressionList
>(decl
->exp
));
1319 void Parser::onMemberModifier(Token
&out
, Token
*modifiers
, Token
&modifier
) {
1320 ModifierExpressionPtr expList
;
1322 expList
= dynamic_pointer_cast
<ModifierExpression
>(modifiers
->exp
);
1324 expList
= NEW_EXP0(ModifierExpression
);
1326 expList
->add(modifier
->num());
1330 ///////////////////////////////////////////////////////////////////////////////
1333 void Parser::initParseTree() {
1334 m_tree
= NEW_STMT0(StatementList
);
1337 void Parser::finiParseTree() {
1338 if (m_staticVars
.size()) fixStaticVars();
1339 FunctionScopePtr pseudoMain
= m_file
->setTree(m_ar
, m_tree
);
1340 completeScope(pseudoMain
);
1341 pseudoMain
->setOuterScope(m_file
);
1342 m_file
->setOuterScope(m_ar
);
1343 m_ar
->parseExtraCode(m_file
->getName());
1344 LocationPtr loc
= getLocation();
1345 loc
->line0
= loc
->char0
= 1;
1346 pseudoMain
->getStmt()->setLocation(loc
);
1349 void Parser::onHaltCompiler() {
1350 if (m_nsState
== InsideNamespace
&& !m_nsFileScope
) {
1351 error("__HALT_COMPILER() can only be used from the outermost scope");
1354 // Backpatch instances of __COMPILER_HALT_OFFSET__
1355 for(auto &cho
: m_compilerHaltOffsetVec
) {
1356 cho
->setCompilerHaltOffset(m_scanner
.getLocation()->cursor
);
1360 void Parser::onStatementListStart(Token
&out
) {
1364 void Parser::addTopStatement(Token
&new_stmt
) {
1365 addStatement(m_tree
, new_stmt
->stmt
);
1368 void Parser::addStatement(Token
&out
, Token
&stmts
, Token
&new_stmt
) {
1370 out
->stmt
= NEW_STMT0(StatementList
);
1372 out
->stmt
= stmts
->stmt
;
1374 addStatement(out
->stmt
, new_stmt
->stmt
);
1377 void Parser::addStatement(StatementPtr stmt
, StatementPtr new_stmt
) {
1379 stmt
->addElement(new_stmt
);
1383 void Parser::finishStatement(Token
&out
, Token
&stmts
) {
1385 out
->stmt
= NEW_STMT0(StatementList
);
1387 out
->stmt
= stmts
->stmt
;
1391 void Parser::onBlock(Token
&out
, Token
&stmts
) {
1393 stmts
->stmt
= NEW_STMT0(StatementList
);
1394 } else if (!stmts
->stmt
->is(Statement::KindOfStatementList
)) {
1395 out
->stmt
= NEW_STMT0(StatementList
);
1396 out
->stmt
->addElement(stmts
->stmt
);
1397 stmts
->stmt
= out
->stmt
;
1399 out
->stmt
= NEW_STMT(BlockStatement
,
1400 dynamic_pointer_cast
<StatementList
>(stmts
->stmt
));
1403 void Parser::onIf(Token
&out
, Token
&cond
, Token
&stmt
, Token
&elseifs
,
1405 StatementPtr stmtList
;
1406 if (!elseifs
->stmt
) {
1407 stmtList
= NEW_STMT0(StatementList
);
1409 stmtList
= elseifs
->stmt
;
1411 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1412 stmt
->stmt
= NEW_STMT(BlockStatement
,
1413 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1415 stmtList
->insertElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1416 if (elseStmt
->stmt
) {
1417 if (elseStmt
->stmt
->is(Statement::KindOfStatementList
)) {
1418 elseStmt
->stmt
= NEW_STMT
1419 (BlockStatement
, dynamic_pointer_cast
<StatementList
>(elseStmt
->stmt
));
1421 stmtList
->addElement(NEW_STMT(IfBranchStatement
, ExpressionPtr(),
1424 out
->stmt
= NEW_STMT(IfStatement
,
1425 dynamic_pointer_cast
<StatementList
>(stmtList
));
1428 void Parser::onElseIf(Token
&out
, Token
&elseifs
, Token
&cond
, Token
&stmt
) {
1429 if (!elseifs
->stmt
) {
1430 out
->stmt
= NEW_STMT0(StatementList
);
1432 out
->stmt
= elseifs
->stmt
;
1434 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1435 stmt
->stmt
= NEW_STMT(BlockStatement
,
1436 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1438 out
->stmt
->addElement(NEW_STMT(IfBranchStatement
, cond
->exp
, stmt
->stmt
));
1441 void Parser::onWhile(Token
&out
, Token
&cond
, Token
&stmt
) {
1442 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1443 stmt
->stmt
= NEW_STMT(BlockStatement
,
1444 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1446 out
->stmt
= NEW_STMT(WhileStatement
, cond
->exp
, stmt
->stmt
);
1449 void Parser::onDo(Token
&out
, Token
&stmt
, Token
&cond
) {
1450 out
->stmt
= NEW_STMT(DoStatement
, stmt
->stmt
, cond
->exp
);
1453 void Parser::onFor(Token
&out
, Token
&expr1
, Token
&expr2
, Token
&expr3
,
1455 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1456 stmt
->stmt
= NEW_STMT(BlockStatement
,
1457 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1459 out
->stmt
= NEW_STMT(ForStatement
, expr1
->exp
, expr2
->exp
, expr3
->exp
,
1463 void Parser::onSwitch(Token
&out
, Token
&expr
, Token
&cases
) {
1464 out
->stmt
= NEW_STMT(SwitchStatement
, expr
->exp
,
1465 dynamic_pointer_cast
<StatementList
>(cases
->stmt
));
1468 void Parser::onCase(Token
&out
, Token
&cases
, Token
*cond
, Token
&stmt
) {
1470 out
->stmt
= NEW_STMT0(StatementList
);
1472 out
->stmt
= cases
->stmt
;
1474 out
->stmt
->addElement(NEW_STMT(CaseStatement
,
1475 cond
? cond
->exp
: ExpressionPtr(),
1479 void Parser::onBreakContinue(Token
&out
, bool isBreak
, Token
* expr
) {
1484 if (!expr
->exp
->getScalarValue(v
)) {
1485 PARSE_ERROR("'%s' operator with non-constant operand is no longer "
1486 "supported", (isBreak
? "break" : "continue"));
1488 if (!v
.isInteger() || v
.toInt64() <= 0) {
1489 PARSE_ERROR("'%s' operator accepts only positive numbers",
1490 (isBreak
? "break" : "continue"));
1492 depth
= static_cast<uint64_t>(v
.toInt64());
1496 out
->stmt
= NEW_STMT(BreakStatement
, depth
);
1498 out
->stmt
= NEW_STMT(ContinueStatement
, depth
);
1502 void Parser::onReturn(Token
&out
, Token
*expr
) {
1503 out
->stmt
= NEW_STMT(ReturnStatement
, expr
? expr
->exp
: ExpressionPtr());
1504 // When HipHopSyntax is enabled, "yield break" is the only supported method
1505 // for early termination of a generator.
1506 if (!m_funcContexts
.empty() &&
1507 (expr
|| (Scanner::AllowHipHopSyntax
& Option::GetScannerType()))) {
1508 FunctionContext
& fc
= m_funcContexts
.back();
1509 if (fc
.isGenerator
) {
1510 Compiler::Error(InvalidYield
, out
->stmt
);
1511 PARSE_ERROR((Scanner::AllowHipHopSyntax
& Option::GetScannerType()) ?
1512 "Cannot mix 'return' and 'yield' in the same function" :
1513 "Generators cannot return values using \"return\"");
1516 fc
.hasReturn
= true;
1520 void Parser::invalidYield() {
1521 ExpressionPtr
exp(new SimpleFunctionCall(BlockScopePtr(),
1525 ExpressionListPtr(),
1527 Compiler::Error(Compiler::InvalidYield
, exp
);
1530 bool Parser::canBeAsyncOrGenerator(string funcName
, string clsName
) {
1531 if (clsName
.empty()) {
1534 if (strcasecmp(funcName
.c_str(), clsName
.c_str()) == 0) {
1537 if (strncmp(funcName
.c_str(), "__", 2) == 0) {
1538 const char *fname
= funcName
.c_str() + 2;
1539 if (!strcasecmp(fname
, "construct") ||
1540 !strcasecmp(fname
, "destruct") ||
1541 !strcasecmp(fname
, "get") ||
1542 !strcasecmp(fname
, "set") ||
1543 !strcasecmp(fname
, "isset") ||
1544 !strcasecmp(fname
, "unset") ||
1545 !strcasecmp(fname
, "call") ||
1546 !strcasecmp(fname
, "callstatic") ||
1547 !strcasecmp(fname
, "invoke")) {
1554 bool Parser::setIsGenerator() {
1555 if (m_funcContexts
.empty()) {
1557 PARSE_ERROR("Yield can only be used inside a function");
1561 FunctionContext
& fc
= m_funcContexts
.back();
1564 PARSE_ERROR((Scanner::AllowHipHopSyntax
& Option::GetScannerType()) ?
1565 "Cannot mix 'return' and 'yield' in the same function" :
1566 "Generators cannot return values using \"return\"");
1571 PARSE_ERROR("'yield' is not allowed in async functions.");
1574 fc
.isGenerator
= true;
1576 if (!canBeAsyncOrGenerator(m_funcName
, m_clsName
)) {
1578 PARSE_ERROR("'yield' is not allowed in constructor, destructor, or "
1586 void Parser::onYield(Token
&out
, Token
&expr
) {
1587 if (setIsGenerator()) {
1588 out
->exp
= NEW_EXP(YieldExpression
, ExpressionPtr(), expr
->exp
);
1592 void Parser::onYieldPair(Token
&out
, Token
&key
, Token
&val
) {
1593 if (setIsGenerator()) {
1594 out
->exp
= NEW_EXP(YieldExpression
, key
->exp
, val
->exp
);
1598 void Parser::onYieldBreak(Token
&out
) {
1599 if (setIsGenerator()) {
1600 out
->stmt
= NEW_STMT(ReturnStatement
, ExpressionPtr());
1604 void Parser::invalidAwait() {
1605 ExpressionPtr
exp(new SimpleFunctionCall(BlockScopePtr(),
1609 ExpressionListPtr(),
1611 Compiler::Error(Compiler::InvalidAwait
, exp
);
1614 bool Parser::setIsAsync() {
1615 if (m_funcContexts
.empty()) {
1617 PARSE_ERROR("'await' can only be used inside a function");
1621 FunctionContext
& fc
= m_funcContexts
.back();
1622 if (fc
.isGenerator
) {
1624 PARSE_ERROR("'await' is not allowed in generators.");
1629 if (!canBeAsyncOrGenerator(m_funcName
, m_clsName
)) {
1631 PARSE_ERROR("'await' is not allowed in constructors, destructors, or "
1639 void Parser::onAwait(Token
&out
, Token
&expr
) {
1641 out
->exp
= NEW_EXP(AwaitExpression
, expr
->exp
);
1645 void Parser::onGlobal(Token
&out
, Token
&expr
) {
1646 out
->stmt
= NEW_STMT(GlobalStatement
,
1647 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1650 void Parser::onGlobalVar(Token
&out
, Token
*exprs
, Token
&expr
) {
1651 ExpressionPtr expList
;
1652 if (exprs
&& exprs
->exp
) {
1653 expList
= exprs
->exp
;
1655 expList
= NEW_EXP0(ExpressionList
);
1657 switch (expr
->num()) {
1659 expList
->addElement(NEW_EXP(SimpleVariable
, expr
->text()));
1662 expList
->addElement(createDynamicVariable(expr
->exp
));
1670 void Parser::onStatic(Token
&out
, Token
&expr
) {
1671 out
->stmt
= NEW_STMT(StaticStatement
,
1672 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1675 void Parser::onEcho(Token
&out
, Token
&expr
, bool html
) {
1677 LocationPtr loc
= getLocation();
1678 if (loc
->line1
== 2 && loc
->char1
== 0 && expr
->text()[0] == '#') {
1679 // skipping linux interpreter declaration
1680 out
->stmt
= NEW_STMT0(StatementList
);
1682 ExpressionPtr exp
= NEW_EXP(ScalarExpression
, T_STRING
, expr
->text(),
1684 ExpressionListPtr expList
= NEW_EXP(ExpressionList
);
1685 expList
->addElement(exp
);
1686 out
->stmt
= NEW_STMT(EchoStatement
, expList
);
1689 out
->stmt
= NEW_STMT(EchoStatement
,
1690 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1694 void Parser::onUnset(Token
&out
, Token
&expr
) {
1695 out
->stmt
= NEW_STMT(UnsetStatement
,
1696 dynamic_pointer_cast
<ExpressionList
>(expr
->exp
));
1697 m_file
->setAttribute(FileScope::ContainsUnset
);
1700 void Parser::onExpStatement(Token
&out
, Token
&expr
) {
1701 ExpStatementPtr
exp(NEW_STMT(ExpStatement
, expr
->exp
));
1703 exp
->onParse(m_ar
, m_file
);
1706 void Parser::onForEach(Token
&out
, Token
&arr
, Token
&name
, Token
&value
,
1708 if (dynamic_pointer_cast
<FunctionCall
>(name
->exp
) ||
1709 dynamic_pointer_cast
<FunctionCall
>(value
->exp
)) {
1710 PARSE_ERROR("Can't use return value in write context");
1712 if (value
->exp
&& name
->num()) {
1713 PARSE_ERROR("Key element cannot be a reference");
1716 checkAssignThis(name
);
1717 checkAssignThis(value
);
1718 if (stmt
->stmt
&& stmt
->stmt
->is(Statement::KindOfStatementList
)) {
1719 stmt
->stmt
= NEW_STMT(BlockStatement
,
1720 dynamic_pointer_cast
<StatementList
>(stmt
->stmt
));
1722 out
->stmt
= NEW_STMT(ForEachStatement
, arr
->exp
, name
->exp
, name
->num() == 1,
1723 value
->exp
, value
->num() == 1, stmt
->stmt
);
1726 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&className
, Token
&var
,
1727 Token
&catchStmt
, Token
&catches
, Token
&finallyStmt
) {
1728 StatementPtr stmtList
;
1729 if (catches
->stmt
) {
1730 stmtList
= catches
->stmt
;
1732 stmtList
= NEW_STMT0(StatementList
);
1734 stmtList
->insertElement(NEW_STMT(CatchStatement
, className
->text(),
1735 var
->text(), catchStmt
->stmt
));
1736 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1737 dynamic_pointer_cast
<StatementList
>(stmtList
),
1739 if (tryStmt
->stmt
) {
1740 out
->stmt
->setLabelScope(stmtList
->getLabelScope());
1744 void Parser::onTry(Token
&out
, Token
&tryStmt
, Token
&finallyStmt
) {
1745 out
->stmt
= NEW_STMT(TryStatement
, tryStmt
->stmt
,
1746 dynamic_pointer_cast
<StatementList
>(NEW_STMT0(StatementList
)),
1748 if (tryStmt
->stmt
) {
1749 out
->stmt
->setLabelScope(tryStmt
->stmt
->getLabelScope());
1753 void Parser::onCatch(Token
&out
, Token
&catches
, Token
&className
, Token
&var
,
1755 StatementPtr stmtList
;
1756 if (catches
->stmt
) {
1757 stmtList
= catches
->stmt
;
1759 stmtList
= NEW_STMT0(StatementList
);
1761 stmtList
->addElement(NEW_STMT(CatchStatement
, className
->text(),
1762 var
->text(), stmt
->stmt
));
1763 out
->stmt
= stmtList
;
1766 void Parser::onFinally(Token
&out
, Token
&stmt
) {
1767 out
->stmt
= NEW_STMT(FinallyStatement
, stmt
->stmt
);
1768 // TODO (#3271396) This can be greatly improved. In particular
1769 // even when a finally block exists inside a function it is often
1770 // the case that the unnamed locals state & ret are not needed.
1771 // See task description for further details.
1772 m_file
->setAttribute(FileScope::NeedsFinallyLocals
);
1775 void Parser::onThrow(Token
&out
, Token
&expr
) {
1776 out
->stmt
= NEW_STMT(ThrowStatement
, expr
->exp
);
1779 void Parser::onClosureStart(Token
&name
) {
1780 if (!m_funcName
.empty()) {
1781 m_containingFuncName
= m_funcName
;
1785 onFunctionStart(name
, true);
1788 Token
Parser::onClosure(ClosureType type
,
1798 auto stmt
= onFunctionHelper(
1799 FunctionType::Closure
,
1810 ExpressionListPtr vars
= dynamic_pointer_cast
<ExpressionList
>(cparams
->exp
);
1812 for (int i
= vars
->getCount() - 1; i
>= 0; i
--) {
1813 ParameterExpressionPtr
param(
1814 dynamic_pointer_cast
<ParameterExpression
>((*vars
)[i
]));
1815 if (param
->getName() == "this") {
1816 PARSE_ERROR("Cannot use $this as lexical variable");
1821 ClosureExpressionPtr closure
= NEW_EXP(
1824 dynamic_pointer_cast
<FunctionStatement
>(stmt
),
1827 closure
->getClosureFunction()->setContainingClosure(closure
);
1833 Token
Parser::onExprForLambda(const Token
& expr
) {
1834 auto stmt
= NEW_STMT(ReturnStatement
, expr
.exp
);
1836 ret
.stmt
= NEW_STMT0(StatementList
);
1837 ret
.stmt
->addElement(stmt
);
1841 void Parser::onClosureParam(Token
&out
, Token
*params
, Token
¶m
,
1843 ExpressionPtr expList
;
1845 expList
= params
->exp
;
1847 expList
= NEW_EXP0(ExpressionList
);
1849 expList
->addElement(NEW_EXP(ParameterExpression
, TypeAnnotationPtr(),
1850 m_scanner
.isHHSyntaxEnabled(), param
->text(),
1851 ref
, 0, ExpressionPtr(), ExpressionPtr()));
1855 void Parser::onLabel(Token
&out
, Token
&label
) {
1856 out
->stmt
= NEW_STMT(LabelStatement
, label
.text());
1859 void Parser::onGoto(Token
&out
, Token
&label
, bool limited
) {
1860 out
->stmt
= NEW_STMT(GotoStatement
, label
.text());
1863 void Parser::onTypedef(Token
& out
, const Token
& name
, const Token
& type
) {
1864 // Note: we don't always get TypeAnnotations (e.g. for shape types
1866 auto const annot
= type
.typeAnnotation
1867 ? type
.typeAnnotation
1868 : std::make_shared
<TypeAnnotation
>(type
.text(), TypeAnnotationPtr());
1870 auto td_stmt
= NEW_STMT(TypedefStatement
, name
.text(), annot
);
1871 td_stmt
->onParse(m_ar
, m_file
);
1872 out
->stmt
= td_stmt
;
1875 void Parser::onTypeAnnotation(Token
& out
, const Token
& name
,
1876 const Token
& typeArgs
) {
1877 out
.set(name
.num(), name
.text());
1878 out
.typeAnnotation
= TypeAnnotationPtr(
1879 new TypeAnnotation(name
.text(), typeArgs
.typeAnnotation
));
1880 if (isTypeVar(name
.text())) {
1881 out
.typeAnnotation
->setTypeVar();
1885 void Parser::onTypeList(Token
& type1
, const Token
& type2
) {
1886 if (!type1
.typeAnnotation
) {
1887 PARSE_ERROR("Missing type in type list");
1889 if (type2
.num() != 0 && !type1
.typeAnnotation
) {
1890 PARSE_ERROR("Missing type in type list");
1892 if (type2
.typeAnnotation
) {
1893 type1
.typeAnnotation
->appendToTypeList(type2
.typeAnnotation
);
1897 void Parser::onTypeSpecialization(Token
& type
, char specialization
) {
1898 if (type
.typeAnnotation
) {
1899 switch (specialization
) {
1901 type
.typeAnnotation
->setNullable();
1904 type
.typeAnnotation
->setSoft();
1907 type
.typeAnnotation
->setTuple();
1910 type
.typeAnnotation
->setFunction();
1913 type
.typeAnnotation
->setXHP();
1919 void Parser::onQuery(Token
&out
, Token
&head
, Token
&body
) {
1920 auto qe
= NEW_EXP(QueryExpression
, head
.exp
, body
.exp
);
1921 qe
->doRewrites(m_ar
, m_file
);
1925 void appendList(ExpressionListPtr expList
, Token
*exps
) {
1926 if (exps
!= nullptr) {
1927 assert(exps
->exp
->is(Expression::KindOfExpressionList
));
1928 ExpressionListPtr
el(static_pointer_cast
<ExpressionList
>(exps
->exp
));
1929 for (unsigned int i
= 0; i
< el
->getCount(); i
++) {
1930 if ((*el
)[i
]) expList
->addElement((*el
)[i
]);
1935 void Parser::onQueryBody(
1936 Token
&out
, Token
*clauses
, Token
&select
, Token
*cont
) {
1937 ExpressionListPtr
expList(NEW_EXP0(ExpressionList
));
1938 appendList(expList
, clauses
);
1939 expList
->addElement(select
.exp
);
1940 if (cont
!= nullptr) expList
->addElement(cont
->exp
);
1944 void Parser::onQueryBodyClause(Token
&out
, Token
*clauses
, Token
&clause
) {
1945 ExpressionPtr expList
;
1946 if (clauses
&& clauses
->exp
) {
1947 expList
= clauses
->exp
;
1949 expList
= NEW_EXP0(ExpressionList
);
1951 expList
->addElement(clause
->exp
);
1955 void Parser::onFromClause(Token
&out
, Token
&var
, Token
&coll
) {
1956 out
->exp
= NEW_EXP(FromClause
, var
.text(), coll
.exp
);
1959 void Parser::onLetClause(Token
&out
, Token
&var
, Token
&expr
) {
1960 out
->exp
= NEW_EXP(LetClause
, var
.text(), expr
.exp
);
1963 void Parser::onWhereClause(Token
&out
, Token
&expr
) {
1964 out
->exp
= NEW_EXP(WhereClause
, expr
.exp
);
1967 void Parser::onJoinClause(Token
&out
, Token
&var
, Token
&coll
,
1968 Token
&left
, Token
&right
) {
1969 out
->exp
= NEW_EXP(JoinClause
, var
.text(), coll
.exp
,
1970 left
.exp
, right
.exp
, "");
1973 void Parser::onJoinIntoClause(Token
&out
, Token
&var
, Token
&coll
,
1974 Token
&left
, Token
&right
, Token
&group
) {
1975 out
->exp
= NEW_EXP(JoinClause
, var
.text(), coll
.exp
,
1976 left
.exp
, right
.exp
, group
.text());
1979 void Parser::onOrderbyClause(Token
&out
, Token
&orderings
) {
1980 out
->exp
= NEW_EXP(OrderbyClause
, orderings
.exp
);
1983 void Parser::onOrdering(Token
&out
, Token
*orderings
, Token
&ordering
) {
1984 ExpressionPtr expList
;
1985 if (orderings
&& orderings
->exp
) {
1986 expList
= orderings
->exp
;
1988 expList
= NEW_EXP0(ExpressionList
);
1990 expList
->addElement(ordering
->exp
);
1994 void Parser::onOrderingExpr(Token
&out
, Token
&expr
, Token
*direction
) {
1995 out
->exp
= NEW_EXP(Ordering
, expr
.exp
, (direction
) ? direction
->text() : "");
1998 void Parser::onSelectClause(Token
&out
, Token
&expr
) {
1999 out
->exp
= NEW_EXP(SelectClause
, expr
.exp
);
2002 void Parser::onGroupClause(Token
&out
, Token
&coll
, Token
&key
) {
2003 out
->exp
= NEW_EXP(GroupClause
, coll
.exp
, key
.exp
);
2006 void Parser::onIntoClause(Token
&out
, Token
&var
, Token
&query
) {
2007 out
->exp
= NEW_EXP(IntoClause
, var
.text(), query
.exp
);
2010 ///////////////////////////////////////////////////////////////////////////////
2011 // namespace support
2013 //////////////////// AliasTable /////////////////////
2015 Parser::AliasTable::AliasTable(const hphp_string_imap
<std::string
>& autoAliases
,
2016 std::function
<bool ()> autoOracle
)
2017 : m_autoAliases(autoAliases
), m_autoOracle(autoOracle
) {
2018 if (!m_autoOracle
) {
2023 void Parser::AliasTable::setFalseOracle() {
2024 m_autoOracle
= [] () { return false; };
2027 std::string
Parser::AliasTable::getName(std::string alias
) {
2028 auto it
= m_aliases
.find(alias
);
2029 if (it
!= m_aliases
.end()) {
2030 return it
->second
.name
;
2032 auto autoIt
= m_autoAliases
.find(alias
);
2033 if (autoIt
!= m_autoAliases
.end()) {
2034 set(alias
, autoIt
->second
, AliasTable::AliasType::USE
);
2035 return autoIt
->second
;
2040 std::string
Parser::AliasTable::getDefName(std::string alias
) {
2041 auto it
= m_aliases
.find(alias
);
2042 if (it
!= m_aliases
.end() && it
->second
.type
== AliasType::DEF
) {
2043 return it
->second
.name
;
2048 std::string
Parser::AliasTable::getUseName(std::string alias
) {
2049 auto it
= m_aliases
.find(alias
);
2050 if (it
!= m_aliases
.end() && it
->second
.type
== AliasType::USE
) {
2051 return it
->second
.name
;
2056 bool Parser::AliasTable::isAliased(std::string alias
) {
2057 if (isUseType(alias
)) {
2060 return m_autoOracle() && m_autoAliases
.find(alias
) != m_autoAliases
.end();
2063 bool Parser::AliasTable::isAutoType(std::string alias
) {
2064 return m_autoOracle() && m_autoAliases
.find(alias
) != m_autoAliases
.end();
2067 bool Parser::AliasTable::isUseType(std::string alias
) {
2068 auto it
= m_aliases
.find(alias
);
2069 return it
!= m_aliases
.end() && it
->second
.type
== AliasType::USE
;
2072 bool Parser::AliasTable::isDefType(std::string alias
) {
2073 auto it
= m_aliases
.find(alias
);
2074 return it
!= m_aliases
.end() && it
->second
.type
== AliasType::DEF
;
2077 void Parser::AliasTable::set(std::string alias
,
2080 m_aliases
[alias
] = (NameEntry
){name
, type
};
2084 * To be called when we enter a fresh namespace.
2086 void Parser::AliasTable::clear() {
2090 //////////////////////////////////////////////////////
2094 * We auto-alias classes only on HH mode.
2096 bool Parser::isAutoAliasOn() {
2097 return m_scanner
.isHHSyntaxEnabled();
2100 hphp_string_imap
<std::string
> Parser::getAutoAliasedClassesHelper() {
2101 hphp_string_imap
<std::string
> autoAliases
;
2102 typedef AliasTable::AliasEntry AliasEntry
;
2103 std::vector
<AliasEntry
> aliases
{
2104 (AliasEntry
){"Traversable", "HH\\Traversable"},
2105 (AliasEntry
){"KeyedTraversable", "HH\\KeyedTraversable"},
2106 (AliasEntry
){"Iterator", "HH\\Iterator"},
2107 (AliasEntry
){"KeyedIterator", "HH\\KeyedIterator"},
2108 (AliasEntry
){"Iterable", "HH\\Iterable"},
2109 (AliasEntry
){"KeyedIterable", "HH\\KeyedIterable"},
2110 (AliasEntry
){"Collection", "HH\\Collection"},
2111 (AliasEntry
){"Vector", "HH\\Vector"},
2112 (AliasEntry
){"Map", "HH\\Map"},
2113 (AliasEntry
){"StableMap", "HH\\Map"}, // Merging with Map
2114 (AliasEntry
){"Set", "HH\\Set"},
2115 (AliasEntry
){"Pair", "HH\\Pair"},
2116 (AliasEntry
){"ImmVector", "HH\\ImmVector"},
2117 (AliasEntry
){"ImmMap", "HH\\ImmMap"},
2118 (AliasEntry
){"ImmSet", "HH\\ImmSet"},
2119 (AliasEntry
){"InvariantException", "HH\\InvariantException"},
2121 (AliasEntry
){"bool", "HH\\bool"},
2122 (AliasEntry
){"boolean", "HH\\bool"},
2123 (AliasEntry
){"int", "HH\\int"},
2124 (AliasEntry
){"integer", "HH\\int"},
2125 (AliasEntry
){"float", "HH\\float"},
2126 (AliasEntry
){"double", "HH\\float"},
2127 (AliasEntry
){"real", "HH\\float"},
2128 (AliasEntry
){"num", "HH\\num"},
2129 (AliasEntry
){"string", "HH\\string"},
2130 (AliasEntry
){"resource", "HH\\resource"},
2131 (AliasEntry
){"mixed", "HH\\mixed"},
2133 for (auto entry
: aliases
) {
2134 autoAliases
[entry
.alias
] = entry
.name
;
2139 const hphp_string_imap
<std::string
>& Parser::getAutoAliasedClasses() {
2140 static auto autoAliases
= getAutoAliasedClassesHelper();
2144 void Parser::nns(int token
, const std::string
& text
) {
2145 if (m_nsState
== SeenNamespaceStatement
&& token
!= ';') {
2146 error("No code may exist outside of namespace {}: %s",
2147 getMessage().c_str());
2151 if (m_nsState
== SeenNothing
&& !text
.empty() && token
!= T_DECLARE
&&
2153 m_nsState
= SeenNonNamespaceStatement
;
2157 void Parser::onNamespaceStart(const std::string
&ns
,
2158 bool file_scope
/* =false */) {
2159 if (m_nsState
== SeenNonNamespaceStatement
) {
2160 error("Namespace declaration statement has to be the very first "
2161 "statement in the script: %s", getMessage().c_str());
2164 if (m_nsState
!= SeenNothing
&& file_scope
!= m_nsFileScope
) {
2165 error("Cannot mix bracketed namespace declarations with unbracketed "
2166 "namespace declarations");
2169 m_nsState
= InsideNamespace
;
2170 m_nsFileScope
= file_scope
;
2173 m_aliasTable
.clear();
2176 void Parser::onNamespaceEnd() {
2177 m_nsState
= SeenNamespaceStatement
;
2180 void Parser::onUse(const std::string
&ns
, const std::string
&as
) {
2183 size_t pos
= ns
.rfind(NAMESPACE_SEP
);
2184 if (pos
== string::npos
) {
2187 key
= ns
.substr(pos
+ 1);
2191 // It's not an error if the alias already exists but is auto-imported.
2192 // In that case, it gets replaced. It prompts an error if it is not
2193 // auto-imported and 'use' statement is trying to replace it.
2194 if (m_aliasTable
.isUseType(key
)) {
2195 error("Cannot use %s as %s because the name is already in use: %s",
2196 ns
.c_str(), key
.c_str(), getMessage().c_str());
2199 if (m_aliasTable
.isDefType(key
)) {
2200 auto defName
= m_aliasTable
.getDefName(key
);
2201 if (strcasecmp(defName
.c_str(), ns
.c_str())) {
2202 error("Cannot use %s as %s because the name is already in use: %s",
2203 ns
.c_str(), key
.c_str(), getMessage().c_str());
2208 m_aliasTable
.set(key
, ns
, AliasTable::AliasType::USE
);
2211 std::string
Parser::nsDecl(const std::string
&name
) {
2212 if (m_namespace
.empty()) {
2215 return m_namespace
+ NAMESPACE_SEP
+ name
;
2218 std::string
Parser::resolve(const std::string
&ns
, bool cls
) {
2219 size_t pos
= ns
.find(NAMESPACE_SEP
);
2220 string alias
= (pos
!= string::npos
) ? ns
.substr(0, pos
) : ns
;
2222 if (m_aliasTable
.isAliased(alias
)) {
2223 auto name
= m_aliasTable
.getName(alias
);
2224 // Was it a namespace alias?
2225 if (pos
!= string::npos
) {
2226 return name
+ ns
.substr(pos
);
2228 // Only classes can appear directly in "use" statements
2234 // Classes don't fallback to the global namespace.
2236 if (!strcasecmp("self", ns
.c_str()) ||
2237 !strcasecmp("parent", ns
.c_str())) {
2243 // if qualified name, prepend current namespace
2244 if (pos
!= string::npos
) {
2248 // unqualified name in global namespace
2249 if (m_namespace
.empty()) {
2253 if (!strcasecmp("true", ns
.c_str()) ||
2254 !strcasecmp("false", ns
.c_str()) ||
2255 !strcasecmp("null", ns
.c_str())) {
2261 void Parser::invalidateGoto(TStatementPtr stmt
, GotoError error
) {
2262 GotoStatement
*gs
= (GotoStatement
*) stmt
;
2264 gs
->invalidate(error
);
2267 void Parser::invalidateLabel(TStatementPtr stmt
) {
2268 LabelStatement
*ls
= (LabelStatement
*) stmt
;
2273 TStatementPtr
Parser::extractStatement(ScannerToken
*stmt
) {
2274 Token
*t
= (Token
*) stmt
;
2275 return t
->stmt
.get();
2278 ///////////////////////////////////////////////////////////////////////////////
2280 bool Parser::hasType(Token
&type
) {
2281 if (!type
.text().empty()) {
2282 if (!m_scanner
.isHHSyntaxEnabled()) {
2283 PARSE_ERROR("Type hint is not enabled");
2291 void Parser::registerAlias(std::string name
) {
2292 size_t pos
= name
.rfind(NAMESPACE_SEP
);
2293 if (pos
!= string::npos
) {
2294 string key
= name
.substr(pos
+ 1);
2295 if (m_aliasTable
.isUseType(key
)) {
2296 auto useName
= m_aliasTable
.getUseName(key
);
2297 if (strcasecmp(useName
.c_str(), name
.c_str())) {
2298 error("Cannot declare class %s because the name is already in use: %s",
2299 name
.c_str(), getMessage().c_str());
2303 m_aliasTable
.set(key
, name
, AliasTable::AliasType::DEF
);
2308 ///////////////////////////////////////////////////////////////////////////////