Objprof for HHVM (Approx. instance counter)
[hiphop-php.git] / hphp / compiler / parser / parser.cpp
blobcd23562c251dc2e56b54382ad35c9ccbd529e636
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
17 #include <vector>
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"
104 #ifdef FACEBOOK
105 #include "hphp/facebook/src/compiler/fb_compiler_hooks.h"
106 #define RealSimpleFunctionCall FBSimpleFunctionCall
107 #else
108 #define RealSimpleFunctionCall SimpleFunctionCall
109 #endif
111 #define NEW_EXP0(cls) \
112 cls##Ptr(new cls(BlockScopePtr(), \
113 getLocation()))
114 #define NEW_EXP(cls, e...) \
115 cls##Ptr(new cls(BlockScopePtr(), \
116 getLocation(), ##e))
117 #define NEW_STMT0(cls) \
118 cls##Ptr(new cls(BlockScopePtr(), getLabelScope(), \
119 getLocation()))
120 #define NEW_STMT(cls, e...) \
121 cls##Ptr(new cls(BlockScopePtr(), getLabelScope(), \
122 getLocation(), ##e))
124 #define PARSE_ERROR(fmt, args...) HPHP_PARSER_ERROR(fmt, this, ##args)
126 using namespace HPHP::Compiler;
128 namespace HPHP {
130 SimpleFunctionCallPtr NewSimpleFunctionCall(
131 EXPRESSION_CONSTRUCTOR_PARAMETERS,
132 const std::string &name, bool hadBackslash, ExpressionListPtr params,
133 ExpressionPtr cls) {
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) {
142 string key = as;
143 if (key.empty()) {
144 size_t pos = fqn.rfind(NAMESPACE_SEP);
145 if (pos == string::npos) {
146 key = fqn;
147 } else {
148 key = fqn.substr(pos + 1);
152 return key;
155 namespace Compiler {
156 ///////////////////////////////////////////////////////////////////////////////
157 // statics
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));
189 newScope();
190 m_staticVars.push_back(StringToExpressionPtrVecMap());
191 m_inTrait = false;
193 Lock lock(m_ar->getMutex());
194 m_ar->addFileScope(m_file);
197 bool Parser::parse() {
198 try {
199 if (!parseImpl()) {
200 throw ParseTimeFatalException(m_fileName, line1(),
201 "Parse error: %s",
202 errString().c_str());
204 if (scanner().isHHFile()) {
205 m_file->setHHFile();
207 return true;
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);
212 } else {
213 m_file->makeFatal(m_ar, e.getMessage(), e.m_line);
215 return false;
219 void Parser::error(const char* fmt, ...) {
220 va_list ap;
221 va_start(ap, fmt);
222 string msg;
223 string_vsnprintf(msg, fmt, ap);
224 va_end(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);
233 exn.setParseFatal();
234 throw exn;
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();
256 return ret;
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);
271 m_scopes.pop_back();
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) {
285 if (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();
305 if (fresh) {
306 m_labelScopes.pop_back();
310 ///////////////////////////////////////////////////////////////////////////////
311 // variables
313 void Parser::onName(Token &out, Token &name, NameKind kind) {
314 switch (kind) {
315 case StringName:
316 case StaticName:
317 onScalar(out, T_STRING, name);
318 break;
319 case StaticClassExprName:
320 case ExprName:
321 case VarName:
322 out = name;
323 break;
327 void Parser::onStaticVariable(Token &out, Token *exprs, Token &var,
328 Token *value) {
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,
337 Token *value) {
338 onVariable(out, exprs, var, value, false, m_scanner.detachDocComment());
341 void Parser::onClassConstant(Token &out, Token *exprs, Token &var,
342 Token &value) {
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;
350 if (exprs) {
351 expList = exprs->exp;
352 } else {
353 expList = NEW_EXP0(ExpressionList);
355 ExpressionPtr exp;
356 if (constant) {
357 exp = NEW_EXP(ConstantExpression, var->text(), false, docComment);
358 } else {
359 exp = NEW_EXP(SimpleVariable, var->text(), docComment);
361 if (value) {
362 exp = NEW_EXP(AssignmentExpression, exp, value->exp, false);
364 expList->addElement(exp);
365 out->exp = expList;
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) {
377 out->exp = var->exp;
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;
388 } else {
389 StaticMemberExpressionPtr sme = NEW_EXP(StaticMemberExpression,
390 cls->exp, name->exp);
391 sme->onParse(m_ar, m_file);
392 out->exp = sme;
396 void Parser::onRefDim(Token &out, Token &var, Token &offset) {
397 if (!var->exp) {
398 var->exp = NEW_EXP(ConstantExpression, var->text(), var->num() & 2);
400 if (!offset->exp) {
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) {
415 if (encap) {
416 ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp);
417 if (var) {
418 return NEW_EXP(SimpleVariable, var->getName());
420 } else {
421 ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(exp);
422 if (var) {
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) {
436 if (!params) {
437 out->exp = NEW_EXP0(ExpressionList);
438 } else {
439 out->exp = params->exp;
441 if (ref) {
442 expr->exp->setContext(Expression::RefParameter);
443 expr->exp->setContext(Expression::RefValue);
445 if (unpack) {
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 &params,
453 Token *cls) {
454 ExpressionPtr clsExp;
455 if (cls) {
456 clsExp = cls->exp;
458 if (dynamic) {
459 out->exp = NEW_EXP(DynamicFunctionCall, name->exp,
460 dynamic_pointer_cast<ExpressionList>(params->exp),
461 clsExp);
462 } else {
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
467 ? funcName
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") {
475 funcName = stripped;
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"
493 )) {
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();
516 out->exp = call;
518 call->onParse(m_ar, m_file);
522 ///////////////////////////////////////////////////////////////////////////////
523 // object property and method calls
525 void Parser::onObjectProperty(Token &out, Token &base, Token &prop) {
526 if (!prop->exp) {
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,
533 Token &params) {
534 if (!prop->exp) {
535 prop->exp = NEW_EXP(ScalarExpression, T_STRING, prop->text());
537 ExpressionListPtr paramsExp;
538 if (params->exp) {
539 paramsExp = dynamic_pointer_cast<ExpressionList>(params->exp);
540 } else {
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);
558 } else {
559 expList = NEW_EXP0(ExpressionList);
561 ExpressionPtr exp;
562 if (type == -1) {
563 exp = expr->exp;
564 } else {
565 exp = NEW_EXP(ScalarExpression, T_ENCAPSED_AND_WHITESPACE,
566 expr->text(), true);
568 expList->addElement(exp);
569 out->exp = expList;
572 void Parser::encapRefDim(Token &out, Token &var, Token &offset) {
573 ExpressionPtr dim;
574 switch (offset->num()) {
575 case T_STRING:
576 dim = NEW_EXP(ScalarExpression, T_STRING, offset->text(), true);
577 break;
578 case T_NUM_STRING:
579 dim = NEW_EXP(ScalarExpression, T_NUM_STRING, offset->text());
580 break;
581 case T_VARIABLE:
582 dim = NEW_EXP(SimpleVariable, offset->text());
583 break;
584 default:
585 assert(false);
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 ///////////////////////////////////////////////////////////////////////////////
605 // expressions
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);
616 out->exp = con;
619 void Parser::onScalar(Token &out, int type, Token &scalar) {
620 if (type == T_FILE || type == T_DIR) {
621 onUnaryOpExp(out, scalar, type, true);
622 return;
625 ScalarExpressionPtr exp;
626 switch (type) {
627 case T_METHOD_C:
628 if (m_inTrait) {
629 exp = NEW_EXP(ScalarExpression, type, scalar->text(),
630 m_clsName + "::" + m_funcName);
631 } else {
632 exp = NEW_EXP(ScalarExpression, type, scalar->text());
634 break;
635 case T_CLASS_C:
636 if (m_inTrait) {
637 // Inside traits we already did the magic for static::class so lets
638 // reuse that
639 out->exp = NEW_EXP(SimpleFunctionCall, "get_class", true,
640 ExpressionListPtr(), ExpressionPtr());
641 return;
643 // fallthrough
644 case T_STRING:
645 case T_LNUMBER:
646 case T_DNUMBER:
647 case T_ONUMBER:
648 case T_LINE:
649 case T_COMPILER_HALT_OFFSET:
650 case T_FUNC_C:
651 exp = NEW_EXP(ScalarExpression, type, scalar->text());
652 break;
653 case T_TRAIT_C:
654 exp = NEW_EXP(ScalarExpression, type, scalar->text(),
655 m_inTrait ? m_clsName : "");
656 break;
657 case T_NS_C:
658 exp = NEW_EXP(ScalarExpression, type, m_namespace);
659 break;
660 case T_CONSTANT_ENCAPSED_STRING:
661 exp = NEW_EXP(ScalarExpression, type, scalar->text(), true);
662 break;
663 default:
664 assert(false);
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);
672 out->exp = exp;
675 void Parser::onExprListElem(Token &out, Token *exprs, Token &expr) {
676 ExpressionPtr expList;
677 if (exprs && exprs->exp) {
678 expList = exprs->exp;
679 } else {
680 expList = NEW_EXP0(ExpressionList);
682 expList->addElement(expr->exp);
683 out->exp = expList;
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;
701 if (!var) {
702 empty_var.exp = ExpressionPtr();
703 var = &empty_var;
705 if (!list) {
706 empty_list.exp = NEW_EXP0(ExpressionList);
707 list = &empty_list;
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);
736 ExpressionPtr exp =
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);
747 out->exp = new_obj;
750 void Parser::onUnaryOpExp(Token &out, Token &operand, int op, bool front) {
751 switch (op) {
752 case T_INCLUDE:
753 case T_INCLUDE_ONCE:
754 case T_REQUIRE:
755 case T_REQUIRE_ONCE:
757 IncludeExpressionPtr exp = NEW_EXP(IncludeExpression, operand->exp, op);
758 out->exp = exp;
759 exp->onParse(m_ar, m_file);
761 break;
762 case T_INC:
763 case T_DEC:
764 case T_ISSET:
765 case T_UNSET:
766 if (dynamic_pointer_cast<FunctionCall>(operand->exp)) {
767 PARSE_ERROR("Can't use return value in write context");
769 default:
771 UnaryOpExpressionPtr exp = NEW_EXP(UnaryOpExpression, operand->exp, op,
772 front);
773 out->exp = exp;
774 exp->onParse(m_ar, m_file);
776 break;
780 void Parser::onBinaryOpExp(Token &out, Token &operand1, Token &operand2,
781 int op) {
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");
790 out->exp = bop;
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,
810 bool ref) {
811 if (!value->exp) return;
813 ExpressionPtr expList;
814 if (pairs && pairs->exp) {
815 expList = pairs->exp;
816 } else {
817 expList = NEW_EXP0(ExpressionList);
819 ExpressionPtr nameExp = name ? name->exp : ExpressionPtr();
820 expList->addElement(NEW_EXP(ArrayPairExpression, nameExp, value->exp, ref));
821 out->exp = expList;
824 void Parser::onEmptyCollection(Token &out) {
825 out->exp = NEW_EXP0(ExpressionList);
828 void
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;
835 } else {
836 expList = NEW_EXP0(ExpressionList);
838 ExpressionPtr nameExp = name ? name->exp : ExpressionPtr();
839 expList->addElement(NEW_EXP(ArrayPairExpression, nameExp, value->exp, false,
840 true));
841 out->exp = expList;
844 void Parser::onEmptyCheckedArray(Token &out) {
845 out->exp = NEW_EXP0(ExpressionList);
848 void
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;
855 } else {
856 expList = NEW_EXP0(ExpressionList);
858 ExpressionPtr nameExp = name ? name->exp : ExpressionPtr();
859 expList->addElement(NEW_EXP(ArrayPairExpression, nameExp, value->exp, false));
860 out->exp = expList;
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,
871 Token &value) {
872 ExpressionPtr expList;
873 if (attrList && attrList->exp) {
874 expList = attrList->exp;
875 } else {
876 expList = NEW_EXP0(ExpressionList);
878 expList->addElement(NEW_EXP(UserAttribute, name->text(), value->exp));
879 out->exp = expList;
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, &params1, 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) {
898 if (!cls->exp) {
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);
904 out->exp = con;
907 void Parser::onClassClass(Token &out, Token &cls, Token &name,
908 bool inStaticContext) {
909 if (inStaticContext) {
910 if (cls->same("parent") || cls->same("static")) {
911 PARSE_ERROR(
912 "%s::class cannot be used for compile-time class name resolution",
913 cls->text().c_str()
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);
925 } else {
926 onClassConst(out, cls, name, inStaticContext);
928 } else {
929 onScalar(out, T_STRING, cls);
933 ///////////////////////////////////////////////////////////////////////////////
934 // function/method declaration
936 void Parser::onFunctionStart(Token &name, bool doPushComment /* = true */) {
937 m_file->pushAttribute();
938 if (doPushComment) {
939 pushComment();
941 newScope();
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();
956 it != end; ++it) {
957 const ExpressionPtrVec &v = it->second;
958 if (v.size() > 1) {
959 ExpressionPtr last;
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) {
968 if (!last) {
969 last = s;
970 } else {
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,
985 int returnsRef) {
986 funcContext.checkFinalAssertions();
988 // let async modifier be mandatory
989 if (funcContext.isAsync && !modifiers->isAsync()) {
990 invalidAwait();
991 PARSE_ERROR("Function '%s' contains 'await' but is not declared as async.",
992 funcName.c_str());
995 if (modifiers->isAsync() && returnsRef) {
996 PARSE_ERROR("Asynchronous function '%s' cannot return reference.",
997 funcName.c_str());
1000 if (modifiers->isAsync() && !canBeAsyncOrGenerator(funcName, m_clsName)) {
1001 PARSE_ERROR("cannot declare constructors, destructors, and "
1002 "magic methods such as '%s' as async",
1003 funcName.c_str());
1007 void Parser::prepareConstructorParameters(StatementListPtr stmts,
1008 ExpressionListPtr params,
1009 bool isAbstract) {
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;
1016 if (isAbstract) {
1017 param->parseTimeFatal(Compiler::InvalidAttribute,
1018 "parameter modifiers not allowed on "
1019 "abstract __construct");
1021 if (!stmts) {
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) {
1051 switch (type) {
1052 case FunctionType::Closure:
1053 return newClosureName(m_clsName, m_containingFuncName);
1054 case FunctionType::Function:
1055 assert(name);
1056 if (!m_lambdaMode) {
1057 return name->text();
1058 } else {
1059 return name->text() + "{lambda}";
1061 case FunctionType::Method:
1062 assert(name);
1063 return name->text();
1065 not_reached();
1068 StatementPtr Parser::onFunctionHelper(FunctionType type,
1069 Token *modifiers, Token &ret,
1070 Token &ref, Token *name, Token &params,
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());
1103 fixStaticVars();
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));
1122 } else {
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);
1133 mth = func;
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();
1147 if (reloc) {
1148 mth->getLocation()->line0 = loc->line0;
1149 mth->getLocation()->char0 = loc->char0;
1152 return mth;
1155 void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
1156 Token &name, Token &params, 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 &params, 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());
1176 if (ref) {
1177 PARSE_ERROR("Parameter $%s is both variadic and by reference"
1178 "; this is unsupported",
1179 var.text().c_str());
1182 ExpressionPtr expList;
1183 if (params) {
1184 expList = params->exp;
1185 } else {
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,
1197 ExpressionPtr(),
1198 attrList,
1199 /* variadic */ true));
1200 out->exp = expList;
1203 void Parser::onParam(Token &out, Token *params, Token &type, Token &var,
1204 bool ref, Token *defValue, Token *attr, Token *modifier) {
1205 ExpressionPtr expList;
1206 if (params) {
1207 expList = params->exp;
1208 } else {
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(),
1221 attrList));
1222 out->exp = expList;
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());
1235 pushComment();
1236 newScope();
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,
1243 Token *enumBase) {
1244 StatementListPtr stmtList;
1245 if (stmt->stmt) {
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;
1253 if (enumBase) {
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++) {
1268 auto param =
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);
1279 modifier->add(mod);
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);
1291 out->stmt = cls;
1293 cls->onParse(m_ar, m_file);
1295 completeScope(cls->getClassScope());
1296 if (cls->ignored()) {
1297 out->stmt = NEW_STMT0(StatementList);
1299 m_clsName.clear();
1300 m_inTrait = false;
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,
1312 Token *attr) {
1313 StatementListPtr stmtList;
1314 if (stmt->stmt) {
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,
1325 attrList);
1326 out->stmt = intf;
1328 intf->onParse(m_ar, m_file);
1330 completeScope(intf->getClassScope());
1333 void Parser::onInterfaceName(Token &out, Token *names, Token &name) {
1334 ExpressionPtr expList;
1335 if (names) {
1336 expList = names->exp;
1337 } else {
1338 expList = NEW_EXP0(ExpressionList);
1340 expList->addElement(NEW_EXP(ScalarExpression, T_STRING, name->text()));
1341 out->exp = expList;
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) {
1349 if (!rules->stmt) {
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;
1359 if (names) {
1360 expList = names->exp;
1361 } else {
1362 expList = NEW_EXP0(ExpressionList);
1364 expList->addElement(NEW_EXP(ScalarExpression, T_STRING, name->text()));
1365 out->exp = expList;
1368 void Parser::onTraitRule(Token &out, Token &stmtList, Token &newStmt) {
1369 if (!stmtList->stmt) {
1370 out->stmt = NEW_STMT0(StatementList);
1371 } else {
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,
1382 traitName->text());
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,
1392 traitName->text());
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);
1411 assert(ruleStmt);
1413 if (!newMethodName->text().empty()) {
1414 ScalarExpressionPtr expNewMethodName =
1415 NEW_EXP(ScalarExpression, T_STRING, newMethodName->text());
1416 ruleStmt->setNewMethodName(expNewMethodName);
1419 if (accessModifiers->exp) {
1420 auto modifiersExp =
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,
1433 Token *type) {
1434 if (modifiers) {
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));
1443 } else {
1444 out->stmt =
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;
1453 if (modifiers) {
1454 expList = dynamic_pointer_cast<ModifierExpression>(modifiers->exp);
1455 } else {
1456 expList = NEW_EXP0(ModifierExpression);
1458 expList->add(modifier->num());
1459 out->exp = expList;
1462 ///////////////////////////////////////////////////////////////////////////////
1463 // statements
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");
1484 return;
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) {
1493 out.reset();
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) {
1501 if (!stmts->stmt) {
1502 out->stmt = NEW_STMT0(StatementList);
1503 } else {
1504 out->stmt = stmts->stmt;
1506 addStatement(out->stmt, new_stmt->stmt);
1509 void Parser::addStatement(StatementPtr stmt, StatementPtr new_stmt) {
1510 if (new_stmt) {
1511 stmt->addElement(new_stmt);
1515 void Parser::finishStatement(Token &out, Token &stmts) {
1516 if (!stmts->stmt) {
1517 out->stmt = NEW_STMT0(StatementList);
1518 } else {
1519 out->stmt = stmts->stmt;
1523 void Parser::onBlock(Token &out, Token &stmts) {
1524 if (!stmts->stmt) {
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,
1536 Token &elseStmt) {
1537 StatementPtr stmtList;
1538 if (!elseifs->stmt) {
1539 stmtList = NEW_STMT0(StatementList);
1540 } else {
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(),
1554 elseStmt->stmt));
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);
1563 } else {
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,
1586 Token &stmt) {
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,
1592 stmt->stmt);
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) {
1601 if (!cases->stmt) {
1602 out->stmt = NEW_STMT0(StatementList);
1603 } else {
1604 out->stmt = cases->stmt;
1606 out->stmt->addElement(NEW_STMT(CaseStatement,
1607 cond ? cond->exp : ExpressionPtr(),
1608 stmt->stmt));
1611 void Parser::onBreakContinue(Token &out, bool isBreak, Token* expr) {
1612 uint64_t depth = 1;
1614 if (expr) {
1615 Variant v;
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());
1627 if (isBreak) {
1628 out->stmt = NEW_STMT(BreakStatement, depth);
1629 } else {
1630 out->stmt = NEW_STMT(ContinueStatement, depth);
1634 void Parser::setHasNonEmptyReturn(ConstructPtr blame) {
1635 if (m_funcContexts.empty()) {
1636 return;
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());
1650 if (expr) {
1651 setHasNonEmptyReturn(out->stmt);
1655 void Parser::invalidYield() {
1656 ExpressionPtr exp(new SimpleFunctionCall(BlockScopePtr(),
1657 getLocation(),
1658 "yield",
1659 false,
1660 ExpressionListPtr(),
1661 ExpressionPtr()));
1662 Compiler::Error(Compiler::InvalidYield, exp);
1665 bool Parser::canBeAsyncOrGenerator(string funcName, string clsName) {
1666 if (clsName.empty()) {
1667 return true;
1669 if (strcasecmp(funcName.c_str(), clsName.c_str()) == 0) {
1670 return false;
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")) {
1683 return false;
1686 return true;
1689 void Parser::setIsGenerator() {
1690 if (m_funcContexts.empty()) {
1691 invalidYield();
1692 PARSE_ERROR("Yield can only be used inside a function");
1695 FunctionContext& fc = m_funcContexts.back();
1696 if (fc.hasNonEmptyReturn) {
1697 invalidYield();
1698 PARSE_ERROR("Generators cannot return values using \"return\"");
1700 if (!canBeAsyncOrGenerator(m_funcName, m_clsName)) {
1701 invalidYield();
1702 PARSE_ERROR("'yield' is not allowed in constructor, destructor, or "
1703 "magic methods");
1706 fc.isGenerator = true;
1709 void Parser::onYield(Token &out, Token &expr) {
1710 setIsGenerator();
1711 out->exp = NEW_EXP(YieldExpression, ExpressionPtr(), expr->exp);
1714 void Parser::onYieldPair(Token &out, Token &key, Token &val) {
1715 setIsGenerator();
1716 out->exp = NEW_EXP(YieldExpression, key->exp, val->exp);
1719 void Parser::onYieldBreak(Token &out) {
1720 setIsGenerator();
1721 out->stmt = NEW_STMT(ReturnStatement, ExpressionPtr());
1724 void Parser::invalidAwait() {
1725 ExpressionPtr exp(new SimpleFunctionCall(BlockScopePtr(),
1726 getLocation(),
1727 "async",
1728 false,
1729 ExpressionListPtr(),
1730 ExpressionPtr()));
1731 Compiler::Error(Compiler::InvalidAwait, exp);
1734 void Parser::setIsAsync() {
1735 if (m_funcContexts.empty()) {
1736 invalidAwait();
1737 PARSE_ERROR("'await' can only be used inside a function");
1740 if (!canBeAsyncOrGenerator(m_funcName, m_clsName)) {
1741 invalidAwait();
1742 PARSE_ERROR("'await' is not allowed in constructors, destructors, or "
1743 "magic methods.");
1746 FunctionContext& fc = m_funcContexts.back();
1747 fc.isAsync = true;
1751 void Parser::onAwait(Token &out, Token &expr) {
1752 setIsAsync();
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;
1765 } else {
1766 expList = NEW_EXP0(ExpressionList);
1768 switch (expr->num()) {
1769 case 0:
1770 expList->addElement(NEW_EXP(SimpleVariable, expr->text()));
1771 break;
1772 case 1:
1773 expList->addElement(createDynamicVariable(expr->exp));
1774 break;
1775 default:
1776 assert(false);
1778 out->exp = expList;
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) {
1787 if (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);
1792 } else {
1793 ExpressionPtr exp = NEW_EXP(ScalarExpression, T_STRING, expr->text(),
1794 true);
1795 ExpressionListPtr expList = NEW_EXP(ExpressionList);
1796 expList->addElement(exp);
1797 out->stmt = NEW_STMT(EchoStatement, expList);
1799 } else {
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));
1813 out->stmt = 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");
1826 if (awaitAs) {
1827 if (name->num() || value->num()) {
1828 PARSE_ERROR("Value element cannot be a reference if await as is used");
1830 setIsAsync();
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;
1847 } else {
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),
1854 finallyStmt->stmt);
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)),
1863 finallyStmt->stmt);
1864 if (tryStmt->stmt) {
1865 out->stmt->setLabelScope(tryStmt->stmt->getLabelScope());
1869 void Parser::onCatch(Token &out, Token &catches, Token &className, Token &var,
1870 Token &stmt) {
1871 StatementPtr stmtList;
1872 if (catches->stmt) {
1873 stmtList = catches->stmt;
1874 } else {
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;
1898 } else {
1899 // pseudoMain
1901 onFunctionStart(name, true);
1904 Token Parser::onClosure(ClosureType type,
1905 Token* modifiers,
1906 Token& ref,
1907 Token& params,
1908 Token& cparams,
1909 Token& stmts) {
1910 Token out;
1911 Token name;
1913 Token retIgnore;
1914 auto stmt = onFunctionHelper(
1915 FunctionType::Closure,
1916 modifiers,
1917 retIgnore,
1918 ref,
1919 nullptr,
1920 params,
1921 stmts,
1922 nullptr,
1923 true
1926 ExpressionListPtr vars = dynamic_pointer_cast<ExpressionList>(cparams->exp);
1927 if (vars) {
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(
1938 ClosureExpression,
1939 type,
1940 dynamic_pointer_cast<FunctionStatement>(stmt),
1941 vars
1943 closure->getClosureFunction()->setContainingClosure(closure);
1944 out->exp = closure;
1946 return out;
1949 Token Parser::onExprForLambda(const Token& expr) {
1950 auto stmt = NEW_STMT(ReturnStatement, expr.exp);
1951 Token ret;
1952 ret.stmt = NEW_STMT0(StatementList);
1953 ret.stmt->addElement(stmt);
1954 return ret;
1957 void Parser::onClosureParam(Token &out, Token *params, Token &param,
1958 bool ref) {
1959 ExpressionPtr expList;
1960 if (params) {
1961 expList = params->exp;
1962 } else {
1963 expList = NEW_EXP0(ExpressionList);
1965 expList->addElement(NEW_EXP(ParameterExpression, TypeAnnotationPtr(),
1966 m_scanner.isHHSyntaxEnabled(), param->text(),
1967 ref, 0, ExpressionPtr(), ExpressionPtr()));
1968 out->exp = expList;
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
1981 // currently).
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) {
2018 case '?':
2019 type.typeAnnotation->setNullable();
2020 break;
2021 case '@':
2022 type.typeAnnotation->setSoft();
2023 break;
2024 case 't':
2025 type.typeAnnotation->setTuple();
2026 break;
2027 case 'f':
2028 type.typeAnnotation->setFunction();
2029 break;
2030 case 'x':
2031 type.typeAnnotation->setXHP();
2032 break;
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);
2040 out->exp = qe;
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);
2059 out->exp = expList;
2062 void Parser::onQueryBodyClause(Token &out, Token *clauses, Token &clause) {
2063 ExpressionPtr expList;
2064 if (clauses && clauses->exp) {
2065 expList = clauses->exp;
2066 } else {
2067 expList = NEW_EXP0(ExpressionList);
2069 expList->addElement(clause->exp);
2070 out->exp = expList;
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;
2105 } else {
2106 expList = NEW_EXP0(ExpressionList);
2108 expList->addElement(ordering->exp);
2109 out->exp = expList;
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) {
2137 setFalseOracle();
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;
2155 return "";
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;
2163 return "";
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;
2171 return "";
2174 bool Parser::AliasTable::isAliased(std::string alias) {
2175 if (isUseType(alias)) {
2176 return true;
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,
2196 std::string name,
2197 AliasType type) {
2198 m_aliases[alias] = (NameEntry){name, type};
2202 * To be called when we enter a fresh namespace.
2204 void Parser::AliasTable::clear() {
2205 m_aliases.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;
2261 return autoAliases;
2264 const hphp_string_imap<std::string>& Parser::getAutoAliasedClasses() {
2265 static auto autoAliases = getAutoAliasedClassesHelper();
2266 return autoAliases;
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());
2273 return;
2276 if (m_nsState == SeenNothing && !text.empty() && token != T_DECLARE &&
2277 token != ';') {
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());
2287 return;
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;
2296 pushComment();
2297 m_namespace = ns;
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());
2316 return;
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());
2323 return;
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)) {
2334 error(
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)) {
2346 error(
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()) {
2356 return name;
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)) {
2367 return 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
2377 if (cls) {
2378 return name;
2382 // Classes don't fallback to the global namespace.
2383 if (cls) {
2384 if (!strcasecmp("self", ns.c_str()) ||
2385 !strcasecmp("parent", ns.c_str())) {
2386 return ns;
2388 return nsDecl(ns);
2391 // if qualified name, prepend current namespace
2392 if (pos != string::npos) {
2393 return nsDecl(ns);
2396 // unqualified name in global namespace
2397 if (m_namespace.empty()) {
2398 return ns;
2401 if (!strcasecmp("true", ns.c_str()) ||
2402 !strcasecmp("false", ns.c_str()) ||
2403 !strcasecmp("null", ns.c_str())) {
2404 return ns;
2406 return nsDecl(ns);
2409 void Parser::invalidateGoto(TStatementPtr stmt, GotoError error) {
2410 GotoStatement *gs = (GotoStatement*) stmt;
2411 assert(gs);
2412 gs->invalidate(error);
2415 void Parser::invalidateLabel(TStatementPtr stmt) {
2416 LabelStatement *ls = (LabelStatement*) stmt;
2417 assert(ls);
2418 ls->invalidate();
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");
2433 return true;
2435 return false;
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());
2447 return;
2449 } else {
2450 m_nsAliasTable.set(key, name, AliasTable::AliasType::DEF);
2455 ///////////////////////////////////////////////////////////////////////////////