6faa7cbea1
Adds runtime support for non-class typehints. Typedefs are introduced using type statements, and autoloaded via a new autoload map entry. Shapes are parsed but the structure is currently thrown away and treated as arrays at runtime. This extends the NamedEntity structure to sometimes cache 'NameDefs', which are either Typedef*'s or Class*'s. VerifyParamType now has to check for typedefs if an object fails a class check, or when checking non-Object types against a non-primitive type name that isn't a class.
2452 linhas
90 KiB
Plaintext
2452 linhas
90 KiB
Plaintext
%{
|
|
#include "parser.h"
|
|
#include <util/util.h>
|
|
#include <util/logger.h>
|
|
|
|
// macros for bison
|
|
#define YYSTYPE HPHP::HPHP_PARSER_NS::Token
|
|
#define YYSTYPE_IS_TRIVIAL 1
|
|
#define YYLTYPE HPHP::Location
|
|
#define YYLTYPE_IS_TRIVIAL 1
|
|
#define YYERROR_VERBOSE
|
|
#define YYINITDEPTH 500
|
|
#define YYLEX_PARAM _p
|
|
|
|
#ifdef yyerror
|
|
#undef yyerror
|
|
#endif
|
|
#define yyerror(loc,p,msg) p->fatal(loc,msg)
|
|
|
|
#ifdef YYLLOC_DEFAULT
|
|
# undef YYLLOC_DEFAULT
|
|
#endif
|
|
#define YYRHSLOC(Rhs, K) ((Rhs)[K])
|
|
#define YYLLOC_DEFAULT(Current, Rhs, N) \
|
|
do \
|
|
if (YYID (N)) { \
|
|
(Current).first(YYRHSLOC (Rhs, 1)); \
|
|
(Current).last (YYRHSLOC (Rhs, N)); \
|
|
} else { \
|
|
(Current).line0 = (Current).line1 = YYRHSLOC (Rhs, 0).line1; \
|
|
(Current).char0 = (Current).char1 = YYRHSLOC (Rhs, 0).char1; \
|
|
} \
|
|
while (YYID (0)); \
|
|
_p->setRuleLocation(&Current);
|
|
|
|
#define YYCOPY(To, From, Count) \
|
|
do { \
|
|
YYSIZE_T yyi; \
|
|
for (yyi = 0; yyi < (Count); yyi++) { \
|
|
(To)[yyi] = (From)[yyi]; \
|
|
} \
|
|
if (From != From ## a) { \
|
|
YYSTACK_FREE (From); \
|
|
} \
|
|
} \
|
|
while (YYID (0))
|
|
|
|
#define YYCOPY_RESET(To, From, Count) \
|
|
do \
|
|
{ \
|
|
YYSIZE_T yyi; \
|
|
for (yyi = 0; yyi < (Count); yyi++) { \
|
|
(To)[yyi] = (From)[yyi]; \
|
|
(From)[yyi].reset(); \
|
|
} \
|
|
if (From != From ## a) { \
|
|
YYSTACK_FREE (From); \
|
|
} \
|
|
} \
|
|
while (YYID (0))
|
|
|
|
#define YYTOKEN_RESET(From, Count) \
|
|
do \
|
|
{ \
|
|
YYSIZE_T yyi; \
|
|
for (yyi = 0; yyi < (Count); yyi++) { \
|
|
(From)[yyi].reset(); \
|
|
} \
|
|
if (From != From ## a) { \
|
|
YYSTACK_FREE (From); \
|
|
} \
|
|
} \
|
|
while (YYID (0))
|
|
|
|
# define YYSTACK_RELOCATE_RESET(Stack_alloc, Stack) \
|
|
do \
|
|
{ \
|
|
YYSIZE_T yynewbytes; \
|
|
YYCOPY_RESET (&yyptr->Stack_alloc, Stack, yysize); \
|
|
Stack = &yyptr->Stack_alloc; \
|
|
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
|
|
yyptr += yynewbytes / sizeof (*yyptr); \
|
|
} \
|
|
while (YYID (0))
|
|
|
|
#define YYSTACK_CLEANUP \
|
|
YYTOKEN_RESET (yyvs, yystacksize); \
|
|
if (yyvs != yyvsa) { \
|
|
YYSTACK_FREE (yyvs); \
|
|
} \
|
|
if (yyls != yylsa) { \
|
|
YYSTACK_FREE (yyls); \
|
|
} \
|
|
|
|
|
|
// macros for rules
|
|
#define BEXP(e...) _p->onBinaryOpExp(e);
|
|
#define UEXP(e...) _p->onUnaryOpExp(e);
|
|
|
|
using namespace HPHP::HPHP_PARSER_NS;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// helpers
|
|
|
|
static void scalar_num(Parser *_p, Token &out, const char *num) {
|
|
Token t;
|
|
t.setText(num);
|
|
_p->onScalar(out, T_LNUMBER, t);
|
|
}
|
|
|
|
static void scalar_num(Parser *_p, Token &out, int num) {
|
|
Token t;
|
|
t.setText(boost::lexical_cast<std::string>(num));
|
|
_p->onScalar(out, T_LNUMBER, t);
|
|
}
|
|
|
|
static void scalar_null(Parser *_p, Token &out) {
|
|
Token tnull; tnull.setText("null");
|
|
_p->onConstantValue(out, tnull);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// converting constant declartion to "define(name, value);"
|
|
|
|
static void on_constant(Parser *_p, Token &out, Token *stmts,
|
|
Token &name, Token &value) {
|
|
Token sname; _p->onScalar(sname, T_CONSTANT_ENCAPSED_STRING, name);
|
|
|
|
Token fname; fname.setText("define");
|
|
Token params1; _p->onCallParam(params1, NULL, sname, 0);
|
|
Token params2; _p->onCallParam(params2, ¶ms1, value, 0);
|
|
Token call; _p->onCall(call, 0, fname, params2, 0);
|
|
Token scall; _p->onExpStatement(scall, call);
|
|
|
|
Token stmts0;
|
|
if (!stmts) {
|
|
_p->onStatementListStart(stmts0);
|
|
stmts = &stmts0;
|
|
}
|
|
_p->addStatement(out, *stmts, scall);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// continuation transformations
|
|
|
|
void prepare_generator(Parser *_p, Token &stmt, Token ¶ms) {
|
|
// 1. add prologue and epilogue to original body and store it back to "stmt"
|
|
{
|
|
// hphp_unpack_continuation()
|
|
Token empty;
|
|
Token cname; cname.setText("hphp_unpack_continuation");
|
|
Token unpack; _p->onCall(unpack, false, cname, empty, NULL, true);
|
|
Token sunpack; _p->onExpStatement(sunpack, unpack);
|
|
|
|
Token stmts0; _p->onStatementListStart(stmts0);
|
|
Token stmts1; _p->addStatement(stmts1, stmts0, sunpack);
|
|
Token stmts2; _p->addStatement(stmts2, stmts1, stmt);
|
|
|
|
stmt.reset();
|
|
_p->finishStatement(stmt, stmts2); stmt = 1;
|
|
}
|
|
|
|
// 2. prepare a single continuation parameter list and store it in "params"
|
|
{
|
|
Token type; type.setText("Continuation");
|
|
Token var; var.setText(CONTINUATION_OBJECT_NAME);
|
|
params.reset();
|
|
type.reset();
|
|
_p->onParam(params, NULL, type, var, false, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
// create a generator function with original name and parameters
|
|
void create_generator(Parser *_p, Token &out, Token ¶ms,
|
|
Token &name, const std::string &closureName,
|
|
const char *clsname, Token *modifiers, bool getArgs,
|
|
Token &origGenFunc, bool isHhvm, Token *attr) {
|
|
_p->pushFuncLocation();
|
|
if (clsname) {
|
|
_p->onMethodStart(name, *modifiers, false);
|
|
} else {
|
|
_p->onFunctionStart(name, false);
|
|
}
|
|
|
|
Token scont;
|
|
{
|
|
Token cname;
|
|
if (isHhvm) {
|
|
Token cn; cn.setText(clsname ? "__CLASS__" : "");
|
|
_p->onScalar(
|
|
cname,
|
|
clsname ? T_CLASS_C : T_CONSTANT_ENCAPSED_STRING,
|
|
cn);
|
|
} else {
|
|
Token cn; cn.setText(clsname ? clsname : "");
|
|
_p->onScalar(cname, T_CONSTANT_ENCAPSED_STRING, cn);
|
|
}
|
|
|
|
Token fn; fn.setText(closureName);
|
|
Token fname; _p->onScalar(fname, T_CONSTANT_ENCAPSED_STRING, fn);
|
|
|
|
Token ofn; ofn.setText(clsname ? "__METHOD__" : "__FUNCTION__");
|
|
Token oname; _p->onScalar(oname, clsname ? T_METHOD_C : T_FUNC_C, ofn);
|
|
|
|
Token param1; _p->onCallParam(param1, NULL, cname, false);
|
|
_p->onCallParam(param1, ¶m1, fname, false);
|
|
_p->onCallParam(param1, ¶m1, oname, false);
|
|
|
|
if (getArgs) {
|
|
Token cname; cname.setText("func_get_args");
|
|
Token empty;
|
|
Token call; _p->onCall(call, false, cname, empty, NULL);
|
|
_p->onCallParam(param1, ¶m1, call, false);
|
|
}
|
|
|
|
Token cname0; cname0.setText("hphp_create_continuation");
|
|
Token call; _p->onCall(call, false, cname0, param1, NULL, true);
|
|
Token ret; _p->onReturn(ret, &call);
|
|
|
|
Token stmts0; _p->onStatementListStart(stmts0);
|
|
Token stmts1; _p->addStatement(stmts1, stmts0, ret);
|
|
_p->finishStatement(scont, stmts1); scont = 1;
|
|
}
|
|
|
|
Token ret, ref;
|
|
ret.setText("Continuation");
|
|
ret.setCheck();
|
|
if (clsname) {
|
|
Token closure;
|
|
_p->onMethod(closure, *modifiers, ret, ref, name, params, scont, attr);
|
|
origGenFunc = closure;
|
|
|
|
Token stmts0; _p->onStatementListStart(stmts0);
|
|
Token stmts1; _p->addStatement(stmts1, stmts0, closure);
|
|
Token stmts2; _p->addStatement(stmts2, stmts1, out);
|
|
_p->finishStatement(out, stmts2); out = 1;
|
|
} else {
|
|
out.reset();
|
|
_p->onFunction(out, modifiers, ret, ref, name, params, scont, attr);
|
|
origGenFunc = out;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void user_attribute_check(Parser *_p) {
|
|
if (!_p->enableHipHopSyntax()) {
|
|
HPHP_PARSER_ERROR("User attributes are not enabled", _p);
|
|
}
|
|
}
|
|
|
|
static void finally_statement(Parser *_p) {
|
|
if (!_p->enableFinallyStatement()) {
|
|
HPHP_PARSER_ERROR("Finally statement is not enabled", _p);
|
|
}
|
|
}
|
|
|
|
static void constant_ae(Parser *_p, Token &out, Token &value) {
|
|
const std::string& valueStr = value.text();
|
|
if (valueStr.size() < 3 || valueStr.size() > 5 ||
|
|
(strcasecmp("true", valueStr.c_str()) != 0 &&
|
|
strcasecmp("false", valueStr.c_str()) != 0 &&
|
|
strcasecmp("null", valueStr.c_str()) != 0 &&
|
|
strcasecmp("inf", valueStr.c_str()) != 0 &&
|
|
strcasecmp("nan", valueStr.c_str()) != 0)) {
|
|
HPHP_PARSER_ERROR("User-defined constants are not allowed in user "
|
|
"attribute expressions", _p);
|
|
}
|
|
_p->onConstantValue(out, value);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* XHP functions: They are defined here, so different parsers don't have to
|
|
* handle XHP rules at all.
|
|
*/
|
|
|
|
static void xhp_tag(Parser *_p, Token &out, Token &label, Token &body) {
|
|
if (!_p->enableXHP()) {
|
|
HPHP_PARSER_ERROR("XHP: not enabled", _p);
|
|
}
|
|
|
|
if (!body.text().empty() && body.text() != label.text()) {
|
|
HPHP_PARSER_ERROR("XHP: mismatched tag: '%s' not the same as '%s'",
|
|
_p, body.text().c_str(), label.text().c_str());
|
|
}
|
|
|
|
label.xhpLabel();
|
|
Token name; _p->onName(name, label, Parser::StringName);
|
|
_p->onNewObject(out, name, body);
|
|
}
|
|
|
|
static void xhp_attribute(Parser *_p, Token &out, Token &type, Token &label,
|
|
Token &def, Token &req) {
|
|
/**
|
|
* The basic builtin types "bool", "int", "double", and "string" all map to
|
|
* T_STRING in the parser, and the parser uses always uses type code 5 for
|
|
* T_STRING. However, XHP uses different type codes for these basic builtin
|
|
* types, so we need to fix up the type code here to make XHP happy.
|
|
*/
|
|
if (type.num() == 5 && type.text().size() >= 3 && type.text().size() <= 7) {
|
|
switch (type.text()[0]) {
|
|
case 'b':
|
|
if ((type.text().size() == 4 &&
|
|
strcasecmp(type.text().c_str(), "bool") == 0) ||
|
|
(type.text().size() == 7 &&
|
|
strcasecmp(type.text().c_str(), "boolean") == 0)) {
|
|
type.reset();
|
|
type.setNum(2);
|
|
}
|
|
break;
|
|
case 'd':
|
|
if (type.text().size() == 6 &&
|
|
strcasecmp(type.text().c_str(), "double") == 0) {
|
|
type.reset();
|
|
type.setNum(8);
|
|
}
|
|
break;
|
|
case 'f':
|
|
if (type.text().size() == 5 &&
|
|
strcasecmp(type.text().c_str(), "float") == 0) {
|
|
type.reset();
|
|
type.setNum(8);
|
|
}
|
|
break;
|
|
case 'i':
|
|
if ((type.text().size() == 3 &&
|
|
strcasecmp(type.text().c_str(), "int") == 0) ||
|
|
(type.text().size() == 7 &&
|
|
strcasecmp(type.text().c_str(), "integer") == 0)) {
|
|
type.reset();
|
|
type.setNum(3);
|
|
}
|
|
break;
|
|
case 'r':
|
|
if (type.text().size() == 4 &&
|
|
strcasecmp(type.text().c_str(), "real") == 0) {
|
|
type.reset();
|
|
type.setNum(8);
|
|
}
|
|
break;
|
|
case 's':
|
|
if (type.text().size() == 6 &&
|
|
strcasecmp(type.text().c_str(), "string") == 0) {
|
|
type.reset();
|
|
type.setNum(1);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Token num; scalar_num(_p, num, type.num());
|
|
Token arr1; _p->onArrayPair(arr1, 0, 0, num, 0);
|
|
|
|
Token arr2;
|
|
switch (type.num()) {
|
|
case 5: /* class */ {
|
|
Token cls; _p->onScalar(cls, T_CONSTANT_ENCAPSED_STRING, type);
|
|
_p->onArrayPair(arr2, &arr1, 0, cls, 0);
|
|
break;
|
|
}
|
|
case 7: /* enum */ {
|
|
Token arr; _p->onArray(arr, type);
|
|
_p->onArrayPair(arr2, &arr1, 0, arr, 0);
|
|
break;
|
|
}
|
|
default: {
|
|
Token tnull; scalar_null(_p, tnull);
|
|
_p->onArrayPair(arr2, &arr1, 0, tnull, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Token arr3; _p->onArrayPair(arr3, &arr2, 0, def, 0);
|
|
Token arr4; _p->onArrayPair(arr4, &arr3, 0, req, 0);
|
|
_p->onArray(out, arr4);
|
|
out.setText(label);
|
|
}
|
|
|
|
static void xhp_attribute_list(Parser *_p, Token &out, Token *list,
|
|
Token &decl) {
|
|
if (decl.num() == 0) {
|
|
decl.xhpLabel();
|
|
if (list) {
|
|
out = *list;
|
|
out.setText(list->text() + ":" + decl.text()); // avoiding vector<string>
|
|
} else {
|
|
out.setText(decl);
|
|
}
|
|
} else {
|
|
Token name; _p->onScalar(name, T_CONSTANT_ENCAPSED_STRING, decl);
|
|
_p->onArrayPair(out, list, &name, decl, 0);
|
|
if (list) {
|
|
out.setText(list->text());
|
|
} else {
|
|
out.setText("");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void xhp_attribute_stmt(Parser *_p, Token &out, Token &attributes) {
|
|
if (!_p->enableXHP()) {
|
|
HPHP_PARSER_ERROR("XHP: not enabled", _p);
|
|
}
|
|
|
|
Token modifiers;
|
|
Token fname; fname.setText("__xhpAttributeDeclaration");
|
|
{
|
|
Token m;
|
|
Token m1; m1.setNum(T_PROTECTED); _p->onMemberModifier(m, NULL, m1);
|
|
Token m2; m2.setNum(T_STATIC); _p->onMemberModifier(modifiers, &m, m2);
|
|
}
|
|
_p->pushFuncLocation();
|
|
_p->onMethodStart(fname, modifiers);
|
|
|
|
std::vector<std::string> classes;
|
|
HPHP::Util::split(':', attributes.text().c_str(), classes, true);
|
|
Token arrAttributes; _p->onArray(arrAttributes, attributes);
|
|
|
|
Token dummy;
|
|
|
|
Token stmts0;
|
|
{
|
|
_p->onStatementListStart(stmts0);
|
|
}
|
|
Token stmts1;
|
|
{
|
|
// static $_ = -1;
|
|
Token one; scalar_num(_p, one, "1");
|
|
Token mone; UEXP(mone, one, '-', 1);
|
|
Token var; var.set(T_VARIABLE, "_");
|
|
Token decl; _p->onStaticVariable(decl, 0, var, &mone);
|
|
Token sdecl; _p->onStatic(sdecl, decl);
|
|
_p->addStatement(stmts1, stmts0, sdecl);
|
|
}
|
|
Token stmts2;
|
|
{
|
|
// if ($_ === -1) {
|
|
// $_ = array_merge(parent::__xhpAttributeDeclaration(),
|
|
// attributes);
|
|
// }
|
|
Token parent; parent.set(T_STRING, "parent");
|
|
Token cls; _p->onName(cls, parent, Parser::StringName);
|
|
Token fname; fname.setText("__xhpAttributeDeclaration");
|
|
Token param1; _p->onCall(param1, 0, fname, dummy, &cls);
|
|
Token params1; _p->onCallParam(params1, NULL, param1, 0);
|
|
|
|
for (unsigned int i = 0; i < classes.size(); i++) {
|
|
Token parent; parent.set(T_STRING, classes[i]);
|
|
Token cls; _p->onName(cls, parent, Parser::StringName);
|
|
Token fname; fname.setText("__xhpAttributeDeclaration");
|
|
Token param; _p->onCall(param, 0, fname, dummy, &cls);
|
|
|
|
Token params; _p->onCallParam(params, ¶ms1, param, 0);
|
|
params1 = params;
|
|
}
|
|
|
|
Token params2; _p->onCallParam(params2, ¶ms1, arrAttributes, 0);
|
|
|
|
Token name; name.set(T_STRING, "array_merge");
|
|
Token call; _p->onCall(call, 0, name, params2, NULL);
|
|
Token tvar; tvar.set(T_VARIABLE, "_");
|
|
Token var; _p->onSimpleVariable(var, tvar);
|
|
Token assign; _p->onAssign(assign, var, call, 0);
|
|
Token exp; _p->onExpStatement(exp, assign);
|
|
Token block; _p->onBlock(block, exp);
|
|
|
|
Token tvar2; tvar2.set(T_VARIABLE, "_");
|
|
Token var2; _p->onSimpleVariable(var2, tvar2);
|
|
Token one; scalar_num(_p, one, "1");
|
|
Token mone; UEXP(mone, one, '-', 1);
|
|
Token cond; BEXP(cond, var2, mone, T_IS_IDENTICAL);
|
|
Token dummy1, dummy2;
|
|
Token sif; _p->onIf(sif, cond, block, dummy1, dummy2);
|
|
_p->addStatement(stmts2, stmts1, sif);
|
|
}
|
|
Token stmts3;
|
|
{
|
|
// return $_;
|
|
Token tvar; tvar.set(T_VARIABLE, "_");
|
|
Token var; _p->onSimpleVariable(var, tvar);
|
|
Token ret; _p->onReturn(ret, &var);
|
|
_p->addStatement(stmts3, stmts2, ret);
|
|
}
|
|
Token stmt;
|
|
{
|
|
_p->finishStatement(stmt, stmts3);
|
|
stmt = 1;
|
|
}
|
|
{
|
|
Token params, ret, ref; ref = 1;
|
|
_p->onMethod(out, modifiers, ret, ref, fname, params, stmt, 0, false);
|
|
}
|
|
}
|
|
|
|
static void xhp_collect_attributes(Parser *_p, Token &out, Token &stmts) {
|
|
Token *attr = _p->xhpGetAttributes();
|
|
if (attr) {
|
|
Token stmt;
|
|
xhp_attribute_stmt(_p, stmt, *attr);
|
|
_p->onClassStatement(out, stmts, stmt);
|
|
} else {
|
|
out = stmts;
|
|
}
|
|
}
|
|
|
|
static void xhp_category_stmt(Parser *_p, Token &out, Token &categories) {
|
|
if (!_p->enableXHP()) {
|
|
HPHP_PARSER_ERROR("XHP: not enabled", _p);
|
|
}
|
|
|
|
Token fname; fname.setText("__xhpCategoryDeclaration");
|
|
Token m1; m1.setNum(T_PROTECTED);
|
|
Token modifiers; _p->onMemberModifier(modifiers, 0, m1);
|
|
_p->pushFuncLocation();
|
|
_p->onMethodStart(fname, modifiers);
|
|
|
|
Token stmts0;
|
|
{
|
|
_p->onStatementListStart(stmts0);
|
|
}
|
|
Token stmts1;
|
|
{
|
|
// static $_ = categories;
|
|
Token arr; _p->onArray(arr, categories);
|
|
Token var; var.set(T_VARIABLE, "_");
|
|
Token decl; _p->onStaticVariable(decl, 0, var, &arr);
|
|
Token sdecl; _p->onStatic(sdecl, decl);
|
|
_p->addStatement(stmts1, stmts0, sdecl);
|
|
}
|
|
Token stmts2;
|
|
{
|
|
// return $_;
|
|
Token tvar; tvar.set(T_VARIABLE, "_");
|
|
Token var; _p->onSimpleVariable(var, tvar);
|
|
Token ret; _p->onReturn(ret, &var);
|
|
_p->addStatement(stmts2, stmts1, ret);
|
|
}
|
|
Token stmt;
|
|
{
|
|
_p->finishStatement(stmt, stmts2);
|
|
stmt = 1;
|
|
}
|
|
{
|
|
Token params, ret, ref; ref = 1;
|
|
_p->onMethod(out, modifiers, ret, ref, fname, params, stmt, 0, false);
|
|
}
|
|
}
|
|
|
|
static void xhp_children_decl_tag(Parser *_p, Token &arr, Token &tag) {
|
|
Token num; scalar_num(_p, num, tag.num());
|
|
Token arr1; _p->onArrayPair(arr1, &arr, 0, num, 0);
|
|
|
|
Token name;
|
|
if (tag.num() == 3 || tag.num() == 4) {
|
|
_p->onScalar(name, T_CONSTANT_ENCAPSED_STRING, tag);
|
|
} else if (tag.num() >= 0) {
|
|
scalar_null(_p, name);
|
|
} else {
|
|
HPHP_PARSER_ERROR("XHP: unknown children declaration", _p);
|
|
}
|
|
Token arr2; _p->onArrayPair(arr2, &arr1, 0, name, 0);
|
|
arr = arr2;
|
|
}
|
|
|
|
static void xhp_children_decl(Parser *_p, Token &out, Token &op1, int op,
|
|
Token *op2) {
|
|
Token num; scalar_num(_p, num, op);
|
|
Token arr; _p->onArrayPair(arr, 0, 0, num, 0);
|
|
|
|
if (op2) {
|
|
Token arr1; _p->onArrayPair(arr1, &arr, 0, op1, 0);
|
|
Token arr2; _p->onArrayPair(arr2, &arr1, 0, *op2, 0);
|
|
_p->onArray(out, arr2);
|
|
} else {
|
|
xhp_children_decl_tag(_p, arr, op1);
|
|
_p->onArray(out, arr);
|
|
}
|
|
}
|
|
|
|
static void xhp_children_paren(Parser *_p, Token &out, Token exp, int op) {
|
|
Token num; scalar_num(_p, num, op);
|
|
Token arr1; _p->onArrayPair(arr1, 0, 0, num, 0);
|
|
|
|
Token num5; scalar_num(_p, num5, 5);
|
|
Token arr2; _p->onArrayPair(arr2, &arr1, 0, num5, 0);
|
|
|
|
Token arr3; _p->onArrayPair(arr3, &arr2, 0, exp, 0);
|
|
_p->onArray(out, arr3);
|
|
}
|
|
|
|
static void xhp_children_stmt(Parser *_p, Token &out, Token &children) {
|
|
if (!_p->enableXHP()) {
|
|
HPHP_PARSER_ERROR("XHP: not enabled", _p);
|
|
}
|
|
|
|
Token fname; fname.setText("__xhpChildrenDeclaration");
|
|
Token m1; m1.setNum(T_PROTECTED);
|
|
Token modifiers; _p->onMemberModifier(modifiers, 0, m1);
|
|
_p->pushFuncLocation();
|
|
_p->onMethodStart(fname, modifiers);
|
|
|
|
Token stmts0;
|
|
{
|
|
_p->onStatementListStart(stmts0);
|
|
}
|
|
Token stmts1;
|
|
{
|
|
// static $_ = children;
|
|
Token arr;
|
|
if (children.num() == 2) {
|
|
arr = children;
|
|
} else if (children.num() >= 0) {
|
|
scalar_num(_p, arr, children.num());
|
|
} else {
|
|
HPHP_PARSER_ERROR("XHP: XHP unknown children declaration", _p);
|
|
}
|
|
Token var; var.set(T_VARIABLE, "_");
|
|
Token decl; _p->onStaticVariable(decl, 0, var, &arr);
|
|
Token sdecl; _p->onStatic(sdecl, decl);
|
|
_p->addStatement(stmts1, stmts0, sdecl);
|
|
}
|
|
Token stmts2;
|
|
{
|
|
// return $_;
|
|
Token tvar; tvar.set(T_VARIABLE, "_");
|
|
Token var; _p->onSimpleVariable(var, tvar);
|
|
Token ret; _p->onReturn(ret, &var);
|
|
_p->addStatement(stmts2, stmts1, ret);
|
|
}
|
|
Token stmt;
|
|
{
|
|
_p->finishStatement(stmt, stmts2);
|
|
stmt = 1;
|
|
}
|
|
{
|
|
Token params, ret, ref; ref = 1;
|
|
_p->onMethod(out, modifiers, ret, ref, fname, params, stmt, 0, false);
|
|
}
|
|
}
|
|
|
|
/* This is called from strict-mode productions (sm_*) to throw an
|
|
* error if we're not in strict mode */
|
|
static void only_in_strict_mode(Parser *_p) {
|
|
if (!_p->scanner().isStrictMode()) {
|
|
HPHP_PARSER_ERROR("Syntax only allowed in strict mode", _p);
|
|
}
|
|
}
|
|
|
|
static void only_in_hphp_syntax(Parser *_p) {
|
|
if (!_p->enableHipHopSyntax()) {
|
|
HPHP_PARSER_ERROR("Syntax only allowed with -v Eval.EnableHipHopSyntax=true", _p);
|
|
}
|
|
}
|
|
|
|
// Shapes may not have leading integers in key names, considered as a
|
|
// parse time error. This is because at runtime they are currently
|
|
// hphp arrays, which will treat leading integer keys as numbers.
|
|
static void validate_shape_keyname(Token& tok, Parser* _p) {
|
|
if (tok.text().empty()) {
|
|
HPHP_PARSER_ERROR("Shape key names may not be empty", _p);
|
|
}
|
|
if (isdigit(tok.text()[0])) {
|
|
HPHP_PARSER_ERROR("Shape key names may not start with integers", _p);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int yylex(YYSTYPE *token, HPHP::Location *loc, Parser *_p) {
|
|
return _p->scan(token, loc);
|
|
}
|
|
%}
|
|
|
|
%expect 2
|
|
%define api.pure
|
|
%parse-param {HPHP::HPHP_PARSER_NS::Parser *_p}
|
|
|
|
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
|
|
%left ','
|
|
%left T_LOGICAL_OR
|
|
%left T_LOGICAL_XOR
|
|
%left T_LOGICAL_AND
|
|
%right T_PRINT
|
|
%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL
|
|
%left '?' ':'
|
|
%left T_BOOLEAN_OR
|
|
%left T_BOOLEAN_AND
|
|
%left '|'
|
|
%left '^'
|
|
%left '&'
|
|
%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
|
|
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
|
|
%left T_SL T_SR
|
|
%left '+' '-' '.'
|
|
%left '*' '/' '%'
|
|
%right '!'
|
|
%nonassoc T_INSTANCEOF
|
|
%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
|
|
%right '['
|
|
|
|
%nonassoc T_NEW T_CLONE
|
|
%token T_EXIT
|
|
%token T_IF
|
|
%left T_ELSEIF
|
|
%left T_ELSE
|
|
%left T_ENDIF
|
|
%token T_LNUMBER
|
|
%token T_DNUMBER
|
|
%token T_STRING
|
|
%token T_STRING_VARNAME
|
|
%token T_VARIABLE
|
|
%token T_NUM_STRING
|
|
%token T_INLINE_HTML
|
|
%token T_CHARACTER
|
|
%token T_BAD_CHARACTER
|
|
%token T_ENCAPSED_AND_WHITESPACE
|
|
%token T_CONSTANT_ENCAPSED_STRING
|
|
%token T_ECHO
|
|
%token T_DO
|
|
%token T_WHILE
|
|
%token T_ENDWHILE
|
|
%token T_FOR
|
|
%token T_ENDFOR
|
|
%token T_FOREACH
|
|
%token T_ENDFOREACH
|
|
%token T_DECLARE
|
|
%token T_ENDDECLARE
|
|
%token T_AS
|
|
%token T_SWITCH
|
|
%token T_ENDSWITCH
|
|
%token T_CASE
|
|
%token T_DEFAULT
|
|
%token T_BREAK
|
|
%token T_GOTO
|
|
%token T_CONTINUE
|
|
%token T_FUNCTION
|
|
%token T_CONST
|
|
%token T_RETURN
|
|
%token T_TRY
|
|
%token T_CATCH
|
|
%token T_THROW
|
|
%token T_USE
|
|
%token T_GLOBAL
|
|
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
|
|
%token T_VAR
|
|
%token T_UNSET
|
|
%token T_ISSET
|
|
%token T_EMPTY
|
|
%token T_HALT_COMPILER
|
|
%token T_CLASS
|
|
%token T_INTERFACE
|
|
%token T_EXTENDS
|
|
%token T_IMPLEMENTS
|
|
%token T_OBJECT_OPERATOR
|
|
%token T_DOUBLE_ARROW
|
|
%token T_LIST
|
|
%token T_ARRAY
|
|
%token T_CLASS_C
|
|
%token T_METHOD_C
|
|
%token T_FUNC_C
|
|
%token T_LINE
|
|
%token T_FILE
|
|
%token T_COMMENT
|
|
%token T_DOC_COMMENT
|
|
%token T_OPEN_TAG
|
|
%token T_OPEN_TAG_WITH_ECHO
|
|
%token T_CLOSE_TAG
|
|
%token T_WHITESPACE
|
|
%token T_START_HEREDOC
|
|
%token T_END_HEREDOC
|
|
%token T_DOLLAR_OPEN_CURLY_BRACES
|
|
%token T_CURLY_OPEN
|
|
%token T_PAAMAYIM_NEKUDOTAYIM
|
|
%token T_NAMESPACE
|
|
%token T_NS_C
|
|
%token T_DIR
|
|
%token T_NS_SEPARATOR
|
|
|
|
%token T_YIELD
|
|
|
|
%token T_XHP_LABEL
|
|
%token T_XHP_TEXT
|
|
%token T_XHP_ATTRIBUTE
|
|
%token T_XHP_CATEGORY
|
|
%token T_XHP_CATEGORY_LABEL
|
|
%token T_XHP_CHILDREN
|
|
%token T_XHP_ENUM
|
|
%token T_XHP_REQUIRED
|
|
|
|
%token T_TRAIT
|
|
%token T_INSTEADOF
|
|
%token T_TRAIT_C
|
|
|
|
%token T_VARARG
|
|
%token T_STRICT_ERROR
|
|
%token T_FINALLY
|
|
|
|
%token T_XHP_TAG_LT
|
|
%token T_XHP_TAG_GT
|
|
%token T_TYPELIST_LT
|
|
%token T_TYPELIST_GT
|
|
%token T_UNRESOLVED_LT
|
|
|
|
%token T_COLLECTION
|
|
%token T_SHAPE
|
|
%token T_TYPE
|
|
%token T_UNRESOLVED_TYPE
|
|
|
|
%%
|
|
|
|
start:
|
|
top_statement_list { _p->popLabelInfo();
|
|
_p->saveParseTree($$);}
|
|
;
|
|
|
|
top_statement_list:
|
|
top_statement_list
|
|
top_statement { _p->addStatement($$,$1,$2);}
|
|
| { _p->onStatementListStart($$);}
|
|
;
|
|
top_statement:
|
|
statement { _p->nns($1.num() == T_DECLARE);
|
|
$$ = $1;}
|
|
| function_declaration_statement { _p->nns(); $$ = $1;}
|
|
| class_declaration_statement { _p->nns(); $$ = $1;}
|
|
| trait_declaration_statement { _p->nns(); $$ = $1;}
|
|
| sm_typedef_statement { $$ = $1; }
|
|
| T_HALT_COMPILER '(' ')' ';' { $$.reset();}
|
|
| T_NAMESPACE namespace_name ';' { _p->onNamespaceStart($2.text());
|
|
$$.reset();}
|
|
| T_NAMESPACE namespace_name '{' { _p->onNamespaceStart($2.text());}
|
|
top_statement_list '}' { _p->onNamespaceEnd(); $$ = $5;}
|
|
| T_NAMESPACE '{' { _p->onNamespaceStart("");}
|
|
top_statement_list '}' { _p->onNamespaceEnd(); $$ = $4;}
|
|
| T_USE use_declarations ';' { _p->nns(); $$.reset();}
|
|
| constant_declaration ';' { _p->nns();
|
|
_p->finishStatement($$, $1); $$ = 1;}
|
|
;
|
|
|
|
ident:
|
|
T_STRING { $$ = $1;}
|
|
| T_XHP_ATTRIBUTE { $$ = $1;}
|
|
| T_XHP_CATEGORY { $$ = $1;}
|
|
| T_XHP_CHILDREN { $$ = $1;}
|
|
| T_XHP_REQUIRED { $$ = $1;}
|
|
| T_XHP_ENUM { $$ = $1;}
|
|
;
|
|
|
|
use_declarations:
|
|
use_declarations ','
|
|
use_declaration { }
|
|
| use_declaration { }
|
|
;
|
|
use_declaration:
|
|
namespace_name { _p->onUse($1.text(),"");}
|
|
| T_NS_SEPARATOR namespace_name { _p->onUse($2.text(),"");}
|
|
| namespace_name T_AS ident { _p->onUse($1.text(),$3.text());}
|
|
| T_NS_SEPARATOR namespace_name
|
|
T_AS ident { _p->onUse($2.text(),$4.text());}
|
|
;
|
|
|
|
namespace_name:
|
|
ident { $$ = $1;}
|
|
| namespace_name T_NS_SEPARATOR
|
|
ident { $$ = $1 + $2 + $3;}
|
|
;
|
|
namespace_string_base:
|
|
namespace_name { $$ = $1; $$ = 1;}
|
|
| T_NS_SEPARATOR namespace_name { $$ = $2; $$ = 0;}
|
|
| T_NAMESPACE T_NS_SEPARATOR
|
|
namespace_name { $$.setText(_p->nsDecl($3.text()));
|
|
$$ = 0;}
|
|
;
|
|
namespace_string:
|
|
namespace_string_base { if ($1.num())
|
|
$1.setText(_p->resolve($1.text(),0));
|
|
$$ = $1;}
|
|
;
|
|
namespace_string_typeargs:
|
|
namespace_string_base
|
|
sm_typeargs_opt { if ($1.num())
|
|
$1.setText(_p->resolve($1.text(),0));
|
|
$$ = $1;}
|
|
;
|
|
class_namespace_string_typeargs:
|
|
namespace_string_base
|
|
sm_typeargs_opt { if ($1.num())
|
|
$1.setText(_p->resolve($1.text(),1));
|
|
$$ = $1;}
|
|
;
|
|
constant_declaration:
|
|
constant_declaration ','
|
|
sm_name_with_type '=' static_scalar { $3.setText(_p->nsDecl($3.text()));
|
|
on_constant(_p,$$,&$1,$3,$5);}
|
|
| T_CONST sm_name_with_type '=' static_scalar { $2.setText(_p->nsDecl($2.text()));
|
|
on_constant(_p,$$, 0,$2,$4);}
|
|
;
|
|
|
|
inner_statement_list:
|
|
inner_statement_list
|
|
inner_statement { _p->addStatement($$,$1,$2);}
|
|
| { _p->onStatementListStart($$);}
|
|
;
|
|
inner_statement:
|
|
statement { $$ = $1;}
|
|
| function_declaration_statement { $$ = $1;}
|
|
| class_declaration_statement { $$ = $1;}
|
|
| trait_declaration_statement { $$ = $1;}
|
|
;
|
|
statement:
|
|
'{' inner_statement_list '}' { _p->onBlock($$, $2);}
|
|
| T_IF parenthesis_expr
|
|
statement
|
|
elseif_list
|
|
else_single { _p->onIf($$,$2,$3,$4,$5);}
|
|
| T_IF parenthesis_expr ':'
|
|
inner_statement_list
|
|
new_elseif_list
|
|
new_else_single
|
|
T_ENDIF ';' { _p->onIf($$,$2,$4,$5,$6);}
|
|
| T_WHILE parenthesis_expr { _p->pushLabelScope();}
|
|
while_statement { _p->popLabelScope();
|
|
_p->onWhile($$,$2,$4);}
|
|
|
|
| T_DO { _p->pushLabelScope();}
|
|
statement T_WHILE parenthesis_expr
|
|
';' { _p->popLabelScope();
|
|
_p->onDo($$,$3,$5);}
|
|
| T_FOR '(' for_expr ';'
|
|
for_expr ';' for_expr ')' { _p->pushLabelScope();}
|
|
for_statement { _p->popLabelScope();
|
|
_p->onFor($$,$3,$5,$7,$10);}
|
|
| T_SWITCH parenthesis_expr { _p->pushLabelScope();}
|
|
switch_case_list { _p->popLabelScope();
|
|
_p->onSwitch($$,$2,$4);}
|
|
| T_BREAK ';' { _p->onBreak($$, NULL);}
|
|
| T_BREAK expr ';' { _p->onBreak($$, &$2);}
|
|
| T_CONTINUE ';' { _p->onContinue($$, NULL);}
|
|
| T_CONTINUE expr ';' { _p->onContinue($$, &$2);}
|
|
| T_RETURN ';' { _p->onReturn($$, NULL);}
|
|
| T_RETURN expr ';' { _p->onReturn($$, &$2);}
|
|
| T_YIELD T_BREAK ';' { _p->onYieldBreak($$);}
|
|
| T_GLOBAL global_var_list ';' { _p->onGlobal($$, $2);}
|
|
| T_STATIC static_var_list ';' { _p->onStatic($$, $2);}
|
|
| T_ECHO expr_list ';' { _p->onEcho($$, $2, 0);}
|
|
| T_UNSET '(' variable_list ')' ';' { _p->onUnset($$, $3);}
|
|
| ';' { $$.reset();}
|
|
| T_INLINE_HTML { _p->onEcho($$, $1, 1);}
|
|
| T_FOREACH '(' expr
|
|
T_AS foreach_variable
|
|
foreach_optional_arg ')' { _p->pushLabelScope();}
|
|
foreach_statement { _p->popLabelScope();
|
|
_p->onForEach($$,$3,$5,$6,$9);}
|
|
| T_DECLARE '(' declare_list ')'
|
|
declare_statement { _p->onBlock($$, $5); $$ = T_DECLARE;}
|
|
| T_TRY '{'
|
|
inner_statement_list '}'
|
|
T_CATCH '('
|
|
fully_qualified_class_name
|
|
T_VARIABLE ')' '{'
|
|
inner_statement_list '}'
|
|
additional_catches
|
|
optional_finally { _p->onTry($$,$3,$7,$8,$11,$13,$14);}
|
|
| T_TRY '{'
|
|
inner_statement_list '}'
|
|
finally { _p->onTry($$, $3, $5);}
|
|
| T_THROW expr ';' { _p->onThrow($$, $2);}
|
|
| T_GOTO ident ';' { _p->onGoto($$, $2, true);
|
|
_p->addGoto($2.text(),
|
|
_p->getLocation(),
|
|
&$$); }
|
|
| expr ';' { _p->onExpStatement($$, $1);}
|
|
| yield_expr ';' { _p->onExpStatement($$, $1);}
|
|
| yield_assign_expr ';' { _p->onExpStatement($$, $1);}
|
|
| yield_list_assign_expr ';' { _p->onExpStatement($$, $1);}
|
|
| ident ':' { _p->onLabel($$, $1);
|
|
_p->addLabel($1.text(),
|
|
_p->getLocation(),
|
|
&$$); }
|
|
;
|
|
|
|
additional_catches:
|
|
additional_catches
|
|
T_CATCH '('
|
|
fully_qualified_class_name
|
|
T_VARIABLE ')'
|
|
'{'
|
|
inner_statement_list '}' { _p->onCatch($$, $1, $4, $5, $8);}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
finally:
|
|
{ finally_statement(_p);}
|
|
T_FINALLY '{'
|
|
inner_statement_list '}' { _p->onFinally($$, $4);}
|
|
;
|
|
|
|
optional_finally:
|
|
finally
|
|
| { $$.reset();}
|
|
;
|
|
|
|
is_reference:
|
|
'&' { $$ = 1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
function_loc:
|
|
T_FUNCTION { _p->pushFuncLocation();}
|
|
;
|
|
|
|
function_declaration_statement:
|
|
function_loc
|
|
is_reference sm_name_with_typevar { $3.setText(_p->nsDecl($3.text()));
|
|
_p->onFunctionStart($3);
|
|
_p->pushLabelInfo();}
|
|
'(' parameter_list ')'
|
|
sm_opt_return_type
|
|
'{' inner_statement_list '}' { Token t; t.reset();
|
|
_p->onFunction($$,0,t,$2,$3,$6,$10,0);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes function_loc
|
|
is_reference sm_name_with_typevar { $4.setText(_p->nsDecl($4.text()));
|
|
_p->onFunctionStart($4);
|
|
_p->pushLabelInfo();}
|
|
'(' parameter_list ')'
|
|
sm_opt_return_type
|
|
'{' inner_statement_list '}' { Token t; t.reset();
|
|
_p->onFunction($$,0,t,$3,$4,$7,$11,&$1);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
;
|
|
|
|
class_declaration_statement:
|
|
class_entry_type
|
|
class_decl_name { $2.setText(_p->nsDecl($2.text()));
|
|
_p->onClassStart($1.num(),$2);}
|
|
extends_from implements_list '{'
|
|
class_statement_list '}' { Token stmts;
|
|
if (_p->peekClass()) {
|
|
xhp_collect_attributes(_p,stmts,$7);
|
|
} else {
|
|
stmts = $7;
|
|
}
|
|
_p->onClass($$,$1.num(),$2,$4,$5,
|
|
stmts,0);
|
|
if (_p->peekClass()) {
|
|
_p->xhpResetAttributes();
|
|
}
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes
|
|
class_entry_type
|
|
class_decl_name { $3.setText(_p->nsDecl($3.text()));
|
|
_p->onClassStart($2.num(),$3);}
|
|
extends_from implements_list '{'
|
|
class_statement_list '}' { Token stmts;
|
|
if (_p->peekClass()) {
|
|
xhp_collect_attributes(_p,stmts,$8);
|
|
} else {
|
|
stmts = $8;
|
|
}
|
|
_p->onClass($$,$2.num(),$3,$5,$6,
|
|
stmts,&$1);
|
|
if (_p->peekClass()) {
|
|
_p->xhpResetAttributes();
|
|
}
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
| T_INTERFACE
|
|
interface_decl_name { $2.setText(_p->nsDecl($2.text()));
|
|
_p->onClassStart(T_INTERFACE,$2);}
|
|
interface_extends_list '{'
|
|
class_statement_list '}' { _p->onInterface($$,$2,$4,$6,0);
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes
|
|
T_INTERFACE
|
|
interface_decl_name { $3.setText(_p->nsDecl($3.text()));
|
|
_p->onClassStart(T_INTERFACE,$3);}
|
|
interface_extends_list '{'
|
|
class_statement_list '}' { _p->onInterface($$,$3,$5,$7,&$1);
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
;
|
|
|
|
trait_declaration_statement:
|
|
T_TRAIT
|
|
trait_decl_name { $2.setText(_p->nsDecl($2.text()));
|
|
_p->onClassStart(T_TRAIT, $2);}
|
|
'{' class_statement_list '}' { Token t_ext, t_imp;
|
|
t_ext.reset(); t_imp.reset();
|
|
_p->onClass($$,T_TRAIT,$2,t_ext,t_imp,
|
|
$5, 0);
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes
|
|
T_TRAIT
|
|
trait_decl_name { $3.setText(_p->nsDecl($3.text()));
|
|
_p->onClassStart(T_TRAIT, $3);}
|
|
'{' class_statement_list '}' { Token t_ext, t_imp;
|
|
t_ext.reset(); t_imp.reset();
|
|
_p->onClass($$,T_TRAIT,$3,t_ext,t_imp,
|
|
$6, &$1);
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
;
|
|
class_decl_name:
|
|
sm_name_with_typevar { _p->pushClass(false); $$ = $1;}
|
|
| T_XHP_LABEL { $1.xhpLabel(); _p->pushTypeScope();
|
|
_p->pushClass(true); $$ = $1;}
|
|
;
|
|
interface_decl_name:
|
|
sm_name_with_typevar { _p->pushClass(false); $$ = $1;}
|
|
;
|
|
trait_decl_name:
|
|
sm_name_with_typevar { _p->pushClass(false); $$ = $1;}
|
|
;
|
|
class_entry_type:
|
|
T_CLASS { $$ = T_CLASS;}
|
|
| T_ABSTRACT T_CLASS { $$ = T_ABSTRACT;}
|
|
| T_FINAL T_CLASS { $$ = T_FINAL;}
|
|
;
|
|
extends_from:
|
|
T_EXTENDS
|
|
fully_qualified_class_name { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
implements_list:
|
|
T_IMPLEMENTS interface_list { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
interface_extends_list:
|
|
T_EXTENDS interface_list { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
interface_list:
|
|
fully_qualified_class_name { _p->onInterfaceName($$, NULL, $1);}
|
|
| interface_list ','
|
|
fully_qualified_class_name { _p->onInterfaceName($$, &$1, $3);}
|
|
;
|
|
trait_list:
|
|
fully_qualified_class_name { _p->onTraitName($$, NULL, $1);}
|
|
| trait_list ','
|
|
fully_qualified_class_name { _p->onTraitName($$, &$1, $3);}
|
|
;
|
|
|
|
foreach_optional_arg:
|
|
T_DOUBLE_ARROW foreach_variable { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
foreach_variable:
|
|
variable { $$ = $1;}
|
|
| '&' variable { $$ = $2; $$ = 1;}
|
|
;
|
|
|
|
for_statement:
|
|
statement { $$ = $1;}
|
|
| ':' inner_statement_list
|
|
T_ENDFOR ';' { $$ = $2;}
|
|
;
|
|
foreach_statement:
|
|
statement { $$ = $1;}
|
|
| ':' inner_statement_list
|
|
T_ENDFOREACH ';' { $$ = $2;}
|
|
;
|
|
while_statement:
|
|
statement { $$ = $1;}
|
|
| ':' inner_statement_list
|
|
T_ENDWHILE ';' { $$ = $2;}
|
|
;
|
|
declare_statement:
|
|
statement { $$ = $1;}
|
|
| ':' inner_statement_list
|
|
T_ENDDECLARE ';' { $$ = $2;}
|
|
;
|
|
|
|
declare_list:
|
|
ident '=' static_scalar
|
|
| declare_list ','
|
|
ident '=' static_scalar
|
|
;
|
|
|
|
switch_case_list:
|
|
'{' case_list '}' { $$ = $2;}
|
|
| '{' ';' case_list '}' { $$ = $3;}
|
|
| ':' case_list T_ENDSWITCH ';' { $$ = $2;}
|
|
| ':' ';' case_list T_ENDSWITCH ';' { $$ = $3;}
|
|
;
|
|
case_list:
|
|
case_list T_CASE expr
|
|
case_separator
|
|
inner_statement_list { _p->onCase($$,$1,&$3,$5);}
|
|
| case_list T_DEFAULT case_separator
|
|
inner_statement_list { _p->onCase($$,$1,NULL,$4);}
|
|
| { $$.reset();}
|
|
;
|
|
case_separator:
|
|
':' { $$.reset();}
|
|
| ';' { $$.reset();}
|
|
;
|
|
|
|
elseif_list:
|
|
elseif_list T_ELSEIF parenthesis_expr
|
|
statement { _p->onElseIf($$,$1,$3,$4);}
|
|
| { $$.reset();}
|
|
;
|
|
new_elseif_list:
|
|
new_elseif_list T_ELSEIF
|
|
parenthesis_expr ':'
|
|
inner_statement_list { _p->onElseIf($$,$1,$3,$5);}
|
|
| { $$.reset();}
|
|
;
|
|
else_single:
|
|
T_ELSE statement { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
new_else_single:
|
|
T_ELSE ':' inner_statement_list { $$ = $3;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
parameter_list:
|
|
non_empty_parameter_list ',' T_VARARG
|
|
{ only_in_strict_mode(_p); $$ = $1; }
|
|
| non_empty_parameter_list
|
|
possible_comma_in_hphp_syntax { $$ = $1;}
|
|
| T_VARARG { only_in_strict_mode(_p); $$.reset(); }
|
|
| { $$.reset();}
|
|
;
|
|
|
|
non_empty_parameter_list:
|
|
optional_user_attributes
|
|
sm_type_opt T_VARIABLE { _p->onParam($$,NULL,$2,$3,0,NULL,&$1);}
|
|
| optional_user_attributes
|
|
sm_type_opt '&' T_VARIABLE { _p->onParam($$,NULL,$2,$4,1,NULL,&$1);}
|
|
| optional_user_attributes
|
|
sm_type_opt '&' T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,NULL,$2,$4,1,&$6,&$1);}
|
|
| optional_user_attributes
|
|
sm_type_opt T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,NULL,$2,$3,0,&$5,&$1);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
sm_type_opt T_VARIABLE { _p->onParam($$,&$1,$4,$5,0,NULL,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
sm_type_opt '&' T_VARIABLE { _p->onParam($$,&$1,$4,$6,1,NULL,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
sm_type_opt '&' T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,&$1,$4,$6,1,&$8,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
sm_type_opt T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,&$1,$4,$5,0,&$7,&$3);}
|
|
;
|
|
|
|
function_call_parameter_list:
|
|
non_empty_fcall_parameter_list
|
|
possible_comma_in_hphp_syntax { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
non_empty_fcall_parameter_list:
|
|
expr { _p->onCallParam($$,NULL,$1,0);}
|
|
| '&' variable { _p->onCallParam($$,NULL,$2,1);}
|
|
| non_empty_fcall_parameter_list ','
|
|
expr { _p->onCallParam($$,&$1,$3,0);}
|
|
| non_empty_fcall_parameter_list ','
|
|
'&' variable { _p->onCallParam($$,&$1,$4,1);}
|
|
;
|
|
|
|
global_var_list:
|
|
global_var_list ',' global_var { _p->onGlobalVar($$, &$1, $3);}
|
|
| global_var { _p->onGlobalVar($$, NULL, $1);}
|
|
;
|
|
global_var:
|
|
T_VARIABLE { $$ = $1;}
|
|
| '$' variable { $$ = $2; $$ = 1;}
|
|
| '$' '{' expr '}' { $$ = $3; $$ = 1;}
|
|
;
|
|
|
|
static_var_list:
|
|
static_var_list ',' T_VARIABLE { _p->onStaticVariable($$,&$1,$3,0);}
|
|
| static_var_list ',' T_VARIABLE
|
|
'=' static_scalar { _p->onStaticVariable($$,&$1,$3,&$5);}
|
|
| T_VARIABLE { _p->onStaticVariable($$,0,$1,0);}
|
|
| T_VARIABLE '=' static_scalar { _p->onStaticVariable($$,0,$1,&$3);}
|
|
;
|
|
|
|
class_statement_list:
|
|
class_statement_list
|
|
class_statement { _p->onClassStatement($$, $1, $2);}
|
|
| { $$.reset();}
|
|
;
|
|
class_statement:
|
|
variable_modifiers { _p->onClassVariableModifer($1);}
|
|
class_variable_declaration ';' { _p->onClassVariableStart
|
|
($$,&$1,$3,NULL);}
|
|
| non_empty_member_modifiers
|
|
sm_type { _p->onClassVariableModifer($1);}
|
|
class_variable_declaration ';' { _p->onClassVariableStart
|
|
($$,&$1,$4,&$2);}
|
|
| class_constant_declaration ';' { _p->onClassVariableStart
|
|
($$,NULL,$1,NULL);}
|
|
| method_modifiers function_loc
|
|
is_reference sm_name_with_typevar '('
|
|
{ _p->onMethodStart($4, $1);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
sm_opt_return_type
|
|
method_body
|
|
{ Token t; t.reset();
|
|
_p->onMethod($$,$1,t,$3,$4,$7,$10,0);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes
|
|
method_modifiers function_loc
|
|
is_reference sm_name_with_typevar '('
|
|
{ _p->onMethodStart($5, $2);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
sm_opt_return_type
|
|
method_body
|
|
{ Token t; t.reset();
|
|
_p->onMethod($$,$2,t,$4,$5,$8,$11,&$1);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
| T_XHP_ATTRIBUTE
|
|
xhp_attribute_stmt ';' { _p->xhpSetAttributes($2);}
|
|
| T_XHP_CATEGORY
|
|
xhp_category_stmt ';' { xhp_category_stmt(_p,$$,$2);}
|
|
| T_XHP_CHILDREN
|
|
xhp_children_stmt ';' { xhp_children_stmt(_p,$$,$2);}
|
|
| T_USE trait_list ';' { Token t; t.reset();
|
|
_p->onTraitUse($$,$2,t); }
|
|
| T_USE trait_list '{'
|
|
trait_rules '}' { _p->onTraitUse($$,$2,$4); }
|
|
;
|
|
trait_rules:
|
|
trait_rules trait_precedence_rule { _p->onTraitRule($$,$1,$2); }
|
|
| trait_rules trait_alias_rule { _p->onTraitRule($$,$1,$2); }
|
|
| /* empty */ { $$.reset(); }
|
|
;
|
|
trait_precedence_rule:
|
|
class_namespace_string_typeargs
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
ident
|
|
T_INSTEADOF trait_list ';' { _p->onTraitPrecRule($$,$1,$3,$5);}
|
|
;
|
|
trait_alias_rule:
|
|
trait_alias_rule_method T_AS
|
|
method_modifiers ident ';' { _p->onTraitAliasRuleModify($$,$1,$3,
|
|
$4);}
|
|
| trait_alias_rule_method T_AS
|
|
non_empty_member_modifiers ';' { Token t; t.reset();
|
|
_p->onTraitAliasRuleModify($$,$1,$3,
|
|
t);}
|
|
;
|
|
trait_alias_rule_method:
|
|
class_namespace_string_typeargs
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
ident { _p->onTraitAliasRuleStart($$,$1,$3);}
|
|
| ident { Token t; t.reset();
|
|
_p->onTraitAliasRuleStart($$,t,$1);}
|
|
;
|
|
|
|
xhp_attribute_stmt:
|
|
xhp_attribute_decl { xhp_attribute_list(_p,$$,
|
|
_p->xhpGetAttributes(),$1);}
|
|
| xhp_attribute_stmt ','
|
|
xhp_attribute_decl { xhp_attribute_list(_p,$$, &$1,$3);}
|
|
;
|
|
|
|
xhp_attribute_decl:
|
|
xhp_attribute_decl_type
|
|
xhp_label_ws
|
|
xhp_attribute_default
|
|
xhp_attribute_is_required { xhp_attribute(_p,$$,$1,$2,$3,$4);
|
|
$$ = 1;}
|
|
| T_XHP_LABEL { $$ = $1; $$ = 0;}
|
|
;
|
|
|
|
xhp_attribute_decl_type:
|
|
T_ARRAY { $$ = 4;}
|
|
| fully_qualified_class_name { /* This case handles all types other
|
|
than "array", "var" and "enum".
|
|
For now we just use type code 5;
|
|
later xhp_attribute() will fix up
|
|
the type code as appropriate. */
|
|
$$ = 5; $$.setText($1);}
|
|
| T_VAR { $$ = 6;}
|
|
| T_XHP_ENUM '{'
|
|
xhp_attribute_enum '}' { $$ = $3; $$ = 7;}
|
|
;
|
|
|
|
xhp_attribute_enum:
|
|
common_scalar { _p->onArrayPair($$, 0,0,$1,0);}
|
|
| xhp_attribute_enum ','
|
|
common_scalar { _p->onArrayPair($$,&$1,0,$3,0);}
|
|
;
|
|
|
|
xhp_attribute_default:
|
|
'=' static_scalar { $$ = $2;}
|
|
| { scalar_null(_p, $$);}
|
|
;
|
|
|
|
xhp_attribute_is_required:
|
|
'@' T_XHP_REQUIRED { scalar_num(_p, $$, "1");}
|
|
| { scalar_num(_p, $$, "0");}
|
|
;
|
|
|
|
xhp_category_stmt:
|
|
xhp_category_decl { Token t; scalar_num(_p, t, "1");
|
|
_p->onArrayPair($$,0,&$1,t,0);}
|
|
| xhp_category_stmt ','
|
|
xhp_category_decl { Token t; scalar_num(_p, t, "1");
|
|
_p->onArrayPair($$,&$1,&$3,t,0);}
|
|
;
|
|
|
|
xhp_category_decl:
|
|
T_XHP_CATEGORY_LABEL { _p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);}
|
|
;
|
|
|
|
xhp_children_stmt:
|
|
xhp_children_paren_expr { $$ = $1; $$ = 2;}
|
|
| ident { $$ = -1;
|
|
if ($1.same("any")) $$ = 1;}
|
|
| T_EMPTY { $$ = 0;}
|
|
;
|
|
|
|
xhp_children_paren_expr:
|
|
'(' xhp_children_decl_expr ')' { xhp_children_paren(_p, $$, $2, 0);}
|
|
| '(' xhp_children_decl_expr ')' '*' { xhp_children_paren(_p, $$, $2, 1);}
|
|
| '(' xhp_children_decl_expr ')' '?' { xhp_children_paren(_p, $$, $2, 2);}
|
|
| '(' xhp_children_decl_expr ')' '+' { xhp_children_paren(_p, $$, $2, 3);}
|
|
;
|
|
|
|
xhp_children_decl_expr:
|
|
xhp_children_paren_expr { $$ = $1;}
|
|
| xhp_children_decl_tag { xhp_children_decl(_p,$$,$1,0, 0);}
|
|
| xhp_children_decl_tag '*' { xhp_children_decl(_p,$$,$1,1, 0);}
|
|
| xhp_children_decl_tag '?' { xhp_children_decl(_p,$$,$1,2, 0);}
|
|
| xhp_children_decl_tag '+' { xhp_children_decl(_p,$$,$1,3, 0);}
|
|
| xhp_children_decl_expr ','
|
|
xhp_children_decl_expr { xhp_children_decl(_p,$$,$1,4,&$3);}
|
|
| xhp_children_decl_expr '|'
|
|
xhp_children_decl_expr { xhp_children_decl(_p,$$,$1,5,&$3);}
|
|
;
|
|
|
|
xhp_children_decl_tag:
|
|
ident { $$ = -1;
|
|
if ($1.same("any")) $$ = 1; else
|
|
if ($1.same("pcdata")) $$ = 2;}
|
|
| T_XHP_LABEL { $1.xhpLabel(); $$ = $1; $$ = 3;}
|
|
| T_XHP_CATEGORY_LABEL { $1.xhpLabel(0); $$ = $1; $$ = 4;}
|
|
;
|
|
|
|
method_body:
|
|
';' { $$.reset();}
|
|
| '{' inner_statement_list '}' { _p->finishStatement($$, $2); $$ = 1;}
|
|
;
|
|
variable_modifiers:
|
|
non_empty_member_modifiers { $$ = $1;}
|
|
| T_VAR { $$.reset();}
|
|
;
|
|
method_modifiers:
|
|
non_empty_member_modifiers { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
non_empty_member_modifiers:
|
|
member_modifier { _p->onMemberModifier($$,NULL,$1);}
|
|
| non_empty_member_modifiers
|
|
member_modifier { _p->onMemberModifier($$,&$1,$2);}
|
|
;
|
|
member_modifier:
|
|
T_PUBLIC { $$ = T_PUBLIC;}
|
|
| T_PROTECTED { $$ = T_PROTECTED;}
|
|
| T_PRIVATE { $$ = T_PRIVATE;}
|
|
| T_STATIC { $$ = T_STATIC;}
|
|
| T_ABSTRACT { $$ = T_ABSTRACT;}
|
|
| T_FINAL { $$ = T_FINAL;}
|
|
;
|
|
class_variable_declaration:
|
|
class_variable_declaration ','
|
|
T_VARIABLE { _p->onClassVariable($$,&$1,$3,0);}
|
|
| class_variable_declaration ','
|
|
T_VARIABLE '=' static_scalar { _p->onClassVariable($$,&$1,$3,&$5);}
|
|
| T_VARIABLE { _p->onClassVariable($$,0,$1,0);}
|
|
| T_VARIABLE '=' static_scalar { _p->onClassVariable($$,0,$1,&$3);}
|
|
;
|
|
class_constant_declaration:
|
|
class_constant_declaration ','
|
|
sm_name_with_type '=' static_scalar { _p->onClassConstant($$,&$1,$3,$5);}
|
|
| T_CONST sm_name_with_type '=' static_scalar { _p->onClassConstant($$,0,$2,$4);}
|
|
;
|
|
|
|
new_expr:
|
|
T_NEW class_name_reference
|
|
ctor_arguments { _p->onNewObject($$, $2, $3);}
|
|
| '(' new_expr ')' { $$ = $2;}
|
|
;
|
|
|
|
parenthesis_expr:
|
|
'(' expr ')' { $$ = $2;}
|
|
;
|
|
|
|
expr_list:
|
|
expr_list ',' expr { _p->onExprListElem($$, &$1, $3);}
|
|
| expr { _p->onExprListElem($$, NULL, $1);}
|
|
;
|
|
|
|
for_expr:
|
|
expr_list { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
yield_expr:
|
|
T_YIELD expr { _p->onYield($$, $2);}
|
|
;
|
|
|
|
yield_assign_expr:
|
|
variable '=' yield_expr { _p->onAssign($$, $1, $3, 0, true);}
|
|
;
|
|
|
|
yield_list_assign_expr:
|
|
T_LIST '(' assignment_list ')'
|
|
'=' yield_expr { _p->onListAssignment($$, $3, &$6, true);}
|
|
;
|
|
|
|
expr:
|
|
expr_no_variable { $$ = $1;}
|
|
| variable { $$ = $1;}
|
|
| new_expr { $$ = $1;}
|
|
|
|
expr_no_variable:
|
|
T_LIST '(' assignment_list ')'
|
|
'=' expr { _p->onListAssignment($$, $3, &$6);}
|
|
| variable '=' expr { _p->onAssign($$, $1, $3, 0);}
|
|
| variable '=' '&' variable { _p->onAssign($$, $1, $4, 1);}
|
|
| variable '=' '&' T_NEW
|
|
class_name_reference
|
|
ctor_arguments { _p->onAssignNew($$,$1,$5,$6);}
|
|
| T_CLONE expr { UEXP($$,$2,T_CLONE,1);}
|
|
| variable T_PLUS_EQUAL expr { BEXP($$,$1,$3,T_PLUS_EQUAL);}
|
|
| variable T_MINUS_EQUAL expr { BEXP($$,$1,$3,T_MINUS_EQUAL);}
|
|
| variable T_MUL_EQUAL expr { BEXP($$,$1,$3,T_MUL_EQUAL);}
|
|
| variable T_DIV_EQUAL expr { BEXP($$,$1,$3,T_DIV_EQUAL);}
|
|
| variable T_CONCAT_EQUAL expr { BEXP($$,$1,$3,T_CONCAT_EQUAL);}
|
|
| variable T_MOD_EQUAL expr { BEXP($$,$1,$3,T_MOD_EQUAL);}
|
|
| variable T_AND_EQUAL expr { BEXP($$,$1,$3,T_AND_EQUAL);}
|
|
| variable T_OR_EQUAL expr { BEXP($$,$1,$3,T_OR_EQUAL);}
|
|
| variable T_XOR_EQUAL expr { BEXP($$,$1,$3,T_XOR_EQUAL);}
|
|
| variable T_SL_EQUAL expr { BEXP($$,$1,$3,T_SL_EQUAL);}
|
|
| variable T_SR_EQUAL expr { BEXP($$,$1,$3,T_SR_EQUAL);}
|
|
| variable T_INC { UEXP($$,$1,T_INC,0);}
|
|
| T_INC variable { UEXP($$,$2,T_INC,1);}
|
|
| variable T_DEC { UEXP($$,$1,T_DEC,0);}
|
|
| T_DEC variable { UEXP($$,$2,T_DEC,1);}
|
|
| expr T_BOOLEAN_OR expr { BEXP($$,$1,$3,T_BOOLEAN_OR);}
|
|
| expr T_BOOLEAN_AND expr { BEXP($$,$1,$3,T_BOOLEAN_AND);}
|
|
| expr T_LOGICAL_OR expr { BEXP($$,$1,$3,T_LOGICAL_OR);}
|
|
| expr T_LOGICAL_AND expr { BEXP($$,$1,$3,T_LOGICAL_AND);}
|
|
| expr T_LOGICAL_XOR expr { BEXP($$,$1,$3,T_LOGICAL_XOR);}
|
|
| expr '|' expr { BEXP($$,$1,$3,'|');}
|
|
| expr '&' expr { BEXP($$,$1,$3,'&');}
|
|
| expr '^' expr { BEXP($$,$1,$3,'^');}
|
|
| expr '.' expr { BEXP($$,$1,$3,'.');}
|
|
| expr '+' expr { BEXP($$,$1,$3,'+');}
|
|
| expr '-' expr { BEXP($$,$1,$3,'-');}
|
|
| expr '*' expr { BEXP($$,$1,$3,'*');}
|
|
| expr '/' expr { BEXP($$,$1,$3,'/');}
|
|
| expr '%' expr { BEXP($$,$1,$3,'%');}
|
|
| expr T_SL expr { BEXP($$,$1,$3,T_SL);}
|
|
| expr T_SR expr { BEXP($$,$1,$3,T_SR);}
|
|
| '+' expr %prec T_INC { UEXP($$,$2,'+',1);}
|
|
| '-' expr %prec T_INC { UEXP($$,$2,'-',1);}
|
|
| '!' expr { UEXP($$,$2,'!',1);}
|
|
| '~' expr { UEXP($$,$2,'~',1);}
|
|
| expr T_IS_IDENTICAL expr { BEXP($$,$1,$3,T_IS_IDENTICAL);}
|
|
| expr T_IS_NOT_IDENTICAL expr { BEXP($$,$1,$3,T_IS_NOT_IDENTICAL);}
|
|
| expr T_IS_EQUAL expr { BEXP($$,$1,$3,T_IS_EQUAL);}
|
|
| expr T_IS_NOT_EQUAL expr { BEXP($$,$1,$3,T_IS_NOT_EQUAL);}
|
|
| expr '<' expr { BEXP($$,$1,$3,'<');}
|
|
| expr T_IS_SMALLER_OR_EQUAL expr { BEXP($$,$1,$3,
|
|
T_IS_SMALLER_OR_EQUAL);}
|
|
| expr '>' expr { BEXP($$,$1,$3,'>');}
|
|
| expr T_IS_GREATER_OR_EQUAL expr { BEXP($$,$1,$3,
|
|
T_IS_GREATER_OR_EQUAL);}
|
|
| expr T_INSTANCEOF
|
|
class_name_reference { BEXP($$,$1,$3,T_INSTANCEOF);}
|
|
| '(' expr_no_variable ')' { $$ = $2;}
|
|
| expr '?' expr ':' expr { _p->onQOp($$, $1, &$3, $5);}
|
|
| expr '?' ':' expr { _p->onQOp($$, $1, 0, $4);}
|
|
| internal_functions { $$ = $1;}
|
|
| T_INT_CAST expr { UEXP($$,$2,T_INT_CAST,1);}
|
|
| T_DOUBLE_CAST expr { UEXP($$,$2,T_DOUBLE_CAST,1);}
|
|
| T_STRING_CAST expr { UEXP($$,$2,T_STRING_CAST,1);}
|
|
| T_ARRAY_CAST expr { UEXP($$,$2,T_ARRAY_CAST,1);}
|
|
| T_OBJECT_CAST expr { UEXP($$,$2,T_OBJECT_CAST,1);}
|
|
| T_BOOL_CAST expr { UEXP($$,$2,T_BOOL_CAST,1);}
|
|
| T_UNSET_CAST expr { UEXP($$,$2,T_UNSET_CAST,1);}
|
|
| T_EXIT exit_expr { UEXP($$,$2,T_EXIT,1);}
|
|
| '@' expr { UEXP($$,$2,'@',1);}
|
|
| scalar { $$ = $1; }
|
|
| array_literal { $$ = $1; }
|
|
| shape_literal { $$ = $1; }
|
|
| '`' backticks_expr '`' { _p->onEncapsList($$,'`',$2);}
|
|
| T_PRINT expr { UEXP($$,$2,T_PRINT,1);}
|
|
| function_loc
|
|
is_reference '(' { Token t; _p->onClosureStart(t);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
sm_opt_return_type lexical_vars
|
|
'{' inner_statement_list '}' { Token u; u.reset();
|
|
_p->onClosure($$,u,$2,$5,$8,$10,0);
|
|
_p->popLabelInfo();}
|
|
| T_STATIC function_loc
|
|
is_reference '(' { Token t; _p->onClosureStart(t);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
sm_opt_return_type lexical_vars
|
|
'{' inner_statement_list '}' { Token u; u.reset();
|
|
_p->onClosure($$,u,$3,$6,$9,$11,1);
|
|
_p->popLabelInfo();}
|
|
| xhp_tag { $$ = $1;}
|
|
| dim_expr { $$ = $1;}
|
|
| collection_literal { $$ = $1;}
|
|
;
|
|
|
|
non_empty_shape_pair_list:
|
|
non_empty_shape_pair_list ','
|
|
T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
expr { validate_shape_keyname($3, _p);
|
|
_p->onArrayPair($$,&$1,&$3,$5,0); }
|
|
| T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
expr { validate_shape_keyname($1, _p);
|
|
_p->onArrayPair($$, 0,&$1,$3,0); }
|
|
;
|
|
|
|
non_empty_static_shape_pair_list:
|
|
non_empty_static_shape_pair_list ','
|
|
T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
static_scalar { validate_shape_keyname($3, _p);
|
|
_p->onArrayPair($$,&$1,&$3,$5,0); }
|
|
| T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
static_scalar { validate_shape_keyname($1, _p);
|
|
_p->onArrayPair($$, 0,&$1,$3,0); }
|
|
;
|
|
|
|
shape_pair_list:
|
|
non_empty_shape_pair_list
|
|
possible_comma { $$ = $1; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
static_shape_pair_list:
|
|
non_empty_static_shape_pair_list
|
|
possible_comma { $$ = $1; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
shape_literal:
|
|
T_SHAPE '(' shape_pair_list ')' { only_in_strict_mode(_p);
|
|
_p->onArray($$, $3, T_ARRAY); }
|
|
;
|
|
|
|
array_literal:
|
|
T_ARRAY '(' array_pair_list ')' { _p->onArray($$,$3,T_ARRAY);}
|
|
;
|
|
|
|
collection_literal:
|
|
fully_qualified_class_name
|
|
'{' collection_init '}' { Token t;
|
|
_p->onName(t,$1,Parser::StringName);
|
|
BEXP($$,t,$3,T_COLLECTION);}
|
|
;
|
|
|
|
static_collection_literal:
|
|
fully_qualified_class_name
|
|
'{' static_collection_init '}' { Token t;
|
|
_p->onName(t,$1,Parser::StringName);
|
|
BEXP($$,t,$3,T_COLLECTION);}
|
|
;
|
|
|
|
dim_expr:
|
|
dim_expr
|
|
'[' dim_offset ']' { _p->onRefDim($$, $1, $3);}
|
|
| dim_expr_base
|
|
'[' dim_offset ']' { _p->onRefDim($$, $1, $3);}
|
|
;
|
|
|
|
dim_expr_base:
|
|
array_literal { $$ = $1;}
|
|
| class_constant { $$ = $1;}
|
|
| '(' expr_no_variable ')' { $$ = $2;}
|
|
;
|
|
|
|
lexical_vars:
|
|
T_USE '('
|
|
lexical_var_list
|
|
possible_comma_in_hphp_syntax
|
|
')' { $$ = $3;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
lexical_var_list:
|
|
lexical_var_list ',' T_VARIABLE { _p->onClosureParam($$,&$1,$3,0);}
|
|
| lexical_var_list ',' '&'T_VARIABLE { _p->onClosureParam($$,&$1,$4,1);}
|
|
| T_VARIABLE { _p->onClosureParam($$, 0,$1,0);}
|
|
| '&' T_VARIABLE { _p->onClosureParam($$, 0,$2,1);}
|
|
;
|
|
|
|
xhp_tag:
|
|
T_XHP_TAG_LT
|
|
T_XHP_LABEL
|
|
xhp_tag_body
|
|
T_XHP_TAG_GT { xhp_tag(_p,$$,$2,$3);}
|
|
;
|
|
xhp_tag_body:
|
|
xhp_attributes '/' { Token t1; _p->onArray(t1,$1);
|
|
Token t2; _p->onArray(t2,$2);
|
|
_p->onCallParam($1,NULL,t1,0);
|
|
_p->onCallParam($$, &$1,t2,0);
|
|
$$.setText("");}
|
|
| xhp_attributes T_XHP_TAG_GT
|
|
xhp_children T_XHP_TAG_LT '/'
|
|
xhp_opt_end_label { _p->onArray($4,$1);
|
|
_p->onArray($5,$3);
|
|
_p->onCallParam($2,NULL,$4,0);
|
|
_p->onCallParam($$, &$2,$5,0);
|
|
$$.setText($6.text());}
|
|
;
|
|
xhp_opt_end_label:
|
|
{ $$.reset(); $$.setText("");}
|
|
| T_XHP_LABEL { $$.reset(); $$.setText($1);}
|
|
;
|
|
xhp_attributes:
|
|
xhp_attributes
|
|
xhp_attribute_name '='
|
|
xhp_attribute_value { _p->onArrayPair($$,&$1,&$2,$4,0);}
|
|
| { $$.reset();}
|
|
;
|
|
xhp_children:
|
|
xhp_children xhp_child { _p->onArrayPair($$,&$1,0,$2,0);}
|
|
| { $$.reset();}
|
|
;
|
|
xhp_attribute_name:
|
|
T_XHP_LABEL { _p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);}
|
|
;
|
|
xhp_attribute_value:
|
|
T_XHP_TEXT { $1.xhpDecode();
|
|
_p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);}
|
|
| '{' expr '}' { $$ = $2;}
|
|
;
|
|
xhp_child:
|
|
T_XHP_TEXT { $$.reset();
|
|
if ($1.htmlTrim()) {
|
|
$1.xhpDecode();
|
|
_p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);
|
|
}
|
|
}
|
|
| '{' expr '}' { $$ = $2; }
|
|
| xhp_tag { $$ = $1; }
|
|
;
|
|
|
|
xhp_label_ws:
|
|
xhp_bareword { $$ = $1;}
|
|
| xhp_label_ws ':'
|
|
xhp_bareword { $$ = $1 + ":" + $3;}
|
|
| xhp_label_ws '-'
|
|
xhp_bareword { $$ = $1 + "-" + $3;}
|
|
;
|
|
xhp_bareword:
|
|
ident { $$ = $1;}
|
|
| T_EXIT { $$ = $1;}
|
|
| T_FUNCTION { $$ = $1;}
|
|
| T_CONST { $$ = $1;}
|
|
| T_RETURN { $$ = $1;}
|
|
| T_YIELD { $$ = $1;}
|
|
| T_TRY { $$ = $1;}
|
|
| T_CATCH { $$ = $1;}
|
|
| T_FINALLY { $$ = $1;}
|
|
| T_THROW { $$ = $1;}
|
|
| T_IF { $$ = $1;}
|
|
| T_ELSEIF { $$ = $1;}
|
|
| T_ENDIF { $$ = $1;}
|
|
| T_ELSE { $$ = $1;}
|
|
| T_WHILE { $$ = $1;}
|
|
| T_ENDWHILE { $$ = $1;}
|
|
| T_DO { $$ = $1;}
|
|
| T_FOR { $$ = $1;}
|
|
| T_ENDFOR { $$ = $1;}
|
|
| T_FOREACH { $$ = $1;}
|
|
| T_ENDFOREACH { $$ = $1;}
|
|
| T_DECLARE { $$ = $1;}
|
|
| T_ENDDECLARE { $$ = $1;}
|
|
| T_INSTANCEOF { $$ = $1;}
|
|
| T_AS { $$ = $1;}
|
|
| T_SWITCH { $$ = $1;}
|
|
| T_ENDSWITCH { $$ = $1;}
|
|
| T_CASE { $$ = $1;}
|
|
| T_DEFAULT { $$ = $1;}
|
|
| T_BREAK { $$ = $1;}
|
|
| T_CONTINUE { $$ = $1;}
|
|
| T_GOTO { $$ = $1;}
|
|
| T_ECHO { $$ = $1;}
|
|
| T_PRINT { $$ = $1;}
|
|
| T_CLASS { $$ = $1;}
|
|
| T_INTERFACE { $$ = $1;}
|
|
| T_EXTENDS { $$ = $1;}
|
|
| T_IMPLEMENTS { $$ = $1;}
|
|
| T_NEW { $$ = $1;}
|
|
| T_CLONE { $$ = $1;}
|
|
| T_VAR { $$ = $1;}
|
|
| T_EVAL { $$ = $1;}
|
|
| T_INCLUDE { $$ = $1;}
|
|
| T_INCLUDE_ONCE { $$ = $1;}
|
|
| T_REQUIRE { $$ = $1;}
|
|
| T_REQUIRE_ONCE { $$ = $1;}
|
|
| T_NAMESPACE { $$ = $1;}
|
|
| T_USE { $$ = $1;}
|
|
| T_GLOBAL { $$ = $1;}
|
|
| T_ISSET { $$ = $1;}
|
|
| T_EMPTY { $$ = $1;}
|
|
| T_HALT_COMPILER { $$ = $1;}
|
|
| T_STATIC { $$ = $1;}
|
|
| T_ABSTRACT { $$ = $1;}
|
|
| T_FINAL { $$ = $1;}
|
|
| T_PRIVATE { $$ = $1;}
|
|
| T_PROTECTED { $$ = $1;}
|
|
| T_PUBLIC { $$ = $1;}
|
|
| T_UNSET { $$ = $1;}
|
|
| T_LIST { $$ = $1;}
|
|
| T_ARRAY { $$ = $1;}
|
|
| T_LOGICAL_OR { $$ = $1;}
|
|
| T_LOGICAL_AND { $$ = $1;}
|
|
| T_LOGICAL_XOR { $$ = $1;}
|
|
| T_CLASS_C { $$ = $1;}
|
|
| T_FUNC_C { $$ = $1;}
|
|
| T_METHOD_C { $$ = $1;}
|
|
| T_LINE { $$ = $1;}
|
|
| T_FILE { $$ = $1;}
|
|
| T_DIR { $$ = $1;}
|
|
| T_NS_C { $$ = $1;}
|
|
| T_TRAIT { $$ = $1;}
|
|
| T_TRAIT_C { $$ = $1;}
|
|
| T_TYPE { $$ = $1;}
|
|
;
|
|
|
|
simple_function_call:
|
|
namespace_string_typeargs '('
|
|
function_call_parameter_list ')' { _p->onCall($$,0,$1,$3,NULL);}
|
|
;
|
|
|
|
fully_qualified_class_name:
|
|
class_namespace_string_typeargs { $$ = $1;}
|
|
| T_XHP_LABEL { $1.xhpLabel(); $$ = $1;}
|
|
;
|
|
static_class_name:
|
|
fully_qualified_class_name { _p->onName($$,$1,Parser::StringName);}
|
|
| T_STATIC { _p->onName($$,$1,Parser::StaticName);}
|
|
| reference_variable { _p->onName($$,$1,
|
|
Parser::StaticClassExprName);}
|
|
;
|
|
class_name_reference:
|
|
fully_qualified_class_name { _p->onName($$,$1,Parser::StringName);}
|
|
| T_STATIC { _p->onName($$,$1,Parser::StaticName);}
|
|
| variable_no_calls { _p->onName($$,$1,Parser::ExprName);}
|
|
;
|
|
|
|
exit_expr:
|
|
'(' ')' { $$.reset();}
|
|
| parenthesis_expr { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
backticks_expr:
|
|
/* empty */ { $$.reset();}
|
|
| T_ENCAPSED_AND_WHITESPACE { _p->addEncap($$, NULL, $1, 0);}
|
|
| encaps_list { $$ = $1;}
|
|
|
|
ctor_arguments:
|
|
'('
|
|
function_call_parameter_list ')' { $$ = $2;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
common_scalar:
|
|
T_LNUMBER { _p->onScalar($$, T_LNUMBER, $1);}
|
|
| T_DNUMBER { _p->onScalar($$, T_DNUMBER, $1);}
|
|
| T_CONSTANT_ENCAPSED_STRING { _p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);}
|
|
| T_LINE { _p->onScalar($$, T_LINE, $1);}
|
|
| T_FILE { _p->onScalar($$, T_FILE, $1);}
|
|
| T_DIR { _p->onScalar($$, T_DIR, $1);}
|
|
| T_CLASS_C { _p->onScalar($$, T_CLASS_C, $1);}
|
|
| T_TRAIT_C { _p->onScalar($$, T_TRAIT_C, $1);}
|
|
| T_METHOD_C { _p->onScalar($$, T_METHOD_C, $1);}
|
|
| T_FUNC_C { _p->onScalar($$, T_FUNC_C, $1);}
|
|
| T_NS_C { _p->onScalar($$, T_NS_C, $1);}
|
|
| T_START_HEREDOC
|
|
T_ENCAPSED_AND_WHITESPACE
|
|
T_END_HEREDOC { _p->onScalar($$, T_CONSTANT_ENCAPSED_STRING, $2);}
|
|
| T_START_HEREDOC
|
|
T_END_HEREDOC { $$.setText(""); _p->onScalar($$, T_CONSTANT_ENCAPSED_STRING, $$);}
|
|
;
|
|
|
|
static_scalar:
|
|
common_scalar { $$ = $1;}
|
|
| namespace_string { _p->onConstantValue($$, $1);}
|
|
| '+' static_scalar { UEXP($$,$2,'+',1);}
|
|
| '-' static_scalar { UEXP($$,$2,'-',1);}
|
|
| T_ARRAY '('
|
|
static_array_pair_list ')' { _p->onArray($$,$3,T_ARRAY); }
|
|
| T_SHAPE '('
|
|
static_shape_pair_list ')' { only_in_strict_mode(_p);
|
|
_p->onArray($$,$3,T_ARRAY); }
|
|
| static_class_constant { $$ = $1;}
|
|
| static_collection_literal { $$ = $1;}
|
|
;
|
|
|
|
static_class_constant:
|
|
class_namespace_string_typeargs
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
ident { _p->onClassConst($$, $1, $3, 1);}
|
|
| T_XHP_LABEL T_PAAMAYIM_NEKUDOTAYIM
|
|
ident { $1.xhpLabel();
|
|
_p->onClassConst($$, $1, $3, 1);}
|
|
;
|
|
|
|
scalar:
|
|
namespace_string { _p->onConstantValue($$, $1);}
|
|
| T_STRING_VARNAME { _p->onConstantValue($$, $1);}
|
|
| class_constant { $$ = $1;}
|
|
| common_scalar { $$ = $1;}
|
|
| '"' encaps_list '"' { _p->onEncapsList($$,'"',$2);}
|
|
| '\'' encaps_list '\'' { _p->onEncapsList($$,'\'',$2);}
|
|
| T_START_HEREDOC encaps_list
|
|
T_END_HEREDOC { _p->onEncapsList($$,T_START_HEREDOC,
|
|
$2);}
|
|
;
|
|
static_array_pair_list:
|
|
non_empty_static_array_pair_list
|
|
possible_comma { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
possible_comma:
|
|
',' { $$.reset();}
|
|
| { $$.reset();}
|
|
;
|
|
possible_comma_in_hphp_syntax:
|
|
',' { only_in_hphp_syntax(_p); $$.reset();}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
non_empty_static_array_pair_list:
|
|
non_empty_static_array_pair_list
|
|
',' static_scalar T_DOUBLE_ARROW
|
|
static_scalar { _p->onArrayPair($$,&$1,&$3,$5,0);}
|
|
| non_empty_static_array_pair_list
|
|
',' static_scalar { _p->onArrayPair($$,&$1, 0,$3,0);}
|
|
| static_scalar T_DOUBLE_ARROW
|
|
static_scalar { _p->onArrayPair($$, 0,&$1,$3,0);}
|
|
| static_scalar { _p->onArrayPair($$, 0, 0,$1,0);}
|
|
;
|
|
|
|
common_scalar_ae:
|
|
T_LNUMBER { _p->onScalar($$, T_LNUMBER, $1);}
|
|
| T_DNUMBER { _p->onScalar($$, T_DNUMBER, $1);}
|
|
| T_CONSTANT_ENCAPSED_STRING { _p->onScalar($$,
|
|
T_CONSTANT_ENCAPSED_STRING, $1);}
|
|
| T_START_HEREDOC
|
|
T_ENCAPSED_AND_WHITESPACE
|
|
T_END_HEREDOC { _p->onScalar($$, T_CONSTANT_ENCAPSED_STRING, $2);}
|
|
| T_START_HEREDOC
|
|
T_END_HEREDOC { $$.setText(""); _p->onScalar($$, T_CONSTANT_ENCAPSED_STRING, $$);}
|
|
;
|
|
static_numeric_scalar_ae:
|
|
T_LNUMBER { _p->onScalar($$,T_LNUMBER,$1);}
|
|
| T_DNUMBER { _p->onScalar($$,T_DNUMBER,$1);}
|
|
| ident { constant_ae(_p,$$,$1);}
|
|
;
|
|
static_scalar_ae:
|
|
common_scalar_ae { $$ = $1;}
|
|
| ident { constant_ae(_p,$$,$1);}
|
|
| '+' static_numeric_scalar_ae { UEXP($$,$2,'+',1);}
|
|
| '-' static_numeric_scalar_ae { UEXP($$,$2,'-',1);}
|
|
| T_ARRAY '('
|
|
static_array_pair_list_ae ')' { _p->onArray($$,$3,T_ARRAY);}
|
|
| T_SHAPE '('
|
|
static_shape_pair_list_ae ')' { only_in_strict_mode(_p);
|
|
_p->onArray($$,$3,T_ARRAY); }
|
|
;
|
|
|
|
static_array_pair_list_ae:
|
|
non_empty_static_array_pair_list_ae
|
|
possible_comma { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
non_empty_static_array_pair_list_ae:
|
|
non_empty_static_array_pair_list_ae
|
|
',' static_scalar_ae T_DOUBLE_ARROW
|
|
static_scalar_ae { _p->onArrayPair($$,&$1,&$3,$5,0);}
|
|
| non_empty_static_array_pair_list_ae
|
|
',' static_scalar_ae { _p->onArrayPair($$,&$1, 0,$3,0);}
|
|
| static_scalar_ae T_DOUBLE_ARROW
|
|
static_scalar_ae { _p->onArrayPair($$, 0,&$1,$3,0);}
|
|
| static_scalar_ae { _p->onArrayPair($$, 0, 0,$1,0);}
|
|
;
|
|
non_empty_static_scalar_list_ae:
|
|
non_empty_static_scalar_list_ae
|
|
',' static_scalar_ae { _p->onArrayPair($$,&$1, 0,$3,0);}
|
|
| static_scalar_ae { _p->onArrayPair($$, 0, 0,$1,0);}
|
|
;
|
|
|
|
static_shape_pair_list_ae:
|
|
non_empty_static_shape_pair_list_ae
|
|
possible_comma { $$ = $1; }
|
|
| { $$.reset(); }
|
|
;
|
|
non_empty_static_shape_pair_list_ae:
|
|
non_empty_static_shape_pair_list_ae
|
|
',' T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW static_scalar_ae { validate_shape_keyname($3, _p);
|
|
_p->onArrayPair($$,&$1,&$3,$5,0); }
|
|
| T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
static_scalar_ae { validate_shape_keyname($1, _p);
|
|
_p->onArrayPair($$, 0,&$1,$3,0); }
|
|
;
|
|
|
|
static_scalar_list_ae:
|
|
non_empty_static_scalar_list_ae
|
|
possible_comma { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
attribute_static_scalar_list:
|
|
'(' static_scalar_list_ae ')' { _p->onArray($$,$2,T_ARRAY);}
|
|
| { Token t; t.reset();
|
|
_p->onArray($$,t,T_ARRAY);}
|
|
;
|
|
|
|
non_empty_user_attribute_list:
|
|
non_empty_user_attribute_list
|
|
',' ident
|
|
attribute_static_scalar_list { _p->onUserAttribute($$,&$1,$3,$4);}
|
|
| ident
|
|
attribute_static_scalar_list { _p->onUserAttribute($$, 0,$1,$2);}
|
|
;
|
|
user_attribute_list:
|
|
{ user_attribute_check(_p);}
|
|
non_empty_user_attribute_list
|
|
possible_comma { $$ = $2;}
|
|
;
|
|
non_empty_user_attributes:
|
|
T_SL user_attribute_list T_SR { $$ = $2;}
|
|
;
|
|
optional_user_attributes:
|
|
non_empty_user_attributes { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
property_access:
|
|
property_access_without_variables { $$ = $1;}
|
|
| T_OBJECT_OPERATOR
|
|
variable_without_objects { $$ = $2;}
|
|
;
|
|
|
|
property_access_without_variables:
|
|
T_OBJECT_OPERATOR ident { $$ = $2;}
|
|
| T_OBJECT_OPERATOR '{' expr '}' { $$ = $3;}
|
|
;
|
|
|
|
array_access:
|
|
'[' dim_offset ']' { $$ = $2;}
|
|
| '{' expr '}' { $$ = $2;}
|
|
;
|
|
|
|
dimmable_variable_access:
|
|
dimmable_variable array_access { _p->onRefDim($$, $1, $2);}
|
|
| '(' new_expr ')' array_access { _p->onRefDim($$, $2, $4);}
|
|
;
|
|
|
|
dimmable_variable_no_calls_access:
|
|
dimmable_variable_no_calls
|
|
array_access { _p->onRefDim($$, $1, $2);}
|
|
| '(' new_expr ')' array_access { _p->onRefDim($$, $2, $4);}
|
|
;
|
|
|
|
variable:
|
|
variable_without_objects { $$ = $1;}
|
|
| simple_function_call { $$ = $1;}
|
|
| object_method_call { $$ = $1;}
|
|
| class_method_call { $$ = $1;}
|
|
| dimmable_variable_access { $$ = $1;}
|
|
| variable property_access { _p->onObjectProperty($$,$1,$2);}
|
|
| '(' new_expr ')' property_access { _p->onObjectProperty($$,$2,$4);}
|
|
| static_class_name
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
variable_without_objects { _p->onStaticMember($$,$1,$3);}
|
|
| callable_variable '('
|
|
function_call_parameter_list ')' { _p->onCall($$,1,$1,$3,NULL);}
|
|
| '(' variable ')' { $$ = $2;}
|
|
;
|
|
|
|
dimmable_variable:
|
|
simple_function_call { $$ = $1;}
|
|
| object_method_call { $$ = $1;}
|
|
| class_method_call { $$ = $1;}
|
|
| dimmable_variable_access { $$ = $1;}
|
|
| variable
|
|
property_access_without_variables { _p->onObjectProperty($$,$1,$2);}
|
|
| '(' new_expr ')'
|
|
property_access_without_variables { _p->onObjectProperty($$,$2,$4);}
|
|
| callable_variable '('
|
|
function_call_parameter_list ')' { _p->onCall($$,1,$1,$3,NULL);}
|
|
| '(' variable ')' { $$ = $2;}
|
|
;
|
|
|
|
callable_variable:
|
|
variable_without_objects { $$ = $1;}
|
|
| dimmable_variable_access { $$ = $1;}
|
|
| '(' variable ')' { $$ = $2;}
|
|
;
|
|
|
|
object_method_call:
|
|
variable T_OBJECT_OPERATOR
|
|
ident sm_typeargs_opt '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$1,$3,$6);}
|
|
| variable T_OBJECT_OPERATOR
|
|
variable_without_objects '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$1,$3,$5);}
|
|
| variable T_OBJECT_OPERATOR
|
|
'{' expr '}' '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$1,$4,$7);}
|
|
| '(' new_expr ')' T_OBJECT_OPERATOR
|
|
ident sm_typeargs_opt '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$2,$5,$8);}
|
|
| '(' new_expr ')' T_OBJECT_OPERATOR
|
|
variable_without_objects '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$2,$5,$7);}
|
|
| '(' new_expr ')' T_OBJECT_OPERATOR
|
|
'{' expr '}' '('
|
|
function_call_parameter_list ')' { _p->onObjectMethodCall($$,$2,$6,$9);}
|
|
;
|
|
|
|
class_method_call:
|
|
static_class_name
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
ident sm_typeargs_opt '('
|
|
function_call_parameter_list ')' { _p->onCall($$,0,$3,$6,&$1);}
|
|
| static_class_name
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
variable_without_objects '('
|
|
function_call_parameter_list ')' { _p->onCall($$,1,$3,$5,&$1);}
|
|
;
|
|
|
|
variable_without_objects:
|
|
reference_variable { $$ = $1;}
|
|
| simple_indirect_reference
|
|
reference_variable { _p->onIndirectRef($$,$1,$2);}
|
|
;
|
|
|
|
reference_variable:
|
|
reference_variable
|
|
'[' dim_offset ']' { _p->onRefDim($$, $1, $3);}
|
|
| reference_variable '{' expr '}' { _p->onRefDim($$, $1, $3);}
|
|
| compound_variable { $$ = $1;}
|
|
;
|
|
compound_variable:
|
|
T_VARIABLE { _p->onSimpleVariable($$, $1);}
|
|
| '$' '{' expr '}' { _p->onDynamicVariable($$, $3, 0);}
|
|
;
|
|
dim_offset:
|
|
expr { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
|
|
simple_indirect_reference:
|
|
'$' { $$ = 1;}
|
|
| simple_indirect_reference '$' { $$++;}
|
|
;
|
|
|
|
variable_no_calls:
|
|
variable_without_objects { $$ = $1;}
|
|
| dimmable_variable_no_calls_access { $$ = $1;}
|
|
| variable_no_calls property_access { _p->onObjectProperty($$,$1,$2);}
|
|
| '(' new_expr ')' property_access { _p->onObjectProperty($$,$2,$4);}
|
|
| static_class_name
|
|
T_PAAMAYIM_NEKUDOTAYIM
|
|
variable_without_objects { _p->onStaticMember($$,$1,$3);}
|
|
| '(' variable ')' { $$ = $2;}
|
|
;
|
|
|
|
dimmable_variable_no_calls:
|
|
| dimmable_variable_no_calls_access { $$ = $1;}
|
|
| variable_no_calls
|
|
property_access_without_variables { _p->onObjectProperty($$,$1,$2);}
|
|
| '(' new_expr ')'
|
|
property_access_without_variables { _p->onObjectProperty($$,$2,$4);}
|
|
| '(' variable ')' { $$ = $2;}
|
|
;
|
|
|
|
assignment_list:
|
|
assignment_list ',' { _p->onAListVar($$,&$1,NULL);}
|
|
| assignment_list ',' variable { _p->onAListVar($$,&$1,&$3);}
|
|
| assignment_list ','
|
|
T_LIST '(' assignment_list ')' { _p->onAListSub($$,&$1,$5);}
|
|
| { _p->onAListVar($$,NULL,NULL);}
|
|
| variable { _p->onAListVar($$,NULL,&$1);}
|
|
| T_LIST '(' assignment_list ')' { _p->onAListSub($$,NULL,$3);}
|
|
;
|
|
|
|
array_pair_list:
|
|
non_empty_array_pair_list
|
|
possible_comma { $$ = $1;}
|
|
| { $$.reset();}
|
|
;
|
|
non_empty_array_pair_list:
|
|
non_empty_array_pair_list
|
|
',' expr T_DOUBLE_ARROW expr { _p->onArrayPair($$,&$1,&$3,$5,0);}
|
|
| non_empty_array_pair_list ',' expr { _p->onArrayPair($$,&$1, 0,$3,0);}
|
|
| expr T_DOUBLE_ARROW expr { _p->onArrayPair($$, 0,&$1,$3,0);}
|
|
| expr { _p->onArrayPair($$, 0, 0,$1,0);}
|
|
| non_empty_array_pair_list
|
|
',' expr T_DOUBLE_ARROW
|
|
'&' variable { _p->onArrayPair($$,&$1,&$3,$6,1);}
|
|
| non_empty_array_pair_list ','
|
|
'&' variable { _p->onArrayPair($$,&$1, 0,$4,1);}
|
|
| expr T_DOUBLE_ARROW '&' variable { _p->onArrayPair($$, 0,&$1,$4,1);}
|
|
| '&' variable { _p->onArrayPair($$, 0, 0,$2,1);}
|
|
;
|
|
|
|
collection_init:
|
|
non_empty_collection_init
|
|
possible_comma { $$ = $1;}
|
|
| { _p->onEmptyCollection($$);}
|
|
;
|
|
non_empty_collection_init:
|
|
non_empty_collection_init
|
|
',' expr T_DOUBLE_ARROW expr { _p->onCollectionPair($$,&$1,&$3,$5);}
|
|
| non_empty_collection_init ',' expr { _p->onCollectionPair($$,&$1, 0,$3);}
|
|
| expr T_DOUBLE_ARROW expr { _p->onCollectionPair($$, 0,&$1,$3);}
|
|
| expr { _p->onCollectionPair($$, 0, 0,$1);}
|
|
;
|
|
|
|
static_collection_init:
|
|
non_empty_static_collection_init
|
|
possible_comma { $$ = $1;}
|
|
| { _p->onEmptyCollection($$);}
|
|
;
|
|
non_empty_static_collection_init:
|
|
non_empty_static_collection_init
|
|
',' static_scalar T_DOUBLE_ARROW
|
|
static_scalar { _p->onCollectionPair($$,&$1,&$3,$5);}
|
|
| non_empty_static_collection_init
|
|
',' static_scalar { _p->onCollectionPair($$,&$1, 0,$3);}
|
|
| static_scalar T_DOUBLE_ARROW
|
|
static_scalar { _p->onCollectionPair($$, 0,&$1,$3);}
|
|
| static_scalar { _p->onCollectionPair($$, 0, 0,$1);}
|
|
;
|
|
|
|
encaps_list:
|
|
encaps_list encaps_var { _p->addEncap($$, &$1, $2, -1);}
|
|
| encaps_list
|
|
T_ENCAPSED_AND_WHITESPACE { _p->addEncap($$, &$1, $2, 0);}
|
|
| encaps_var { _p->addEncap($$, NULL, $1, -1);}
|
|
| T_ENCAPSED_AND_WHITESPACE
|
|
encaps_var { _p->addEncap($$, NULL, $1, 0);
|
|
_p->addEncap($$, &$$, $2, -1); }
|
|
;
|
|
|
|
encaps_var:
|
|
T_VARIABLE { _p->onSimpleVariable($$, $1);}
|
|
| T_VARIABLE '['
|
|
encaps_var_offset ']' { _p->encapRefDim($$, $1, $3);}
|
|
| T_VARIABLE T_OBJECT_OPERATOR
|
|
ident { _p->encapObjProp($$, $1, $3);}
|
|
| T_DOLLAR_OPEN_CURLY_BRACES
|
|
expr '}' { _p->onDynamicVariable($$, $2, 1);}
|
|
| T_DOLLAR_OPEN_CURLY_BRACES
|
|
T_STRING_VARNAME '[' expr ']' '}' { _p->encapArray($$, $2, $4);}
|
|
| T_CURLY_OPEN variable '}' { $$ = $2;}
|
|
;
|
|
encaps_var_offset:
|
|
ident { $$ = $1; $$ = T_STRING;}
|
|
| T_NUM_STRING { $$ = $1; $$ = T_NUM_STRING;}
|
|
| T_VARIABLE { $$ = $1; $$ = T_VARIABLE;}
|
|
;
|
|
|
|
internal_functions:
|
|
T_ISSET '(' variable_list ')' { UEXP($$,$3,T_ISSET,1);}
|
|
| T_EMPTY '(' variable ')' { UEXP($$,$3,T_EMPTY,1);}
|
|
| T_INCLUDE expr { UEXP($$,$2,T_INCLUDE,1);}
|
|
| T_INCLUDE_ONCE expr { UEXP($$,$2,T_INCLUDE_ONCE,1);}
|
|
| T_EVAL '(' expr ')' { UEXP($$,$3,T_EVAL,1);}
|
|
| T_REQUIRE expr { UEXP($$,$2,T_REQUIRE,1);}
|
|
| T_REQUIRE_ONCE expr { UEXP($$,$2,T_REQUIRE_ONCE,1);}
|
|
;
|
|
|
|
variable_list:
|
|
variable { _p->onExprListElem($$, NULL, $1);}
|
|
| variable_list ',' variable { _p->onExprListElem($$, &$1, $3);}
|
|
;
|
|
|
|
class_constant:
|
|
static_class_name
|
|
T_PAAMAYIM_NEKUDOTAYIM ident { _p->onClassConst($$, $1, $3, 0);}
|
|
;
|
|
|
|
/* strict-mode productions -- these allow some extra stuff in strict
|
|
* mode, but simplify down to the original thing
|
|
*/
|
|
|
|
sm_typedef_statement:
|
|
T_TYPE ident '=' sm_type ';' { only_in_strict_mode(_p);
|
|
_p->onTypedef($$, $2, $4); }
|
|
;
|
|
|
|
sm_name_with_type: /* foo -> int foo */
|
|
ident { $$ = $1; }
|
|
| sm_type ident { only_in_strict_mode(_p); $$ = $2; }
|
|
;
|
|
|
|
sm_name_with_typevar: /* foo -> foo<X,Y>; this adds a typevar scope
|
|
* and must be followed by a call to
|
|
* popTypeScope() */
|
|
ident { _p->pushTypeScope(); $$ = $1; }
|
|
| ident
|
|
T_TYPELIST_LT
|
|
sm_typevar_list
|
|
T_TYPELIST_GT { _p->pushTypeScope(); $$ = $1;
|
|
only_in_strict_mode(_p); }
|
|
;
|
|
|
|
sm_typeargs_opt:
|
|
T_TYPELIST_LT
|
|
sm_type_list
|
|
T_TYPELIST_GT { only_in_strict_mode(_p); $$ = $2; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
sm_type_list:
|
|
sm_type
|
|
| sm_type_list ',' sm_type
|
|
;
|
|
|
|
sm_func_type_list:
|
|
sm_type_list ',' T_VARARG { $$.reset(); }
|
|
| sm_type_list { $$.reset(); }
|
|
| T_VARARG { $$.reset(); }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
sm_opt_return_type:
|
|
{ $$.reset(); }
|
|
| ':' sm_type { only_in_strict_mode(_p); $$ = $2; }
|
|
;
|
|
|
|
sm_typevar_list:
|
|
ident ',' sm_typevar_list { _p->addTypeVar($1.text()); }
|
|
| ident { _p->addTypeVar($1.text()); }
|
|
| ident T_AS sm_shape_type
|
|
sm_typevar_list
|
|
| ident T_AS ident ','
|
|
sm_typevar_list { _p->addTypeVar($1.text()); }
|
|
| ident T_AS ident { _p->addTypeVar($1.text()); }
|
|
| ident T_AS sm_shape_type
|
|
;
|
|
|
|
sm_shape_member_type:
|
|
T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
sm_type { validate_shape_keyname($1, _p); }
|
|
;
|
|
|
|
sm_non_empty_shape_member_list:
|
|
sm_non_empty_shape_member_list ','
|
|
sm_shape_member_type
|
|
| sm_shape_member_type
|
|
;
|
|
|
|
sm_shape_member_list:
|
|
sm_non_empty_shape_member_list
|
|
possible_comma { $$ = $1; }
|
|
| /* empty */
|
|
{}
|
|
|
|
sm_shape_type:
|
|
T_SHAPE
|
|
'(' sm_shape_member_list ')' { only_in_strict_mode(_p);
|
|
$$.setText("array"); }
|
|
;
|
|
|
|
/* extends non_empty_type_decl with some more types */
|
|
sm_type:
|
|
/* double-optional types will be rejected by the typechecker; we
|
|
* already allow plenty of nonsense types anyway */
|
|
'?' sm_type { only_in_strict_mode(_p); $$.reset(); }
|
|
| '@' sm_type { only_in_strict_mode(_p); $$.reset(); }
|
|
| ident sm_typeargs_opt { $$ = $1;
|
|
/* if the type annotation is a bound
|
|
typevar we have to strip it */
|
|
if (_p->scanner().isStrictMode() &&
|
|
(_p->isTypeVar($$.text()) ||
|
|
!$$.text().compare("mixed") ||
|
|
!$$.text().compare("this")
|
|
)) {
|
|
$$.reset();
|
|
}
|
|
}
|
|
| T_ARRAY { $$.setText("array"); }
|
|
| sm_shape_type { $$ = $1; }
|
|
| T_ARRAY T_TYPELIST_LT sm_type
|
|
T_TYPELIST_GT { only_in_strict_mode(_p);
|
|
$$.setText("array"); }
|
|
| T_ARRAY T_TYPELIST_LT sm_type ','
|
|
sm_type T_TYPELIST_GT { only_in_strict_mode(_p);
|
|
$$.setText("array"); }
|
|
| T_XHP_LABEL { $1.xhpLabel(); $$ = $1; }
|
|
| '(' T_FUNCTION
|
|
'(' sm_func_type_list ')'
|
|
':' sm_type ')' { only_in_strict_mode(_p); $$.reset(); }
|
|
| '(' sm_type_list ',' sm_type ')' { only_in_strict_mode(_p);
|
|
$$.setText("array"); }
|
|
;
|
|
|
|
sm_type_opt:
|
|
sm_type { $$ = $1; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
%%
|
|
bool Parser::parseImpl() {
|
|
return yyparse(this) == 0;
|
|
}
|