PageRenderTime 74ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 1ms

/hphp/parser/xhpast2/parser.h

http://github.com/facebook/hiphop-php
C Header | 1610 lines | 1342 code | 149 blank | 119 comment | 113 complexity | 0544d1e2763078328b424a37eb8b7d54 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_PARSER_XHPAST2_H_
  17. #define incl_HPHP_PARSER_XHPAST2_H_
  18. #include <stdexcept>
  19. #include <iostream>
  20. #include <cstdarg>
  21. #include "folly/Format.h"
  22. #include "folly/String.h"
  23. #include "hphp/parser/parser.h"
  24. #include "astnode.hpp"
  25. #define HPHP_PARSER_NS XHPAST2
  26. #define HPHP_PARSER_ERROR(fmt, p, args...) \
  27. throw std::runtime_error(folly::format( \
  28. "{}:{}:{}", (p)->file(), (p)->line1(), \
  29. folly::stringPrintf(fmt, ##args)).str())
  30. namespace HPHP { namespace HPHP_PARSER_NS {
  31. extern bool g_verifyMode;
  32. //////////////////////////////////////////////////////////////////////
  33. struct ExtraInfo {
  34. virtual ~ExtraInfo() {}
  35. };
  36. struct OnNameEI : ExtraInfo {
  37. HPHP::ParserBase::NameKind kind;
  38. explicit OnNameEI(HPHP::ParserBase::NameKind k) : kind(k) {};
  39. };
  40. struct OnVariableEI : ExtraInfo {
  41. bool constant;
  42. const std::string& docComment;
  43. OnVariableEI(bool c, const std::string& dc) : constant(c), docComment(dc) {}
  44. };
  45. struct OnDynamicVariableEI : ExtraInfo {
  46. bool encap;
  47. explicit OnDynamicVariableEI(bool e) : encap(e) {}
  48. };
  49. struct OnCallParamEI : ExtraInfo {
  50. bool ref;
  51. explicit OnCallParamEI(bool r) : ref(r) {}
  52. };
  53. struct OnCallEI : ExtraInfo {
  54. bool dynamic;
  55. bool fromCompiler;
  56. OnCallEI(bool d, bool f) : dynamic(d), fromCompiler(f) {}
  57. };
  58. struct OnEncapsListEI : ExtraInfo {
  59. int type;
  60. explicit OnEncapsListEI(int t) : type(t) {}
  61. };
  62. struct AddEncapEI : ExtraInfo {
  63. int type;
  64. explicit AddEncapEI(int t) : type(t) {}
  65. };
  66. struct OnScalarEI : ExtraInfo {
  67. int type;
  68. explicit OnScalarEI(int t) : type(t) {}
  69. };
  70. struct OnListAssignmentEI : ExtraInfo {
  71. bool rhsFirst;
  72. explicit OnListAssignmentEI(bool rhs) : rhsFirst(rhs) {}
  73. };
  74. struct OnAssignEI : ExtraInfo {
  75. bool ref;
  76. bool rhsFirst;
  77. OnAssignEI(bool r, bool rhs) : ref(r), rhsFirst(rhs) {}
  78. };
  79. struct OnUnaryOpExpEI : ExtraInfo {
  80. int op;
  81. bool front;
  82. OnUnaryOpExpEI(int o, bool f) : op(o), front(f) {}
  83. };
  84. struct OnBinaryOpExpEI : ExtraInfo {
  85. int op;
  86. explicit OnBinaryOpExpEI(int o) : op(o) {}
  87. };
  88. struct OnArrayEI : ExtraInfo {
  89. int op;
  90. explicit OnArrayEI(int o) : op(o) {}
  91. };
  92. struct OnArrayPairEI : ExtraInfo {
  93. bool ref;
  94. explicit OnArrayPairEI(bool r) : ref(r) {}
  95. };
  96. struct OnClassConstEI : ExtraInfo {
  97. bool text;
  98. explicit OnClassConstEI(bool t) : text(t) {}
  99. };
  100. struct OnParamEI : ExtraInfo {
  101. bool ref;
  102. explicit OnParamEI(bool r) : ref(r) {}
  103. };
  104. struct OnClassEI : ExtraInfo {
  105. int type;
  106. explicit OnClassEI(int t) : type(t) {}
  107. };
  108. struct OnMethodEI : ExtraInfo {
  109. bool reloc;
  110. explicit OnMethodEI(bool r) : reloc(r) {}
  111. };
  112. struct OnReturnEI : ExtraInfo {
  113. bool checkYield;
  114. explicit OnReturnEI(bool c) : checkYield(c) {}
  115. };
  116. struct OnEchoEI : ExtraInfo {
  117. bool html;
  118. explicit OnEchoEI(bool h) : html(h) {}
  119. };
  120. struct OnClosureEI : ExtraInfo {
  121. bool is_static;
  122. explicit OnClosureEI(bool i) : is_static(i) {}
  123. };
  124. struct OnClosureParamEI : ExtraInfo {
  125. bool ref;
  126. explicit OnClosureParamEI(bool r) : ref(r) {}
  127. };
  128. struct OnGotoEI : ExtraInfo {
  129. bool limited;
  130. explicit OnGotoEI(bool l) : limited(l) {}
  131. };
  132. struct OnTypeSpecializationEI : ExtraInfo {
  133. char specialization;
  134. explicit OnTypeSpecializationEI(char s) : specialization(s) {}
  135. };
  136. enum NodeType {
  137. RAW = 0,
  138. ONNAME = 1,
  139. ONVARIABLE = 2,
  140. ONSTATICVARIABLE = 3,
  141. ONCLASSVARIABLESTART = 4,
  142. ONCLASSVARIABLE = 5,
  143. ONCLASSCONSTANT = 6,
  144. ONSIMPLEVARIABLE = 7,
  145. ONSYNTHESIZEDVARIABLE = 8,
  146. ONDYNAMICVARIABLE = 9,
  147. ONINDIRECTREF = 10,
  148. ONSTATICMEMBER = 11,
  149. ONREFDIM = 12,
  150. ONCALLPARAM = 13,
  151. ONCALL = 14,
  152. ONENCAPSLIST = 15,
  153. ADDENCAP = 16,
  154. ENCAPREFDIM = 17,
  155. ENCAPOBJPROP = 18,
  156. ENCAPARRAY = 19,
  157. ONCONSTANTVALUE = 20,
  158. ONSCALAR = 21,
  159. ONEXPRLISTELEM = 22,
  160. ONOBJECTPROPERTY = 23,
  161. ONOBJECTMETHODCALL = 24,
  162. ONLISTASSIGNMENT = 25,
  163. ONALISTVAR = 26,
  164. ONALISTSUB = 27,
  165. ONASSIGN = 28,
  166. ONASSIGNNEW = 29,
  167. ONNEWOBJECT = 30,
  168. ONUNARYOPEXP = 31,
  169. ONBINARYOPEXP = 32,
  170. ONQOP = 33,
  171. ONARRAY = 34,
  172. ONARRAYPAIR = 35,
  173. ONCOLLECTIONPAIR = 36,
  174. ONUSERATTRIBUTE = 37,
  175. ONCLASSCONST = 38,
  176. ONFUNCTION = 39,
  177. ONPARAM = 40,
  178. ONCLASS = 41,
  179. ONINTERFACE = 42,
  180. ONINTERFACENAME = 43,
  181. ONTRAITUSE = 44,
  182. ONTRAITNAME = 45,
  183. ONTRAITRULE = 46,
  184. ONTRAITPRECRULE = 47,
  185. ONTRAITALIASRULESTART = 48,
  186. ONTRAITALIASRULEMODIFY = 49,
  187. ONMETHOD = 50,
  188. ONMEMBERMODIFIER = 51,
  189. ONSTATEMENTLISTSTART = 52,
  190. ADDSTATEMENT = 53,
  191. ONCLASSSTATEMENT = 54,
  192. FINISHSTATEMENT = 55,
  193. ONBLOCK = 56,
  194. ONIF = 57,
  195. ONELSEIF = 58,
  196. ONWHILE = 59,
  197. ONDO = 60,
  198. ONFOR = 61,
  199. ONSWITCH = 62,
  200. ONCASE = 63,
  201. ONBREAK = 64,
  202. ONCONTINUE = 65,
  203. ONRETURN = 66,
  204. ONYIELD = 67,
  205. ONYIELDBREAK = 68,
  206. ONGLOBAL = 69,
  207. ONGLOBALVAR = 70,
  208. ONSTATIC = 71,
  209. ONECHO = 72,
  210. ONUNSET = 73,
  211. ONEXPSTATEMENT = 74,
  212. ONFOREACH = 75,
  213. ONTRYCATCHFINALLY = 76,
  214. ONTRYFINALLY = 77,
  215. ONCATCH = 78,
  216. ONFINALLY = 79,
  217. ONTHROW = 80,
  218. ONCLOSURE = 81,
  219. ONCLOSUREPARAM = 82,
  220. ONLABEL = 83,
  221. ONGOTO = 84,
  222. ONTYPEDEF = 85,
  223. ONTYPEANNOTATION = 86,
  224. ONTYPELIST = 87,
  225. ONTYPESPECIALIZATION = 88,
  226. ONYIELDPAIR = 89,
  227. ONAWAIT = 90,
  228. };
  229. struct Token : ScannerToken {
  230. // this parser implementation could leak memory and is unsuitable for long
  231. // running processes
  232. NodeType nodeType;
  233. ExtraInfo *extra;
  234. std::vector<Token *> children;
  235. Token() : nodeType(RAW),extra(nullptr) {}
  236. Token& operator=(int num) {
  237. ScannerToken::m_num = num;
  238. return *this;
  239. }
  240. Token& operator=(Token& other) {
  241. ScannerToken::operator=(other);
  242. nodeType = other.nodeType;
  243. extra = other.extra;
  244. children.clear();
  245. appendChildren(&other);
  246. return *this;
  247. }
  248. Token* operator->() {
  249. return this;
  250. }
  251. Token& operator+(const char* str) {
  252. ScannerToken::m_text += str;
  253. return *this;
  254. }
  255. Token& operator+(const Token& token) {
  256. ScannerToken::m_num += token.m_num;
  257. ScannerToken::m_text += token.m_text;
  258. return *this;
  259. }
  260. Token& appendChild(Token *token) {
  261. if (token) {
  262. Token *c = new Token();
  263. *c = *token;
  264. children.push_back(c);
  265. } else {
  266. children.push_back(token);
  267. }
  268. return *this;
  269. }
  270. Token& appendChildren(Token *token) {
  271. for (std::vector<Token *>::iterator i = token->children.begin();
  272. i != token->children.end(); ++i) {
  273. children.push_back(*i);
  274. }
  275. return *this;
  276. }
  277. Token& setNodeType(NodeType t) {
  278. nodeType = t;
  279. children.clear();
  280. extra = nullptr;
  281. return *this;
  282. }
  283. Token& setExtra(ExtraInfo *ei) {
  284. extra = ei;
  285. return *this;
  286. }
  287. friend std::ostream& operator<<(std::ostream& out, Token& t) {
  288. if (t.nodeType == RAW) {
  289. out << "RAW:" << t.m_text;
  290. } else {
  291. out << "[" << t.nodeType << ":" << t.m_num << ":" << t.m_id;
  292. if (t.children.size() > 0) {
  293. std::cout << " [";
  294. for (int i = 0; i < t.children.size(); i++) {
  295. Token *c = t.children[i];
  296. if (c) {
  297. out << *c;
  298. } else {
  299. out << "NULL";
  300. }
  301. if (i < t.children.size() - 1) {
  302. out << ",";
  303. }
  304. }
  305. std::cout << "]";
  306. }
  307. out << "]";
  308. }
  309. return out;
  310. // return out << t.m_text << ":" << t.m_num << ":" << t.m_id;
  311. }
  312. };
  313. struct XHPASTTokenListener : HPHP::TokenListener {
  314. std::vector<xhpast::Token*> tokens;
  315. virtual int publish(const char *rawText, int rawLeng, int type) {
  316. // single chars like ':' with no explicit token type
  317. if ((type == -1) && (rawLeng == 1)) {
  318. type = (unsigned int)rawText[0];
  319. }
  320. tokens.push_back(
  321. new xhpast::Token((unsigned int)type,
  322. const_cast<char*>(rawText),
  323. (unsigned int)rawLeng)
  324. );
  325. return tokens.size() - 1;
  326. }
  327. friend std::ostream& operator<<(std::ostream& out, XHPASTTokenListener& l) {
  328. for (std::vector<xhpast::Token*>::iterator it = l.tokens.begin();
  329. it != l.tokens.end(); ++it) {
  330. out << "[" << (*it)->type << "," << (*it)->value.size() << "]";
  331. }
  332. return out;
  333. }
  334. ~XHPASTTokenListener() {
  335. for (std::vector<xhpast::Token*>::iterator it = tokens.begin();
  336. it != tokens.end(); ++it) {
  337. // std::cout << "[" << (*it)->value << "," << (*it)->type << "]";
  338. delete (*it);
  339. }
  340. }
  341. };
  342. /*
  343. * Parser that creates an AST
  344. */
  345. struct Parser : ParserBase {
  346. XHPASTTokenListener m_listener;
  347. explicit Parser(Scanner& scanner,
  348. const char* filename)
  349. : ParserBase(scanner, filename) {
  350. scanner.setListener(dynamic_cast<HPHP::TokenListener*>(&m_listener));
  351. }
  352. #define X(...)
  353. //#define X(...) traceCb(__FUNCTION__,## __VA_ARGS__)
  354. void fatal(const Location* loc, const char* msg) {
  355. throw std::runtime_error(folly::format(
  356. "{}:{}: {}", m_fileName, m_loc.line0, msg).str());
  357. }
  358. void parseFatal(const Location* loc, const char* msg) {
  359. throw std::runtime_error(folly::format(
  360. "{}:{}: {}", m_fileName, m_loc.line0, msg).str());
  361. }
  362. void parse() {
  363. if (!parseImpl()) {
  364. error("parse failure: %s\n", getMessage().c_str());
  365. }
  366. }
  367. public:
  368. bool parseImpl();
  369. void error(const char* fmt, ...) {
  370. va_list ap;
  371. va_start(ap, fmt);
  372. std::string msg;
  373. Util::string_vsnprintf(msg, fmt, ap);
  374. va_end(ap);
  375. throw std::runtime_error(folly::format(
  376. "{}:{}: {}", m_fileName, m_loc.line0, msg).str());
  377. }
  378. void invalidateGoto(TStatementPtr, ParserBase::GotoError) { }
  379. void invalidateLabel(TStatementPtr) { }
  380. void* extractStatement(ScannerToken*) { return nullptr; }
  381. bool enableFinallyStatement() { return true; }
  382. IMPLEMENT_XHP_ATTRIBUTES;
  383. Token tree;
  384. void initParseTree() {}
  385. void finiParseTree() {}
  386. void onName(Token& out, Token& name, NameKind kind) {
  387. out.setNodeType(ONNAME).setExtra(new OnNameEI(kind)).appendChild(&name);
  388. }
  389. void onVariable(Token& out, Token* exprs, Token& var, Token* value,
  390. bool constant = false,
  391. const std::string& docComment = "") {
  392. out.setNodeType(ONVARIABLE).setExtra(new OnVariableEI(constant, docComment))
  393. .appendChild(exprs).appendChild(&var).appendChild(value);
  394. }
  395. void onStaticVariable(Token &out, Token *exprs, Token &var, Token *value) {
  396. out.setNodeType(ONSTATICVARIABLE).appendChild(exprs).appendChild(&var)
  397. .appendChild(value);
  398. }
  399. void onClassVariableModifer(Token &mod) { /* TODO */
  400. X(mod);
  401. }
  402. void onClassVariableStart(Token &out, Token *modifiers, Token &decl,
  403. Token *type) {
  404. out.setNodeType(ONCLASSVARIABLESTART).appendChild(modifiers)
  405. .appendChild(&decl).appendChild(type);
  406. }
  407. void onClassVariable(Token &out, Token *exprs, Token &var, Token *value) {
  408. out.setNodeType(ONCLASSVARIABLE).appendChild(exprs).appendChild(&var)
  409. .appendChild(value);
  410. }
  411. void onClassConstant(Token &out, Token *exprs, Token &var, Token &value) {
  412. out.setNodeType(ONCLASSCONSTANT).appendChild(exprs).appendChild(&var)
  413. .appendChild(&value);
  414. }
  415. void onSimpleVariable(Token &out, Token &var) {
  416. out.setNodeType(ONSIMPLEVARIABLE).appendChild(&var);
  417. }
  418. void onSynthesizedVariable(Token& out, Token &var) {
  419. out.setNodeType(ONSYNTHESIZEDVARIABLE).appendChild(&var);
  420. }
  421. void onDynamicVariable(Token &out, Token &expr, bool encap) {
  422. out.setNodeType(ONDYNAMICVARIABLE).appendChild(&expr)
  423. .setExtra(new OnDynamicVariableEI(encap));
  424. }
  425. void onIndirectRef(Token &out, Token &refCount, Token &var) {
  426. out.setNodeType(ONINDIRECTREF).appendChild(&refCount).appendChild(&var);
  427. }
  428. void onStaticMember(Token &out, Token &cls, Token &name) {
  429. out.setNodeType(ONSTATICMEMBER).appendChild(&cls).appendChild(&name);
  430. }
  431. void onRefDim(Token &out, Token &var, Token &offset) {
  432. out.setNodeType(ONREFDIM).appendChild(&var).appendChild(&offset);
  433. }
  434. void onCallParam(Token &out, Token *params, Token &expr, bool ref) {
  435. out.setNodeType(ONCALLPARAM).appendChild(params).appendChild(&expr)
  436. .setExtra(new OnCallParamEI(ref));
  437. }
  438. void onCall(Token &out, bool dynamic, Token &name, Token &params,
  439. Token *cls, bool fromCompiler = false) {
  440. out.setNodeType(ONCALL).appendChild(&name).appendChild(&params)
  441. .appendChild(cls).setExtra(new OnCallEI(dynamic, fromCompiler));
  442. }
  443. void onEncapsList(Token &out, int type, Token &list) {
  444. out.setNodeType(ONENCAPSLIST).appendChild(&list)
  445. .setExtra(new OnEncapsListEI(type));
  446. }
  447. void addEncap(Token &out, Token *list, Token &expr, int type) {
  448. out.setNodeType(ADDENCAP).appendChild(list).appendChild(&expr)
  449. .setExtra(new AddEncapEI(type));
  450. }
  451. void encapRefDim(Token &out, Token &var, Token &offset) {
  452. out.setNodeType(ENCAPREFDIM).appendChild(&var).appendChild(&offset);
  453. }
  454. void encapObjProp(Token &out, Token &var, Token &name) {
  455. out.setNodeType(ENCAPOBJPROP).appendChild(&var).appendChild(&name);
  456. }
  457. void encapArray(Token &out, Token &var, Token &expr) {
  458. out.setNodeType(ENCAPARRAY).appendChild(&var).appendChild(&expr);
  459. }
  460. void onConstantValue(Token &out, Token &constant) {
  461. out.setNodeType(ONCONSTANTVALUE).appendChild(&constant);
  462. }
  463. void onScalar(Token &out, int type, Token &scalar) {
  464. out.setNodeType(ONSCALAR).appendChild(&scalar)
  465. .setExtra(new OnScalarEI(type));
  466. }
  467. void onExprListElem(Token &out, Token *exprs, Token &expr) {
  468. out.setNodeType(ONEXPRLISTELEM).appendChild(exprs).appendChild(&expr);
  469. }
  470. void onObjectProperty(Token &out, Token &base, Token &prop) {
  471. out.setNodeType(ONOBJECTPROPERTY).appendChild(&base).appendChild(&prop);
  472. }
  473. void onObjectMethodCall(Token &out, Token &base, Token &prop,
  474. Token &params) {
  475. out.setNodeType(ONOBJECTMETHODCALL).appendChild(&base).appendChild(&prop)
  476. .appendChild(&params);
  477. }
  478. void onListAssignment(Token &out, Token &vars, Token *expr,
  479. bool rhsFirst = false) {
  480. out.setNodeType(ONLISTASSIGNMENT).appendChild(&vars).appendChild(expr)
  481. .setExtra(new OnListAssignmentEI(rhsFirst));
  482. }
  483. void onAListVar(Token &out, Token *list, Token *var) {
  484. out.setNodeType(ONALISTVAR).appendChild(list).appendChild(var);
  485. }
  486. void onAListSub(Token &out, Token *list, Token &sublist) {
  487. out.setNodeType(ONALISTSUB).appendChild(list).appendChild(&sublist);
  488. }
  489. void onAssign(Token& out, Token& var, Token& expr, bool ref,
  490. bool rhsFirst = false) {
  491. out.setNodeType(ONASSIGN).appendChild(&var).appendChild(&expr)
  492. .setExtra(new OnAssignEI(ref, rhsFirst));
  493. }
  494. void onAssignNew(Token &out, Token &var, Token &name, Token &args) {
  495. out.setNodeType(ONASSIGNNEW).appendChild(&var).appendChild(&name)
  496. .appendChild(&args);
  497. }
  498. void onNewObject(Token &out, Token &name, Token &args) {
  499. out.setNodeType(ONNEWOBJECT).appendChild(&name).appendChild(&args);
  500. }
  501. void onUnaryOpExp(Token &out, Token &operand, int op, bool front) {
  502. out.setNodeType(ONUNARYOPEXP).appendChild(&operand)
  503. .setExtra(new OnUnaryOpExpEI(op, front));
  504. }
  505. void onBinaryOpExp(Token &out, Token &operand1, Token &operand2, int op) {
  506. out.setNodeType(ONBINARYOPEXP).appendChild(&operand1).appendChild(&operand2)
  507. .setExtra(new OnBinaryOpExpEI(op));
  508. }
  509. void onQOp(Token &out, Token &exprCond, Token *expYes, Token &expNo) {
  510. out.setNodeType(ONQOP).appendChild(&exprCond).appendChild(expYes)
  511. .appendChild(&expNo);
  512. }
  513. void onArray(Token &out, Token &pairs, int op = T_ARRAY) {
  514. out.setNodeType(ONARRAY).appendChild(&pairs)
  515. .setExtra(new OnArrayEI(op));
  516. }
  517. void onArrayPair(Token &out, Token *pairs, Token *name, Token &value,
  518. bool ref) {
  519. out.setNodeType(ONARRAYPAIR).appendChild(pairs).appendChild(name)
  520. .appendChild(&value).setExtra(new OnArrayPairEI(ref));
  521. }
  522. void onEmptyCollection(Token &out) { X(); /* TODO */}
  523. void onCollectionPair(Token &out, Token *pairs, Token *name, Token &value) {
  524. out.setNodeType(ONCOLLECTIONPAIR).appendChild(pairs).appendChild(name)
  525. .appendChild(&value);
  526. }
  527. void onUserAttribute(Token &out, Token *attrList, Token &name,
  528. Token &value) {
  529. out.setNodeType(ONUSERATTRIBUTE).appendChild(attrList).appendChild(&name)
  530. .appendChild(&value);
  531. }
  532. void onClassConst(Token &out, Token &cls, Token &name, bool text) {
  533. out.setNodeType(ONCLASSCONST).appendChild(&cls).appendChild(&name)
  534. .setExtra(new OnClassConstEI(text));
  535. }
  536. void fixStaticVars() { /* TODO */}
  537. void onFunctionStart(Token& name, bool doPushComment = true) {
  538. /* TODO */
  539. }
  540. void onClosureStart(Token& name) {
  541. /* TODO */
  542. }
  543. void onFunction(Token& out, Token *modifiers, Token& ret, Token& ref,
  544. Token& name, Token& params, Token& stmt, Token* attr) {
  545. out.setNodeType(ONFUNCTION).appendChild(modifiers).appendChild(&ret)
  546. .appendChild(&ref).appendChild(&name).appendChild(&params)
  547. .appendChild(&stmt).appendChild(attr);
  548. }
  549. void onParam(Token &out, Token *params, Token &type, Token &var,
  550. bool ref, Token *defValue, Token *attr, Token *mods) {
  551. out.setNodeType(ONPARAM).appendChild(params).appendChild(&type)
  552. .appendChild(&var).appendChild(defValue).appendChild(attr)
  553. .appendChild(mods).setExtra(new OnParamEI(ref));
  554. }
  555. void onClassStart(int type, Token &name) {
  556. /* TODO */
  557. }
  558. void onClass(Token &out, int type, Token &name, Token &base,
  559. Token &baseInterface, Token &stmt, Token *attr) {
  560. out.setNodeType(ONCLASS).appendChild(&name).appendChild(&base)
  561. .appendChild(&baseInterface).appendChild(&stmt).appendChild(attr)
  562. .setExtra(new OnClassEI(type));
  563. }
  564. void onInterface(Token &out, Token &name, Token &base, Token &stmt,
  565. Token *attr) {
  566. out.setNodeType(ONINTERFACE).appendChild(&name).appendChild(&base)
  567. .appendChild(&stmt).appendChild(attr);
  568. }
  569. void onInterfaceName(Token &out, Token *names, Token &name) {
  570. out.setNodeType(ONINTERFACENAME).appendChild(names).appendChild(&name);
  571. }
  572. void onTraitUse(Token &out, Token &traits, Token &rules) {
  573. out.setNodeType(ONTRAITUSE).appendChild(&traits).appendChild(&rules);
  574. }
  575. void onTraitName(Token &out, Token *names, Token &name) {
  576. out.setNodeType(ONTRAITNAME).appendChild(names).appendChild(&name);
  577. }
  578. void onTraitRule(Token &out, Token &stmtList, Token &newStmt) {
  579. out.setNodeType(ONTRAITRULE).appendChild(&stmtList).appendChild(&newStmt);
  580. }
  581. void onTraitPrecRule(Token &out, Token &className, Token &methodName,
  582. Token &otherClasses) {
  583. out.setNodeType(ONTRAITPRECRULE).appendChild(&className)
  584. .appendChild(&methodName).appendChild(&otherClasses);
  585. }
  586. void onTraitAliasRuleStart(Token &out, Token &className, Token &methodName) {
  587. out.setNodeType(ONTRAITALIASRULESTART).appendChild(&className)
  588. .appendChild(&methodName);
  589. }
  590. void onTraitAliasRuleModify(Token &out, Token &rule, Token &accessModifiers,
  591. Token &newMethodName) {
  592. out.setNodeType(ONTRAITALIASRULEMODIFY).appendChild(&rule)
  593. .appendChild(&accessModifiers).appendChild(&newMethodName);
  594. }
  595. void onMethodStart(Token &name, Token &mods, bool doPushComment = true) {
  596. /* TODO */
  597. }
  598. void onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
  599. Token &name, Token &params, Token &stmt, Token *attr,
  600. bool reloc = true) {
  601. // modifiers could be garbage Tokens if no modifier specified.
  602. out.setNodeType(ONMETHOD).appendChild(&modifiers).appendChild(&ret)
  603. .appendChild(&ref).appendChild(&name).appendChild(&params)
  604. .appendChild(&stmt).appendChild(attr).setExtra(new OnMethodEI(reloc));
  605. }
  606. void onMemberModifier(Token &out, Token *modifiers, Token &modifier) {
  607. out.setNodeType(ONMEMBERMODIFIER).appendChild(modifiers)
  608. .appendChild(&modifier);
  609. }
  610. void onStatementListStart(Token &out) {
  611. out.setNodeType(ONSTATEMENTLISTSTART);
  612. }
  613. void addTopStatement(Token &new_stmt) { this->tree = new_stmt; }
  614. // TODO
  615. void onHaltCompiler() {}
  616. void addStatement(Token& out, Token& stmts, Token& new_stmt) {
  617. out.setNodeType(ADDSTATEMENT).appendChild(&stmts).appendChild(&new_stmt);
  618. }
  619. void onClassStatement(Token &out, Token &stmts, Token &new_stmt) {
  620. out.setNodeType(ONCLASSSTATEMENT).appendChild(&stmts)
  621. .appendChild(&new_stmt);
  622. }
  623. void finishStatement(Token& out, Token& stmts) {
  624. out.setNodeType(FINISHSTATEMENT).appendChild(&stmts);
  625. }
  626. void onBlock(Token& out, Token& stmts) {
  627. out.setNodeType(ONBLOCK).appendChild(&stmts);
  628. }
  629. void onIf(Token &out, Token &cond, Token &stmt, Token &elseifs,
  630. Token &elseStmt) {
  631. out.setNodeType(ONIF).appendChild(&cond).appendChild(&stmt)
  632. .appendChild(&elseifs).appendChild(&elseStmt);
  633. }
  634. void onElseIf(Token& out, Token& elseifs, Token& cond, Token& stmt) {
  635. out.setNodeType(ONELSEIF).appendChild(&elseifs).appendChild(&cond)
  636. .appendChild(&stmt);
  637. }
  638. void onWhile(Token &out, Token &cond, Token &stmt) {
  639. out.setNodeType(ONWHILE).appendChild(&cond).appendChild(&stmt);
  640. }
  641. void onDo(Token &out, Token &stmt, Token &cond) {
  642. out.setNodeType(ONDO).appendChild(&stmt).appendChild(&cond);
  643. }
  644. void onFor(Token &out, Token &expr1, Token &expr2, Token &expr3,
  645. Token &stmt) {
  646. out.setNodeType(ONFOR).appendChild(&expr1).appendChild(&expr2)
  647. .appendChild(&expr3).appendChild(&stmt);
  648. }
  649. void onSwitch(Token &out, Token &expr, Token &cases) {
  650. out.setNodeType(ONSWITCH).appendChild(&expr).appendChild(&cases);
  651. }
  652. void onCase(Token &out, Token &cases, Token *cond, Token &stmt) {
  653. out.setNodeType(ONCASE).appendChild(&cases).appendChild(cond)
  654. .appendChild(&stmt);
  655. }
  656. void onBreakContinue(Token &out, bool isBreak, Token *expr) {
  657. if (isBreak) {
  658. out.setNodeType(ONBREAK).appendChild(expr);
  659. } else {
  660. out.setNodeType(ONCONTINUE).appendChild(expr);
  661. }
  662. }
  663. void onReturn(Token &out, Token *expr, bool checkYield = true) {
  664. out.setNodeType(ONRETURN).appendChild(expr)
  665. .setExtra(new OnReturnEI(checkYield));
  666. }
  667. void onYield(Token &out, Token &expr) {
  668. out.setNodeType(ONYIELD).appendChild(&expr);
  669. }
  670. void onYieldPair(Token &out, Token &key, Token &val) {
  671. out.setNodeType(ONYIELDPAIR).appendChild(&key).appendChild(&val);
  672. }
  673. void onYieldBreak(Token &out) {
  674. out.setNodeType(ONYIELDBREAK);
  675. }
  676. void onAwait(Token &out, Token &expr) {
  677. out.setNodeType(ONAWAIT).appendChild(&expr);
  678. }
  679. void onGlobal(Token &out, Token &expr) {
  680. out.setNodeType(ONGLOBAL).appendChild(&expr);
  681. }
  682. void onGlobalVar(Token &out, Token *exprs, Token &expr) {
  683. out.setNodeType(ONGLOBALVAR).appendChild(exprs).appendChild(&expr);
  684. }
  685. void onStatic(Token &out, Token &expr) {
  686. out.setNodeType(ONSTATIC).appendChild(&expr);
  687. }
  688. void onEcho(Token &out, Token &expr, bool html) {
  689. out.setNodeType(ONECHO).appendChild(&expr).setExtra(new OnEchoEI(html));
  690. }
  691. void onUnset(Token &out, Token &expr) {
  692. out.setNodeType(ONUNSET).appendChild(&expr);
  693. }
  694. void onExpStatement(Token& out, Token& expr) {
  695. out.setNodeType(ONEXPSTATEMENT).appendChild(&expr);
  696. }
  697. void onForEachStart() {/* TODO */}
  698. void onForEach(Token &out, Token &arr, Token &name, Token &value,
  699. Token &stmt) {
  700. out.setNodeType(ONFOREACH).appendChild(&arr).appendChild(&name)
  701. .appendChild(&value).appendChild(&stmt);
  702. }
  703. void onTry(Token &out, Token &tryStmt, Token &className, Token &var,
  704. Token &catchStmt, Token &catches, Token &finallyStmt) {
  705. out.setNodeType(ONTRYCATCHFINALLY).appendChild(&tryStmt)
  706. .appendChild(&className).appendChild(&var).appendChild(&catchStmt)
  707. .appendChild(&catches).appendChild(&finallyStmt);
  708. }
  709. void onTry(Token &out, Token &tryStmt, Token &finallyStmt) {
  710. out.setNodeType(ONTRYFINALLY).appendChild(&tryStmt)
  711. .appendChild(&finallyStmt);
  712. }
  713. void onCatch(Token &out, Token &catches, Token &className, Token &var,
  714. Token &stmt) {
  715. out.setNodeType(ONCATCH).appendChild(&catches).appendChild(&className)
  716. .appendChild(&var).appendChild(&stmt);
  717. }
  718. void onFinally(Token &out, Token &stmt) {
  719. out.setNodeType(ONFINALLY).appendChild(&stmt);
  720. }
  721. void onThrow(Token &out, Token &expr) {
  722. out.setNodeType(ONTHROW).appendChild(&expr);
  723. }
  724. void onClosure(Token &out, Token *modifiers, Token &ret, Token &ref,
  725. Token &params, Token &cparams, Token &stmts) {
  726. out.setNodeType(ONCLOSURE).appendChild(modifiers).appendChild(&ret)
  727. .appendChild(&ref).appendChild(&params).appendChild(&cparams)
  728. .appendChild(&stmts);
  729. }
  730. void onClosureParam(Token &out, Token *params, Token &param, bool ref) {
  731. out.setNodeType(ONCLOSUREPARAM).appendChild(params).appendChild(&param)
  732. .setExtra(new OnClosureParamEI(ref));
  733. }
  734. void onLabel(Token &out, Token &label) {
  735. out.setNodeType(ONLABEL).appendChild(&label);
  736. }
  737. void onGoto(Token &out, Token &label, bool limited) {
  738. out.setNodeType(ONGOTO).appendChild(&label).setExtra(new OnGotoEI(limited));
  739. }
  740. void onTypedef(Token& out, Token& name, Token& value) {
  741. out.setNodeType(ONTYPEDEF).appendChild(&name).appendChild(&value);
  742. }
  743. void onTypeAnnotation(Token& out, const Token& name, const Token& typeArgs) {
  744. out.setNodeType(ONTYPEANNOTATION).appendChild(const_cast<Token *>(&name))
  745. .appendChild(const_cast<Token *>(&typeArgs));
  746. }
  747. void onTypeList(Token& type1, const Token& type2) {
  748. // TODO: no out?
  749. // out.setNodeType(ONTYPELIST).appendChild(const_cast<Token *>(&type2));
  750. }
  751. void onTypeSpecialization(Token& type, char specialization) {
  752. // TODO: no out?
  753. // out.setNodeType(ONTYPESPECIALIZATION)
  754. // .setExtra(new OnTypeSpecializationEI(specialization));
  755. }
  756. // for namespace support
  757. void onNamespaceStart(const std::string &ns, bool file_scope = false) {
  758. // TODO
  759. }
  760. void onNamespaceEnd() {}
  761. void onUse(const std::string &ns, const std::string &as) {
  762. // TODO
  763. }
  764. void nns(bool declare = false) {
  765. // TODO
  766. }
  767. std::string nsDecl(const std::string &name) {
  768. // TODO
  769. return name;
  770. }
  771. std::string resolve(const std::string &ns, bool cls) {
  772. // TODO
  773. return ns;
  774. }
  775. /////////////////////////////////////////////////////////////////////////////
  776. // Functions below are used to output XHPAST
  777. /////////////////////////////////////////////////////////////////////////////
  778. void coalesceTree() {
  779. coalesceTreeImpl(&tree);
  780. }
  781. // Collapse/elide certain nodes to avoid deep trees
  782. void coalesceTreeImpl(Token *node) {
  783. if (node != nullptr) {
  784. // copy children
  785. std::vector<Token *> children1(node->children);
  786. node->children.clear();
  787. for (std::vector<Token *>::iterator i = children1.begin();
  788. i < children1.end();
  789. ++i) {
  790. Token *child = *i;
  791. if (child && child->nodeType == ONSTATEMENTLISTSTART) {
  792. delete child; // no longer in the tree
  793. continue;
  794. }
  795. coalesceTreeImpl(child);
  796. if (child && (child->nodeType == node->nodeType) &&
  797. ((child->nodeType == ADDSTATEMENT))) {
  798. node->children.insert(node->children.end(),
  799. child->children.begin(),
  800. child->children.end());
  801. delete child; // no longer in the tree
  802. } else {
  803. node->children.push_back(child);
  804. }
  805. }
  806. }
  807. }
  808. xhpast::Node* outputXHPAST() {
  809. xhpast::Node* xhpast_tree = outputXHPASTImpl(&tree);
  810. xhpast::Node* root = new xhpast::Node(n_PROGRAM);
  811. root->appendChild(xhpast_tree);
  812. root->l_tok = xhpast_tree->l_tok;
  813. return root;
  814. }
  815. xhpast::Node* extend_right(xhpast::Node *n, int type) {
  816. // Extend r_tok to the first token of type
  817. n->r_tok = scan_forward(n->r_tok + 1, type);
  818. return n;
  819. }
  820. xhpast::Node* extend_left(xhpast::Node *n, int type) {
  821. // Extend l_tok to the first token of type
  822. for (int i = n->l_tok - 1; i >= 0; i--) {
  823. xhpast::Token *t = m_listener.tokens[i];
  824. if (t->type == type) {
  825. n->l_tok = i;
  826. return n;
  827. }
  828. }
  829. // missing token!
  830. always_assert(false);
  831. }
  832. int scan_forward(int start, int type) {
  833. for (int i = start; i < m_listener.tokens.size(); i++) {
  834. if (m_listener.tokens[i]->type == type) {
  835. return i;
  836. }
  837. }
  838. // missing token!
  839. always_assert(false);
  840. }
  841. int scan_backward(int start, int type) {
  842. for (int i = start; i >= 0; i--) {
  843. if (m_listener.tokens[i]->type == type) {
  844. return i;
  845. }
  846. }
  847. // missing token!
  848. always_assert(false);
  849. }
  850. xhpast::Node* extend_to_delimiters(xhpast::Node *n, int left, int right) {
  851. extend_left(n, left);
  852. return extend_right(n, right);
  853. }
  854. // returns l_tok of first real child
  855. int transform_children(Token *node, xhpast::Node *n) {
  856. int l_tok = -2;
  857. for (std::vector<Token *>::iterator i = node->children.begin();
  858. i < node->children.end();
  859. ++i) {
  860. // TODO: It is possible that in all cases with NULL children, we just
  861. // want to append n_EMPTY, but just continue quietly for now.
  862. if (!(*i)) continue;
  863. xhpast::Node *newChild = outputXHPASTImpl(*i);
  864. n->appendChild(newChild);
  865. if (l_tok == -2) {
  866. l_tok = newChild->l_tok;
  867. }
  868. // optionally insert an n_OPEN_TAG if it follows an ONECHO
  869. // TODO: only for HTML?
  870. if ((*i)->nodeType == ONECHO) {
  871. int id = (*i)->ID() + 1;
  872. if (id < m_listener.tokens.size()) {
  873. xhpast::Token *t = m_listener.tokens[id];
  874. if (t->type == T_OPEN_TAG) {
  875. n->appendChild(new xhpast::Node(n_OPEN_TAG, id, id));
  876. }
  877. }
  878. }
  879. }
  880. return l_tok;
  881. }
  882. int insert_binary_operator(xhpast::Node *n) {
  883. // Locate operator and insert between children
  884. xhpast::Node *c1 = n->children.front();
  885. xhpast::Node *c2 = n->children.back();
  886. int id1 = c1->r_tok; // must be greater than this
  887. int id2 = c2->l_tok; // and less than this
  888. for (int i = id1 + 1; i < id2; i++) {
  889. xhpast::Token *t = m_listener.tokens[i];
  890. switch (t->type) {
  891. case T_COMMENT:
  892. case T_DOC_COMMENT: // needed?
  893. case T_WHITESPACE: {
  894. continue;
  895. }
  896. default: {
  897. n->children.pop_back();
  898. n->children.push_back(new xhpast::Node(n_OPERATOR, i, i));
  899. n->children.push_back(c2);
  900. return t->type;
  901. }
  902. }
  903. }
  904. always_assert(false); // couldn't find the operator!
  905. }
  906. xhpast::Node* outputCondition(Token *cond) {
  907. xhpast::Node *control_cond = new xhpast::Node(n_CONTROL_CONDITION);
  908. control_cond->appendChild(outputXHPASTImpl(cond));
  909. extend_to_delimiters(control_cond, '(', ')');
  910. return control_cond;
  911. }
  912. xhpast::Node *childOf(xhpast::Node *child, int type) {
  913. xhpast::Node *parent = new xhpast::Node(type);
  914. parent->appendChild(child);
  915. return parent;
  916. }
  917. // parse ;, stmt;, {} or { stmts; }
  918. xhpast::Node *possibleStatements(int start, Token *node) {
  919. if (node->nodeType == RAW) {
  920. // We need to find the ";"
  921. int semicolon = scan_forward(start, ';');
  922. xhpast::Node *stmt = new xhpast::Node(n_STATEMENT, semicolon);
  923. stmt->appendChild(new xhpast::Node(n_EMPTY));
  924. return stmt;
  925. } else {
  926. return outputXHPASTImpl(node);
  927. }
  928. }
  929. xhpast::Node *declareParamList(Token *params, int name_pos) {
  930. xhpast::Node *param_list =
  931. new xhpast::Node(n_DECLARATION_PARAMETER_LIST);
  932. while (params && (params->nodeType == ONPARAM)) {
  933. std::vector<Token *>::iterator i = params->children.begin();
  934. params = *i++;
  935. UNUSED Token *type = *i++; // TODO
  936. Token *var = *i++;
  937. UNUSED Token *defValue = *i++; // TODO
  938. UNUSED Token *attr = *i++; // TODO
  939. UNUSED Token *mods = *i; // TODO
  940. // TODO: bool ref
  941. xhpast::Node *p = new xhpast::Node(n_DECLARATION_PARAMETER);
  942. // TODO: class type
  943. p->appendChild(new xhpast::Node(n_EMPTY));
  944. p->appendChild(new xhpast::Node(n_VARIABLE, var->ID()));
  945. // TODO: default value
  946. p->appendChild(new xhpast::Node(n_EMPTY));
  947. // Must prepend to get argument order right
  948. param_list->prependChild(p);
  949. }
  950. if (param_list->children.size() == 0) {
  951. // no params
  952. param_list->l_tok = scan_forward(name_pos, '(');
  953. param_list->r_tok = scan_forward(param_list->l_tok, ')');
  954. } else {
  955. extend_to_delimiters(param_list, '(', ')');
  956. }
  957. return param_list;
  958. }
  959. xhpast::Node *statementList(Token *stmt, int last_loc) {
  960. // statement list: need to extend this to brackets
  961. if (stmt) {
  962. xhpast::Node *stmts = outputXHPASTImpl(stmt);
  963. if (stmt->nodeType != FINISHSTATEMENT) {
  964. extend_to_delimiters(stmts, '{', '}');
  965. }
  966. return stmts;
  967. } else {
  968. // empty body; start looking for braces after the params
  969. int open_brace = scan_forward(last_loc, '{');
  970. xhpast::Node *braces = new xhpast::Node(n_STATEMENT_LIST,
  971. open_brace);
  972. extend_right(braces, '}');
  973. return braces;
  974. }
  975. }
  976. xhpast::Node *callParamList(Token *params, int name_pos) {
  977. xhpast::Node *param_list = new xhpast::Node(n_CALL_PARAMETER_LIST);
  978. while (params && (params->nodeType == ONCALLPARAM)) {
  979. std::vector<Token *>::iterator i = params->children.begin();
  980. params = *i++;
  981. // TODO: ref
  982. param_list->prependChild(outputXHPASTImpl(*i));
  983. }
  984. if (param_list->children.size() == 0) {
  985. // no params
  986. param_list->l_tok = scan_forward(name_pos, '(');
  987. param_list->r_tok = scan_forward(param_list->l_tok, ')');
  988. } else {
  989. extend_to_delimiters(param_list, '(', ')');
  990. }
  991. return param_list;
  992. }
  993. xhpast::Node *objectProperty(Token *base, Token *prop) {
  994. xhpast::Node *arrow = new xhpast::Node(n_OBJECT_PROPERTY_ACCESS);
  995. arrow->appendChild(outputXHPASTImpl(base));
  996. arrow->appendChild(new xhpast::Node(n_STRING, prop->ID()));
  997. return arrow;
  998. }
  999. xhpast::Node *outputXHPASTImpl(Token *node) {
  1000. xhpast::Node* n = new xhpast::Node();
  1001. n->l_tok = node->ID();
  1002. n->r_tok = node->ID();
  1003. switch (node->nodeType) {
  1004. case ONSIMPLEVARIABLE: {
  1005. // no children
  1006. n->type = n_VARIABLE;
  1007. break;
  1008. }
  1009. case ONECHO: {
  1010. std::vector<Token *>::iterator i = node->children.begin();
  1011. if ((*i)->nodeType == RAW) {
  1012. // no children
  1013. n->type = n_INLINE_HTML;
  1014. } else {
  1015. n->type = n_ECHO_LIST;
  1016. Token *current = *i;
  1017. while (current) {
  1018. std::vector<Token *>::iterator i = current->children.begin();
  1019. current = *i++;
  1020. xhpast::Node *child = outputXHPASTImpl(*i);
  1021. if (n->r_tok < child->r_tok) {
  1022. n->r_tok = child->r_tok;
  1023. }
  1024. n->prependChild(child);
  1025. }
  1026. xhpast::Node *stmt = childOf(n, n_STATEMENT);
  1027. return extend_right(stmt, ';');
  1028. }
  1029. break;
  1030. }
  1031. case ONSTATEMENTLISTSTART: {
  1032. // Should never reach here because parent should have elided this
  1033. always_assert(false);
  1034. break;
  1035. }
  1036. case ONEXPSTATEMENT: {
  1037. n->type = n_STATEMENT;
  1038. transform_children(node, n);
  1039. extend_right(n, ';');
  1040. break;
  1041. }
  1042. case ADDSTATEMENT: {
  1043. n->type = n_STATEMENT_LIST;
  1044. // ADDSTATEMENT simply contains its children, so set l_tok to be l_tok
  1045. // of first child; r_tok will be set correctly by transform_children
  1046. n->l_tok = transform_children(node, n);
  1047. break;
  1048. }
  1049. case ONRETURN: {
  1050. n->type = n_RETURN;
  1051. std::vector<Token *>::iterator i = node->children.begin();
  1052. Token *expr = *i;
  1053. if (expr) {
  1054. transform_children(node, n);
  1055. } else {
  1056. n->appendChild(new xhpast::Node(n_EMPTY));
  1057. }
  1058. xhpast::Node *stmt = childOf(n, n_STATEMENT);
  1059. return extend_right(stmt, ';');
  1060. }
  1061. case ONMETHOD: {
  1062. std::vector<Token *>::iterator i = node->children.begin();
  1063. Token *modifiers = *i++;
  1064. UNUSED Token *ret = *i++; // TODO
  1065. UNUSED Token *ref = *i++; // TODO
  1066. Token *name = *i++;
  1067. Token *params = *i++;
  1068. Token *stmt = *i++;
  1069. UNUSED Token *attr = *i; // TODO
  1070. // TODO: reloc
  1071. n->type = n_METHOD_DECLARATION;
  1072. // modifiers private public protected, etc.
  1073. xhpast::Node *mods = new xhpast::Node(n_METHOD_MODIFIER_LIST);
  1074. while (modifiers && (modifiers->nodeType == ONMEMBERMODIFIER)) {
  1075. i = modifiers->children.begin();
  1076. modifiers = *i++;
  1077. mods->appendChild(new xhpast::Node(n_STRING, (*i)->ID()));
  1078. }
  1079. n->appendChild(mods);
  1080. // TODO
  1081. n->appendChild(new xhpast::Node(n_EMPTY));
  1082. n->appendChild(new xhpast::Node(n_STRING, name->ID()));
  1083. xhpast::Node *param_list = declareParamList(params, name->ID());
  1084. n->appendChild(param_list);
  1085. // TODO
  1086. n->appendChild(new xhpast::Node(n_EMPTY));
  1087. n->appendChild(statementList(stmt, param_list->r_tok));
  1088. // Hang method off n_statement
  1089. return childOf(n, n_STATEMENT);
  1090. }
  1091. case ONFUNCTION: {
  1092. // children are modifiers (maybe null), ret, ref, name, params, stmt,
  1093. // attr (maybe null)
  1094. std::vector<Token *>::iterator i = node->children.begin();
  1095. UNUSED Token *modifiers = *i++; // TODO
  1096. UNUSED Token *ret = *i++; // TODO
  1097. UNUSED Token *ref = *i++; // TODO
  1098. Token *name = *i++;
  1099. Token *params = *i++;
  1100. Token *stmt = *i++;
  1101. UNUSED Token *attr = *i; // TODO
  1102. n->type = n_FUNCTION_DECLARATION;
  1103. // TODO: T_STATIC
  1104. n->appendChild(new xhpast::Node(n_EMPTY));
  1105. // TODO: is_reference
  1106. n->appendChild(new xhpast::Node(n_EMPTY));
  1107. // function name
  1108. n->appendChild(new xhpast::Node(n_STRING, name->ID()));
  1109. // params
  1110. xhpast::Node *param_list = declareParamList(params, name->ID());
  1111. n->appendChild(param_list);
  1112. // lexical vars
  1113. n->appendChild(new xhpast::Node(n_EMPTY));
  1114. // statement list: need to extend this to brackets
  1115. n->appendChild(statementList(stmt, param_list->r_tok));
  1116. // Hang function off n_statement
  1117. return childOf(n, n_STATEMENT);
  1118. }
  1119. case ONPARAM: {
  1120. // should be handled in onfunction / onmethod
  1121. always_assert(false);
  1122. break;
  1123. }
  1124. case ONASSIGN:
  1125. case ONBINARYOPEXP: {
  1126. n->type = n_BINARY_EXPRESSION;
  1127. transform_children(node, n);
  1128. int t = insert_binary_operator(n);
  1129. // See if n_CONCATENATION_LIST
  1130. if (t == '.') {
  1131. n->type = n_CONCATENATION_LIST;
  1132. xhpast::Node *second = n->children.back();
  1133. n->children.pop_back();
  1134. xhpast::Node *op = n->children.back();
  1135. n->children.pop_back();
  1136. xhpast::Node *first = n->children.back();
  1137. n->children.pop_back();
  1138. if (first->type == n_CONCATENATION_LIST) {
  1139. n->appendChildren(first);
  1140. } else {
  1141. n->appendChild(first);
  1142. }
  1143. n->appendChild(op);
  1144. // note: the second child should never be an n_CONCATENATION_LIST due
  1145. // to the structure of the parse tree
  1146. n->appendChild(second);
  1147. }
  1148. break;
  1149. }
  1150. case ONIF: {
  1151. // children are cond stmt elsifs elsestmt
  1152. n->type = n_IF;
  1153. std::vector<Token *>::iterator i = node->children.begin();
  1154. Token *cond = *i++;
  1155. Token *stmt = *i++;
  1156. Token *elseifs = *i++;
  1157. Token *elsestmt = *i;
  1158. n->type = n_IF;
  1159. // condition
  1160. n->appendChild(outputCondition(cond));
  1161. // statements
  1162. n->appendChild(outputXHPASTImpl(stmt));
  1163. // elseifs
  1164. while (elseifs->nodeType == ONELSEIF) {
  1165. i = elseifs->children.begin();
  1166. Token *next_elseifs = *i++;
  1167. xhpast::Node *elseif_out = new xhpast::Node(n_ELSEIF);
  1168. elseif_out->appendChild(outputCondition(*i++));
  1169. elseif_out->appendChild(outputXHPASTImpl(*i));
  1170. extend_left(elseif_out, T_ELSEIF);
  1171. n->appendChild(elseif_out);
  1172. elseifs = next_elseifs;
  1173. }
  1174. xhpast::Node *else_out = new xhpast::Node(n_ELSE);
  1175. else_out->appendChild(outputXHPASTImpl(elsestmt));
  1176. extend_left(else_out, T_ELSE);
  1177. n->appendChild(else_out);
  1178. xhpast::Node *cond_list = new xhpast::Node(n_CONDITION_LIST);
  1179. cond_list->appendChild(n);
  1180. return childOf(cond_list, n_STATEMENT);
  1181. }
  1182. case ONWHILE: {
  1183. n->type = n_WHILE;
  1184. std::vector<Token *>::iterator i = node->children.begin();
  1185. n->appendChild(outputCondition(*i++));
  1186. n->appendChild(possibleStatements(n->r_tok, *i));
  1187. return childOf(n, n_STATEMENT);
  1188. }
  1189. case ONFOR: {
  1190. n->type = n_FOR;
  1191. std::vector<Token *>::iterator i = node->children.begin();
  1192. // initialization
  1193. xhpast::Node *loop_exprs = childOf(outputXHPASTImpl(*i++),
  1194. n_FOR_EXPRESSION);
  1195. // termination condition
  1196. loop_exprs->appendChild(outputXHPASTImpl(*i++));
  1197. // loop update
  1198. loop_exprs->appendChild(outputXHPASTImpl(*i++));
  1199. extend_to_delimiters(loop_exprs, '(', ')');
  1200. n->appendChild(loop_exprs);
  1201. // loop body
  1202. n->appendChild(possibleStatements(n->r_tok, *i));
  1203. return childOf(n, n_STATEMENT);
  1204. }
  1205. case ONEXPRLISTELEM: {
  1206. transform_children(node, n);
  1207. n->type = n_EXPRESSION_LIST;
  1208. break;
  1209. }
  1210. case ONBLOCK: {
  1211. transform_children(node, n);
  1212. if (node->children.size() > 0) {
  1213. xhpast::Node *stmts = n->firstChild();
  1214. extend_to_delimiters(stmts, '{', '}');
  1215. return stmts;
  1216. } else {
  1217. n->type = n_STATEMENT_LIST;
  1218. extend_right(n, '}');
  1219. }
  1220. break;
  1221. }
  1222. case ONSCALAR: {
  1223. OnScalarEI *ei = dynamic_cast<OnScalarEI*>(node->extra);
  1224. switch (ei->type) {
  1225. case T_DNUMBER:
  1226. case T_LNUMBER: {
  1227. n->type = n_NUMERIC_SCALAR;
  1228. break;
  1229. }
  1230. case T_CONSTANT_ENCAPSED_STRING: {
  1231. n->type = n_STRING_SCALAR;
  1232. break;
  1233. }
  1234. case T_LINE:
  1235. case T_FILE:
  1236. case T_DIR:
  1237. case T_CLASS_C:
  1238. case T_TRAIT_C:
  1239. case T_METHOD_C:
  1240. case T_FUNC_C:
  1241. case T_NS_C: {
  1242. n->type = n_MAGIC_SCALAR;
  1243. break;
  1244. }
  1245. default: {
  1246. // where do we output n_HEREDOC?
  1247. always_assert(false); // unexpected
  1248. }
  1249. }
  1250. break;
  1251. }
  1252. case ONUNARYOPEXP: {
  1253. transform_children(node, n);
  1254. OnUnaryOpExpEI *ei = dynamic_cast<OnUnaryOpExpEI*>(node->extra);
  1255. if (ei->front) {
  1256. n->type = n_UNARY_PREFIX_EXPRESSION;
  1257. int loc = scan_backward(node->ID(), ei->op);
  1258. n->prependChild(new xhpast::Node(n_OPERATOR, loc));
  1259. } else { // back
  1260. n->type = n_UNARY_POSTFIX_EXPRESSION;
  1261. int loc = scan_forward(node->ID(), ei->op);
  1262. n->appendChild(new xhpast::Node(n_OPERATOR, loc));
  1263. }
  1264. break;
  1265. }
  1266. case ONBREAK: {
  1267. n->type = n_BREAK;
  1268. // TODO: break expr
  1269. n->appendChild(new xhpast::Node(n_EMPTY));
  1270. xhpast::Node* top_stmt = childOf(n, n_STATEMENT);
  1271. return extend_right(top_stmt, ';');
  1272. }
  1273. case ONCONTINUE: {
  1274. n->type = n_CONTINUE;
  1275. // TODO: continue expr
  1276. n->appendChild(new xhpast::Node(n_EMPTY));
  1277. xhpast::Node* top_stmt = childOf(n, n_STATEMENT);
  1278. return extend_right(top_stmt, ';');
  1279. }
  1280. case ONSWITCH: {
  1281. n->type = n_SWITCH;
  1282. std::vector<Token *>::iterator i = node->children.begin();
  1283. // first child is control condition
  1284. n->appendChild(outputCondition(*i++));
  1285. // next child is list of cases
  1286. xhpast::Node *case_list = new xhpast::Node(n_STATEMENT_LIST);
  1287. int right_most = n->r_tok;
  1288. Token* cases = *i;
  1289. while (cases->nodeType == ONCASE) {
  1290. i = cases->children.begin();
  1291. std::vector<Token *>::iterator end = cases->children.end();
  1292. cases = *i++;
  1293. // cse because case is a reserved word
  1294. xhpast::Node *cse;
  1295. if (*i) {
  1296. cse = new xhpast::Node(n_CASE);
  1297. // condition
  1298. cse->appendChild(outputXHPASTImpl(*i));
  1299. extend_left(cse, T_CASE);
  1300. } else {
  1301. std::cout << right_most << std::endl;
  1302. int loc = scan_forward(right_most, T_DEFAULT);
  1303. cse = new xhpast::Node(n_DEFAULT, loc);
  1304. }
  1305. if (i != end) {
  1306. i++;
  1307. }
  1308. // body
  1309. if (i != end) {
  1310. // TODO: replace with possibleStatements?
  1311. cse->appendChild(outputXHPASTImpl(*i));
  1312. } else {
  1313. cse->appendChild(new xhpast::Node(n_STATEMENT_LIST));
  1314. }
  1315. // must prepend to get the order right
  1316. case_list->prependChild(cse);
  1317. right_most = case_list->r_tok;
  1318. }
  1319. n->appendChild(extend_to_delimiters(case_list, '{', '}'));
  1320. return childOf(n, n_STATEMENT);
  1321. }
  1322. case ONARRAY: {
  1323. // TODO: depends on type
  1324. n->type = n_ARRAY_LITERAL;
  1325. xhpast::Node *value_list = new xhpast::Node(n_ARRAY_VALUE_LIST);
  1326. std::vector<Token *>::iterator i = node->children.begin();
  1327. Token *pair = *i;
  1328. while (pair && pair->nodeType == ONARRAYPAIR) {
  1329. // TODO: refs
  1330. i = pair->children.begin();
  1331. Token *next_pair = *i++;
  1332. Token *name = *i++;
  1333. Token *value = *i;
  1334. xhpast::Node *entry = new xhpast::Node(n_ARRAY_VALUE);
  1335. if (name) {
  1336. entry->appendChild(outputXHPASTImpl(name));
  1337. } else {
  1338. entry->appendChild(new xhpast::Node(n_EMPTY));
  1339. }
  1340. entry->appendChild(outputXHPASTImpl(value));
  1341. // must prepend to get the order right
  1342. value_list->prependChild(entry);
  1343. pair = next_pair;
  1344. }
  1345. n->appendChild(value_list);
  1346. extend_right(n, ')');
  1347. break;
  1348. }
  1349. case ONOBJECTMETHODCALL: {
  1350. std::vector<Token *>::iterator i = node->children.begin();
  1351. Token *base = *i++;
  1352. Token *prop = *i++;
  1353. Token *params = *i;
  1354. n->type = n_METHOD_CALL;
  1355. n->appendChild(objectProperty(base, prop));
  1356. n->appendChild(callParamList(params, prop->ID()));
  1357. break;
  1358. }
  1359. case ONCALL: {
  1360. std::vector<Token *>::iterator i = node->children.begin();
  1361. Token *name = *i++;
  1362. Token *params = *i++;
  1363. UNUSED Token *cls = *i; // TODO
  1364. // TODO: dynamic, fromCompiler, cls
  1365. n->type = n_FUNCTION_CALL;
  1366. n->appendChild(new xhpast::Node(n_SYMBOL_NAME, name->ID()));
  1367. n->appendChild(callParamList(params, name->ID()));
  1368. break;
  1369. }
  1370. case ONCLASS: {
  1371. std::vector<Token *>::iterator i = node->children.begin();
  1372. Token *name = *i++;
  1373. UNUSED Token *base = *i++; // TODO
  1374. UNUSED Token *baseInterface = *i++; // TODO
  1375. Token *stmt = *i++;
  1376. UNUSED Token *attr = *i; // TODO
  1377. n->type = n_CLASS_DECLARATION;
  1378. // TODO attributes
  1379. xhpast::Node *attr_out = new xhpast::Node(n_CLASS_ATTRIBUTES, n->l_tok);
  1380. attr_out->appendChild(new xhpast::Node(n_EMPTY));
  1381. n->appendChild(attr_out);
  1382. n->appendChild(new xhpast::Node(n_CLASS_NAME, name->ID()));
  1383. // TODO
  1384. n->appendChild(new xhpast::Node(n_EMPTY));
  1385. // TODO
  1386. n->appendChild(new xhpast::Node(n_EMPTY));
  1387. n->appendChild(outputXHPASTImpl(stmt));
  1388. return childOf(n, n_STATEMENT);
  1389. }
  1390. case ONCLASSSTATEMENT: {
  1391. n->type = n_STATEMENT_LIST;
  1392. Token *stmts = node;
  1393. do {
  1394. std::vector<Token *>::iterator i = stmts->children.begin();
  1395. stmts = *i++;
  1396. Token *stmt = *i;
  1397. n->prependChild(outputXHPASTImpl(stmt));
  1398. } while(stmts->nodeType == ONCLASSSTATEMENT);
  1399. extend_to_delimiters(n, '{', '}');
  1400. break;
  1401. }
  1402. case FINISHSTATEMENT: {
  1403. if (node->children.size() > 0) {
  1404. std::vector<Token *>::iterator i = node->children.begin();
  1405. return extend_to_delimiters(outputXHPASTImpl(*i), '{', '}');
  1406. } else {
  1407. n->type = n_STATEMENT_LIST;
  1408. return extend_right(n, '}');
  1409. }
  1410. }
  1411. case ONDO: {
  1412. n->type = n_DO_WHILE;
  1413. std::vector<Token *>::iterator i = node->children.begin();
  1414. n->appendChild(possibleStatements(n->l_tok, *i++));
  1415. n->appendChild(outputCondition(*i));
  1416. xhpast::Node *ret = childOf(n, n_STATEMENT);
  1417. return extend_right(ret, ';');
  1418. }
  1419. case ONCONSTANTVALUE: {
  1420. n->type = n_SYMBOL_NAME;
  1421. break;
  1422. }
  1423. case ONENCAPSLIST: {
  1424. transform_children(node, n);
  1425. n->type = n_STRING_SCALAR;
  1426. n->children.clear(); // memory leak, + remember to collapse range to 318
  1427. break;
  1428. }
  1429. case ONOBJECTPROPERTY: {
  1430. std::vector<Token *>::iterator i = node->children.begin();
  1431. Token *base = *i++;
  1432. Token *prop = *i;
  1433. return objectProperty(base, prop);
  1434. }
  1435. case ONYIELD: {
  1436. transform_children(node, n);
  1437. n->type = n_YIELD_EXPRESSION;
  1438. xhpast::Node *yield_kw = new xhpast::Node(n_YIELD, node->ID());
  1439. n->prependChild(yield_kw);
  1440. break;
  1441. }
  1442. case ONAWAIT: {
  1443. transform_children(node, n);
  1444. n->type = n_AWAIT_EXPRESSION;
  1445. xhpast::Node *await_kw = new xhpast::Node(n_AWAIT, node->ID());
  1446. n->prependChild(await_kw);
  1447. break;
  1448. }
  1449. default: {
  1450. transform_children(node, n);
  1451. n->type = node->nodeType;
  1452. break;
  1453. }
  1454. }
  1455. // fyi: Some branches of the switch return early
  1456. return n;
  1457. }
  1458. };
  1459. //////////////////////////////////////////////////////////////////////
  1460. }}
  1461. #endif