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