2475 linhas
92 KiB
Plaintext
2475 linhas
92 KiB
Plaintext
%{
|
|
#ifdef TEST_PARSER
|
|
#include "util/parser/test/parser.h"
|
|
#else
|
|
#include "compiler/parser/parser.h"
|
|
#endif
|
|
#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->scanner().hipHopSyntaxEnabled()) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void only_in_hh_syntax(Parser *_p) {
|
|
if (!_p->scanner().hipHopSyntaxEnabled()) {
|
|
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_HACK_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
|
|
|
|
%token T_COMPILER_HALT_OFFSET
|
|
|
|
%%
|
|
|
|
start:
|
|
{ _p->initParseTree(); } top_statement_list { _p->popLabelInfo();
|
|
_p->finiParseTree();}
|
|
;
|
|
|
|
top_statement_list:
|
|
top_statement_list
|
|
top_statement { _p->addTopStatement($2);}
|
|
| { }
|
|
;
|
|
top_statement:
|
|
statement { _p->nns($1.num()); $$ = $1;}
|
|
| function_declaration_statement { _p->nns(); $$ = $1;}
|
|
| class_declaration_statement { _p->nns(); $$ = $1;}
|
|
| trait_declaration_statement { _p->nns(); $$ = $1;}
|
|
| hh_typedef_statement { $$ = $1; }
|
|
| T_HALT_COMPILER '(' ')' ';' { _p->onHaltCompiler();
|
|
_p->finiParseTree();
|
|
YYACCEPT;}
|
|
| T_NAMESPACE namespace_name ';' { _p->onNamespaceStart($2.text(), true);
|
|
$$.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; $$ = $1.num() | 2;}
|
|
;
|
|
namespace_string_base:
|
|
namespace_name { $$ = $1; $$ = $$.num() | 1;}
|
|
| T_NAMESPACE T_NS_SEPARATOR
|
|
namespace_name { $$.set($3.num() | 2, _p->nsDecl($3.text()));}
|
|
| T_NS_SEPARATOR namespace_name { $$ = $2; $$ = $$.num() | 2;}
|
|
;
|
|
namespace_string:
|
|
namespace_string_base { if ($1.num() & 1) {
|
|
$1.setText(_p->resolve($1.text(),0));
|
|
}
|
|
$$ = $1;}
|
|
;
|
|
namespace_string_typeargs:
|
|
namespace_string_base
|
|
hh_typeargs_opt { if ($1.num() & 1) {
|
|
$1.setText(_p->resolve($1.text(),0));
|
|
}
|
|
$$ = $1;}
|
|
;
|
|
class_namespace_string_typeargs:
|
|
namespace_string_base
|
|
hh_typeargs_opt { if ($1.num() & 1) {
|
|
$1.setText(_p->resolve($1.text(),1));
|
|
}
|
|
$$ = $1;}
|
|
;
|
|
constant_declaration:
|
|
constant_declaration ','
|
|
hh_name_with_type
|
|
'=' static_scalar { $3.setText(_p->nsDecl($3.text()));
|
|
on_constant(_p,$$,&$1,$3,$5);}
|
|
| T_CONST hh_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 hh_name_with_typevar { $3.setText(_p->nsDecl($3.text()));
|
|
_p->onFunctionStart($3);
|
|
_p->pushLabelInfo();}
|
|
'(' parameter_list ')'
|
|
hh_opt_return_type
|
|
'{' inner_statement_list '}' { _p->onFunction($$,0,$8,$2,$3,$6,$10,0);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes function_loc
|
|
is_reference hh_name_with_typevar { $4.setText(_p->nsDecl($4.text()));
|
|
_p->onFunctionStart($4);
|
|
_p->pushLabelInfo();}
|
|
'(' parameter_list ')'
|
|
hh_opt_return_type
|
|
'{' inner_statement_list '}' { _p->onFunction($$,0,$9,$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);}
|
|
implements_list
|
|
'{' class_statement_list '}' { Token t_ext, t_imp;
|
|
t_ext.reset(); t_imp.reset();
|
|
_p->onClass($$,T_TRAIT,$2,t_ext,t_imp,
|
|
$6, 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);}
|
|
implements_list
|
|
'{' class_statement_list '}' { Token t_ext, t_imp;
|
|
t_ext.reset(); t_imp.reset();
|
|
_p->onClass($$,T_TRAIT,$3,t_ext,t_imp,
|
|
$7, &$1);
|
|
_p->popClass();
|
|
_p->popTypeScope();}
|
|
;
|
|
class_decl_name:
|
|
hh_name_with_typevar { _p->pushClass(false); $$ = $1;}
|
|
| T_XHP_LABEL { $1.xhpLabel(); _p->pushTypeScope();
|
|
_p->pushClass(true); $$ = $1;}
|
|
;
|
|
interface_decl_name:
|
|
hh_name_with_typevar { _p->pushClass(false); $$ = $1;}
|
|
;
|
|
trait_decl_name:
|
|
hh_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_hh_syntax(_p); $$ = $1; }
|
|
| non_empty_parameter_list
|
|
possible_comma_in_hphp_syntax { $$ = $1;}
|
|
| T_VARARG { only_in_hh_syntax(_p); $$.reset(); }
|
|
| { $$.reset();}
|
|
;
|
|
|
|
non_empty_parameter_list:
|
|
optional_user_attributes
|
|
hh_type_opt T_VARIABLE { _p->onParam($$,NULL,$2,$3,0,NULL,&$1);}
|
|
| optional_user_attributes
|
|
hh_type_opt '&' T_VARIABLE { _p->onParam($$,NULL,$2,$4,1,NULL,&$1);}
|
|
| optional_user_attributes
|
|
hh_type_opt '&' T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,NULL,$2,$4,1,&$6,&$1);}
|
|
| optional_user_attributes
|
|
hh_type_opt T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,NULL,$2,$3,0,&$5,&$1);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
hh_type_opt T_VARIABLE { _p->onParam($$,&$1,$4,$5,0,NULL,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
hh_type_opt '&' T_VARIABLE { _p->onParam($$,&$1,$4,$6,1,NULL,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
hh_type_opt '&' T_VARIABLE
|
|
'=' static_scalar { _p->onParam($$,&$1,$4,$6,1,&$8,&$3);}
|
|
| non_empty_parameter_list ','
|
|
optional_user_attributes
|
|
hh_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
|
|
hh_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 hh_name_with_typevar '('
|
|
{ _p->onMethodStart($4, $1);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
hh_opt_return_type
|
|
method_body
|
|
{ _p->onMethod($$,$1,$9,$3,$4,$7,$10,0);
|
|
_p->popLabelInfo();
|
|
_p->popTypeScope();}
|
|
| non_empty_user_attributes
|
|
method_modifiers function_loc
|
|
is_reference hh_name_with_typevar '('
|
|
{ _p->onMethodStart($5, $2);
|
|
_p->pushLabelInfo();}
|
|
parameter_list ')'
|
|
hh_opt_return_type
|
|
method_body
|
|
{ _p->onMethod($$,$2,$10,$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 ','
|
|
hh_name_with_type '=' static_scalar { _p->onClassConstant($$,&$1,$3,$5);}
|
|
| T_CONST hh_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 ')'
|
|
hh_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 ')'
|
|
hh_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_hh_syntax(_p);
|
|
_p->onArray($$, $3, T_ARRAY); }
|
|
;
|
|
|
|
array_literal:
|
|
T_ARRAY '(' array_pair_list ')' { _p->onArray($$,$3,T_ARRAY);}
|
|
| '[' array_pair_list ']' { _p->onArray($$,$2,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_COMPILER_HALT_OFFSET { $$ = $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_COMPILER_HALT_OFFSET { _p->onScalar($$, T_COMPILER_HALT_OFFSET, $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_hh_syntax(_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_hh_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);}
|
|
| '[' static_array_pair_list_ae ']' { _p->onArray($$,$2,T_ARRAY);}
|
|
| T_SHAPE '('
|
|
static_shape_pair_list_ae ')' { only_in_hh_syntax(_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 hh_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 hh_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 hh_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);}
|
|
;
|
|
|
|
/* hack productions -- these allow some extra stuff in hack
|
|
* mode, but simplify down to the original thing
|
|
*/
|
|
|
|
hh_typedef_statement:
|
|
T_TYPE hh_name_with_typevar
|
|
'=' hh_type ';' { only_in_hh_syntax(_p);
|
|
_p->onTypedef($$, $2, $4);
|
|
_p->popTypeScope(); }
|
|
;
|
|
|
|
hh_name_with_type: /* foo -> int foo */
|
|
ident { $$ = $1; }
|
|
| hh_type ident { only_in_hh_syntax(_p); $$ = $2; }
|
|
;
|
|
|
|
hh_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
|
|
hh_typevar_list
|
|
T_TYPELIST_GT { _p->pushTypeScope(); $$ = $1;
|
|
only_in_hh_syntax(_p); }
|
|
;
|
|
|
|
hh_typeargs_opt:
|
|
T_TYPELIST_LT
|
|
hh_type_list
|
|
T_TYPELIST_GT { only_in_hh_syntax(_p); $$ = $2; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
hh_type_list:
|
|
hh_type { Token t; t.reset();
|
|
_p->onTypeList($1, t);
|
|
$$ = $1; }
|
|
| hh_type_list ',' hh_type { _p->onTypeList($1, $3);
|
|
$$ = $1; }
|
|
;
|
|
|
|
hh_func_type_list:
|
|
hh_type_list ',' T_VARARG { $$ = $1; }
|
|
| hh_type_list { $$ = $1; }
|
|
| T_VARARG { $$.reset(); }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
hh_opt_return_type:
|
|
{ $$.reset(); }
|
|
| ':' hh_type { only_in_hh_syntax(_p); $$ = $2; }
|
|
;
|
|
|
|
hh_typevar_list:
|
|
namespace_string ','
|
|
hh_typevar_list { _p->addTypeVar($1.text()); }
|
|
| namespace_string { _p->addTypeVar($1.text()); }
|
|
| namespace_string T_AS
|
|
hh_shape_type hh_typevar_list
|
|
| namespace_string T_AS
|
|
namespace_string ','
|
|
hh_typevar_list { _p->addTypeVar($1.text()); }
|
|
| namespace_string T_AS
|
|
namespace_string { _p->addTypeVar($1.text()); }
|
|
| namespace_string T_AS
|
|
hh_shape_type
|
|
;
|
|
|
|
hh_shape_member_type:
|
|
T_CONSTANT_ENCAPSED_STRING
|
|
T_DOUBLE_ARROW
|
|
hh_type { validate_shape_keyname($1, _p); }
|
|
;
|
|
|
|
hh_non_empty_shape_member_list:
|
|
hh_non_empty_shape_member_list ','
|
|
hh_shape_member_type
|
|
| hh_shape_member_type
|
|
;
|
|
|
|
hh_shape_member_list:
|
|
hh_non_empty_shape_member_list
|
|
possible_comma { $$ = $1; }
|
|
| /* empty */
|
|
{}
|
|
|
|
hh_shape_type:
|
|
T_SHAPE
|
|
'(' hh_shape_member_list ')' { only_in_hh_syntax(_p);
|
|
$$.setText("array"); }
|
|
;
|
|
|
|
/* extends non_empty_type_decl with some more types */
|
|
hh_type:
|
|
/* double-optional types will be rejected by the typechecker; we
|
|
* already allow plenty of nonsense types anyway */
|
|
'?' hh_type { only_in_hh_syntax(_p);
|
|
_p->onTypeSpecialization($2, '?');
|
|
$$ = $2; }
|
|
| '@' hh_type { only_in_hh_syntax(_p);
|
|
_p->onTypeSpecialization($2, '@');
|
|
$$ = $2; }
|
|
| namespace_string hh_typeargs_opt { _p->onTypeAnnotation($$, $1, $2); }
|
|
| T_ARRAY { Token t; t.reset();
|
|
$1.setText("array");
|
|
_p->onTypeAnnotation($$, $1, t); }
|
|
| hh_shape_type { $$ = $1; }
|
|
| T_ARRAY T_TYPELIST_LT hh_type
|
|
T_TYPELIST_GT { only_in_hh_syntax(_p);
|
|
$1.setText("array");
|
|
_p->onTypeAnnotation($$, $1, $3); }
|
|
| T_ARRAY T_TYPELIST_LT hh_type ','
|
|
hh_type T_TYPELIST_GT { only_in_hh_syntax(_p);
|
|
_p->onTypeList($3, $5);
|
|
$1.setText("array");
|
|
_p->onTypeAnnotation($$, $1, $3); }
|
|
| T_XHP_LABEL { $1.xhpLabel();
|
|
Token t; t.reset();
|
|
_p->onTypeAnnotation($$, $1, t);
|
|
_p->onTypeSpecialization($$, 'x'); }
|
|
| '(' T_FUNCTION
|
|
'(' hh_func_type_list ')'
|
|
':' hh_type ')' { only_in_hh_syntax(_p);
|
|
_p->onTypeList($7, $4);
|
|
_p->onTypeAnnotation($$, $2, $7);
|
|
_p->onTypeSpecialization($$, 'f'); }
|
|
| '(' hh_type_list ',' hh_type ')' { only_in_hh_syntax(_p);
|
|
_p->onTypeList($2, $4);
|
|
Token t; t.reset(); t.setText("array");
|
|
_p->onTypeAnnotation($$, t, $2);
|
|
_p->onTypeSpecialization($$, 't'); }
|
|
;
|
|
|
|
hh_type_opt:
|
|
hh_type { $$ = $1; }
|
|
| { $$.reset(); }
|
|
;
|
|
|
|
%%
|
|
bool Parser::parseImpl() {
|
|
return yyparse(this) == 0;
|
|
}
|