PageRenderTime 45ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/util/parser/parser.cpp

https://github.com/github-ivan/hiphop-php
C++ | 351 lines | 270 code | 49 blank | 32 comment | 55 complexity | c1f9b846481b52104302ca2cfcc9ec5c MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- 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. #include "parser.h"
  17. #include <runtime/base/macros.h>
  18. #include <util/hash.h>
  19. using namespace std;
  20. using namespace boost;
  21. namespace HPHP {
  22. ///////////////////////////////////////////////////////////////////////////////
  23. Mutex ParserBase::s_mutex;
  24. std::map<int64, int> ParserBase::s_closureIds;
  25. char ParserBase::GetAnonPrefix(AnonFuncKind kind) {
  26. CT_ASSERT(Closure == 0 && Continuation <= 9);
  27. CT_ASSERT(CharClosure == '0' && CharContinuation <= '9');
  28. return '0' + kind;
  29. }
  30. template <int i>
  31. static bool NameImpl(const std::string &name) {
  32. return !name.empty() && isdigit(name[0]) && i == (name[0] - '0');
  33. }
  34. bool ParserBase::IsClosureName(const std::string &name) {
  35. return NameImpl<Closure>(name);
  36. }
  37. bool ParserBase::IsCreateFunctionName(const std::string &name) {
  38. return NameImpl<CreateFunction>(name);
  39. }
  40. bool ParserBase::IsContinuationName(const std::string &name) {
  41. return NameImpl<ContinuationFromClosure>(name) ||
  42. NameImpl<Continuation>(name);
  43. }
  44. bool ParserBase::IsContinuationFromClosureName(const std::string &name) {
  45. return NameImpl<ContinuationFromClosure>(name);
  46. }
  47. bool ParserBase::IsClosureOrContinuationName(const std::string &name) {
  48. return IsClosureName(name) || IsContinuationName(name);
  49. }
  50. bool ParserBase::IsAnonFunctionName(const char *name) {
  51. if (!*name) return true;
  52. char begin = CharClosure;
  53. char end = CharContinuation;
  54. char test = name[0];
  55. return begin <= test && test <= end;
  56. }
  57. void ParserBase::Reset() {
  58. Lock lock(s_mutex);
  59. s_closureIds.clear();
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////
  62. ParserBase::ParserBase(Scanner &scanner, const char *fileName)
  63. : m_scanner(scanner), m_fileName(fileName), m_nsState(SeenNothing) {
  64. if (m_fileName == NULL) m_fileName = "";
  65. // global scope
  66. m_labelInfos.reserve(3);
  67. m_labelInfos.resize(1);
  68. pushLabelScope();
  69. }
  70. ParserBase::~ParserBase() {
  71. }
  72. std::string ParserBase::getMessage(bool filename /* = false */) const {
  73. string ret = m_scanner.getError();
  74. if (!ret.empty()) {
  75. ret += " ";
  76. }
  77. ret += getMessage(m_scanner.getLocation(), filename);
  78. return ret;
  79. }
  80. std::string ParserBase::getMessage(Location *loc,
  81. bool filename /* = false */) const {
  82. int line = loc->line1;
  83. int column = loc->char1;
  84. string ret = "(";
  85. if (filename) {
  86. ret += string("File: ") + file() + ", ";
  87. }
  88. ret += string("Line: ") + lexical_cast<string>(line);
  89. ret += ", Char: " + lexical_cast<string>(column) + ")";
  90. return ret;
  91. }
  92. LocationPtr ParserBase::getLocation() const {
  93. LocationPtr location(new Location());
  94. location->file = file();
  95. location->line0 = line0();
  96. location->char0 = char0();
  97. location->line1 = line1();
  98. location->char1 = char1();
  99. return location;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. // T_FUNCTION related functions
  103. void ParserBase::pushFuncLocation() {
  104. m_funcLocs.push_back(getLocation());
  105. }
  106. LocationPtr ParserBase::popFuncLocation() {
  107. ASSERT(!m_funcLocs.empty());
  108. LocationPtr loc = m_funcLocs.back();
  109. m_funcLocs.pop_back();
  110. return loc;
  111. }
  112. std::string ParserBase::getAnonFuncName(AnonFuncKind kind) {
  113. int64 h = hash_string_cs(m_fileName, strlen(m_fileName));
  114. int closureId;
  115. {
  116. Lock lock(s_mutex);
  117. int &id = s_closureIds[h];
  118. closureId = ++id;
  119. }
  120. string ret;
  121. ret += GetAnonPrefix(kind);
  122. ret += lexical_cast<string>(h);
  123. ret += "_";
  124. ret += lexical_cast<string>(closureId);
  125. return ret;
  126. }
  127. ///////////////////////////////////////////////////////////////////////////////
  128. // checks GOTO label syntax
  129. void ParserBase::pushLabelInfo() {
  130. m_labelInfos.resize(m_labelInfos.size() + 1);
  131. pushLabelScope();
  132. }
  133. void ParserBase::pushLabelScope() {
  134. ASSERT(!m_labelInfos.empty());
  135. LabelInfo &info = m_labelInfos.back();
  136. info.scopes.push_back(++info.scopeId);
  137. }
  138. void ParserBase::popLabelScope() {
  139. ASSERT(!m_labelInfos.empty());
  140. LabelInfo &info = m_labelInfos.back();
  141. info.scopes.pop_back();
  142. }
  143. void ParserBase::addLabel(const std::string &label,
  144. LocationPtr loc,
  145. ScannerToken *stmt) {
  146. ASSERT(!m_labelInfos.empty());
  147. LabelInfo &info = m_labelInfos.back();
  148. if (info.labels.find(label) != info.labels.end()) {
  149. error("Label '%s' already defined: %s", label.c_str(),
  150. getMessage().c_str());
  151. invalidateLabel(extractStatement(stmt));
  152. return;
  153. }
  154. ASSERT(!info.scopes.empty());
  155. LabelStmtInfo labelInfo;
  156. labelInfo.scopeId = info.scopes.back();
  157. labelInfo.stmt = extractStatement(stmt);
  158. labelInfo.loc = loc;
  159. info.labels[label] = labelInfo;
  160. }
  161. void ParserBase::addGoto(const std::string &label,
  162. LocationPtr loc,
  163. ScannerToken *stmt) {
  164. ASSERT(!m_labelInfos.empty());
  165. LabelInfo &info = m_labelInfos.back();
  166. GotoInfo gotoInfo;
  167. gotoInfo.label = label;
  168. gotoInfo.scopes = info.scopes;
  169. gotoInfo.loc = loc;
  170. gotoInfo.stmt = extractStatement(stmt);
  171. info.gotos.push_back(gotoInfo);
  172. }
  173. void ParserBase::popLabelInfo() {
  174. ASSERT(!m_labelInfos.empty());
  175. LabelInfo &info = m_labelInfos.back();
  176. LabelMap labels = info.labels; // shallow copy
  177. for (unsigned int i = 0; i < info.gotos.size(); i++) {
  178. const GotoInfo &gotoInfo = info.gotos[i];
  179. LabelMap::const_iterator iter = info.labels.find(gotoInfo.label);
  180. if (iter == info.labels.end()) {
  181. error("'goto' to undefined label '%s': %s",
  182. gotoInfo.label.c_str(), getMessage(gotoInfo.loc.get()).c_str());
  183. invalidateGoto(gotoInfo.stmt, UndefLabel);
  184. continue;
  185. }
  186. const LabelStmtInfo &labelInfo = iter->second;
  187. if (gotoInfo.label.find(YIELD_LABEL_PREFIX) == 0) {
  188. labels.erase(gotoInfo.label);
  189. continue;
  190. }
  191. int labelScopeId = labelInfo.scopeId;
  192. bool found = false;
  193. for (int j = gotoInfo.scopes.size() - 1; j >= 0; j--) {
  194. if (labelScopeId == gotoInfo.scopes[j]) {
  195. found = true;
  196. break;
  197. }
  198. }
  199. if (!found) {
  200. error("'goto' into loop or switch statement "
  201. "is disallowed: %s", getMessage(gotoInfo.loc.get()).c_str());
  202. invalidateGoto(gotoInfo.stmt, InvalidBlock);
  203. continue;
  204. } else {
  205. labels.erase(gotoInfo.label);
  206. }
  207. }
  208. // now invalidate all un-used labels
  209. for (LabelMap::const_iterator it(labels.begin());
  210. it != labels.end();
  211. ++it) {
  212. invalidateLabel(it->second.stmt);
  213. }
  214. m_labelInfos.pop_back();
  215. }
  216. ///////////////////////////////////////////////////////////////////////////////
  217. // namespace support
  218. void ParserBase::nns(bool declare /* = false */) {
  219. if (m_nsState == SeenNamespaceStatement) {
  220. error("No code may exist outside of namespace {}: %s",
  221. getMessage().c_str());
  222. return;
  223. }
  224. if (m_nsState == SeenNothing && !declare) {
  225. m_nsState = SeenNonNamespaceStatement;
  226. }
  227. }
  228. void ParserBase::onNamespaceStart(const std::string &ns) {
  229. if (m_nsState == SeenNonNamespaceStatement) {
  230. error("Namespace declaration statement has to be the very first "
  231. "statement in the script: %s", getMessage().c_str());
  232. return;
  233. }
  234. m_nsState = InsideNamespace;
  235. m_namespace = ns;
  236. }
  237. void ParserBase::onNamespaceEnd() {
  238. m_nsState = SeenNamespaceStatement;
  239. }
  240. void ParserBase::onUse(const std::string &ns, const std::string &as) {
  241. if (m_aliases.find(as) != m_aliases.end()) {
  242. error("Cannot use %s as %s because the name is already in use: %s",
  243. ns.c_str(), as.c_str(), getMessage().c_str());
  244. return;
  245. }
  246. string key = as;
  247. if (key.empty()) {
  248. size_t pos = ns.rfind(NAMESPACE_SEP);
  249. if (pos == string::npos) {
  250. key = ns;
  251. } else {
  252. key = ns.substr(pos + 1);
  253. }
  254. }
  255. m_aliases[key] = ns;
  256. }
  257. std::string ParserBase::nsDecl(const std::string &name) {
  258. if (m_namespace.empty()) {
  259. return name;
  260. }
  261. return m_namespace + NAMESPACE_SEP + name;
  262. }
  263. std::string ParserBase::resolve(const std::string &ns, bool cls) {
  264. // try import rules first
  265. string alias = ns;
  266. size_t pos = ns.find(NAMESPACE_SEP);
  267. if (pos != string::npos) {
  268. alias = ns.substr(0, pos);
  269. }
  270. hphp_string_imap<std::string>::const_iterator iter = m_aliases.find(alias);
  271. if (iter != m_aliases.end()) {
  272. if (pos != string::npos) {
  273. return iter->second + ns.substr(pos);
  274. }
  275. return iter->second;
  276. }
  277. // if qualified name, prepend current namespace
  278. if (pos != string::npos) {
  279. return nsDecl(ns);
  280. }
  281. // unqualified name in global namespace
  282. if (m_namespace.empty()) {
  283. return ns;
  284. }
  285. // unqualified class name always prefixed with NAMESPACE_SEP
  286. if (cls) {
  287. if (strcasecmp("self", ns.c_str()) && strcasecmp("parent", ns.c_str())) {
  288. return m_namespace + NAMESPACE_SEP + ns;
  289. }
  290. return ns;
  291. }
  292. if (!strcasecmp("true", ns.c_str()) ||
  293. !strcasecmp("false", ns.c_str()) ||
  294. !strcasecmp("null", ns.c_str())) {
  295. return ns;
  296. }
  297. // unqualified function name needs leading NAMESPACE_SEP to indicate this
  298. // needs runtime resolution
  299. return NAMESPACE_SEP + m_namespace + NAMESPACE_SEP + ns;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. }