269ec416d5
This reverts commit 2e9677b7c3f37e9627b9cbc9a6ddec82a10e7215. Third time is the charm. I hid it from reflection, but I missed `get_class_methods`. The diff betweenn this and what was reverted is https://phabricator.fb.com/P2217891 and then I did https://phabricator.fb.com/P2217904 because it looked like it should be done.
263 linhas
7.5 KiB
C++
263 linhas
7.5 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "parser.h"
|
|
#include "hphp/util/hash.h"
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ParserBase::IsClosureName(const std::string &name) {
|
|
return boost::istarts_with(name, "closure$");
|
|
}
|
|
|
|
bool ParserBase::IsContinuationName(const std::string &name) {
|
|
return boost::iends_with(name, "$continuation");
|
|
}
|
|
|
|
bool ParserBase::IsClosureOrContinuationName(const std::string &name) {
|
|
return IsClosureName(name) || IsContinuationName(name);
|
|
}
|
|
|
|
std::string ParserBase::newContinuationName(const std::string &name) {
|
|
assert(!name.empty());
|
|
size_t pos = 0;
|
|
std::string shorterName = name;
|
|
std::string suffix("$continuation");
|
|
while((pos = shorterName.find(suffix, pos)) != std::string::npos) {
|
|
shorterName.replace(pos, suffix.length(), "");
|
|
}
|
|
return shorterName + suffix;
|
|
}
|
|
|
|
std::string ParserBase::newClosureName(
|
|
const std::string &className,
|
|
const std::string &funcName) {
|
|
std::string name = "Closure$";
|
|
if (!className.empty()) {
|
|
name += className + "::";
|
|
}
|
|
name += funcName;
|
|
|
|
int id = ++m_seenClosures[name];
|
|
if (id > 1) {
|
|
// we've seen the same name before, uniquify
|
|
name = name + '#' + std::to_string(id);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
ParserBase::ParserBase(Scanner &scanner, const char *fileName)
|
|
: m_scanner(scanner), m_fileName(fileName) {
|
|
if (m_fileName == nullptr) m_fileName = "";
|
|
|
|
// global scope
|
|
m_labelInfos.reserve(3);
|
|
m_labelInfos.resize(1);
|
|
pushLabelScope();
|
|
}
|
|
|
|
ParserBase::~ParserBase() {
|
|
}
|
|
|
|
std::string ParserBase::getMessage(bool filename /* = false */) const {
|
|
string ret = m_scanner.getError();
|
|
if (!ret.empty()) {
|
|
ret += " ";
|
|
}
|
|
ret += getMessage(m_scanner.getLocation(), filename);
|
|
return ret;
|
|
}
|
|
|
|
std::string ParserBase::getMessage(Location *loc,
|
|
bool filename /* = false */) const {
|
|
int line = loc->line1;
|
|
int column = loc->char1;
|
|
string ret = "(";
|
|
if (filename) {
|
|
ret += string("File: ") + file() + ", ";
|
|
}
|
|
ret += string("Line: ") + boost::lexical_cast<string>(line);
|
|
ret += ", Char: " + boost::lexical_cast<string>(column) + ")";
|
|
return ret;
|
|
}
|
|
|
|
LocationPtr ParserBase::getLocation() const {
|
|
LocationPtr location(new Location());
|
|
location->file = file();
|
|
location->line0 = line0();
|
|
location->char0 = char0();
|
|
location->line1 = line1();
|
|
location->char1 = char1();
|
|
location->cursor = cursor();
|
|
return location;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// T_FUNCTION related functions
|
|
|
|
void ParserBase::pushFuncLocation() {
|
|
m_funcLocs.push_back(getLocation());
|
|
}
|
|
|
|
LocationPtr ParserBase::popFuncLocation() {
|
|
assert(!m_funcLocs.empty());
|
|
LocationPtr loc = m_funcLocs.back();
|
|
m_funcLocs.pop_back();
|
|
return loc;
|
|
}
|
|
|
|
void ParserBase::pushClass(bool isXhpClass) {
|
|
m_classes.push_back(isXhpClass);
|
|
}
|
|
|
|
bool ParserBase::peekClass() {
|
|
assert(!m_classes.empty());
|
|
return m_classes.back();
|
|
}
|
|
|
|
void ParserBase::popClass() {
|
|
m_classes.pop_back();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// typevar scopes
|
|
|
|
void ParserBase::pushTypeScope() {
|
|
m_typeScopes.push_back(m_typeVars);
|
|
m_typeVars.clear();
|
|
}
|
|
|
|
void ParserBase::popTypeScope() {
|
|
m_typeScopes.pop_back();
|
|
}
|
|
|
|
void ParserBase::addTypeVar(const std::string &name) {
|
|
m_typeVars.insert(name);
|
|
}
|
|
|
|
bool ParserBase::isTypeVar(const std::string &name) {
|
|
for (TypevarScopeStack::iterator iter = m_typeScopes.begin();
|
|
iter != m_typeScopes.end();
|
|
iter++) {
|
|
if (iter->find(name) != iter->end()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// checks GOTO label syntax
|
|
|
|
void ParserBase::pushLabelInfo() {
|
|
m_labelInfos.resize(m_labelInfos.size() + 1);
|
|
pushLabelScope();
|
|
}
|
|
|
|
void ParserBase::pushLabelScope() {
|
|
assert(!m_labelInfos.empty());
|
|
LabelInfo &info = m_labelInfos.back();
|
|
info.scopes.push_back(++info.scopeId);
|
|
}
|
|
|
|
void ParserBase::popLabelScope() {
|
|
assert(!m_labelInfos.empty());
|
|
LabelInfo &info = m_labelInfos.back();
|
|
info.scopes.pop_back();
|
|
}
|
|
|
|
void ParserBase::addLabel(const std::string &label,
|
|
LocationPtr loc,
|
|
ScannerToken *stmt) {
|
|
assert(!m_labelInfos.empty());
|
|
LabelInfo &info = m_labelInfos.back();
|
|
if (info.labels.find(label) != info.labels.end()) {
|
|
error("Label '%s' already defined: %s", label.c_str(),
|
|
getMessage().c_str());
|
|
invalidateLabel(extractStatement(stmt));
|
|
return;
|
|
}
|
|
assert(!info.scopes.empty());
|
|
LabelStmtInfo labelInfo;
|
|
labelInfo.scopeId = info.scopes.back();
|
|
labelInfo.stmt = extractStatement(stmt);
|
|
labelInfo.loc = loc;
|
|
info.labels[label] = labelInfo;
|
|
}
|
|
|
|
void ParserBase::addGoto(const std::string &label,
|
|
LocationPtr loc,
|
|
ScannerToken *stmt) {
|
|
assert(!m_labelInfos.empty());
|
|
LabelInfo &info = m_labelInfos.back();
|
|
GotoInfo gotoInfo;
|
|
gotoInfo.label = label;
|
|
gotoInfo.scopes = info.scopes;
|
|
gotoInfo.loc = loc;
|
|
gotoInfo.stmt = extractStatement(stmt);
|
|
info.gotos.push_back(gotoInfo);
|
|
}
|
|
|
|
void ParserBase::popLabelInfo() {
|
|
assert(!m_labelInfos.empty());
|
|
LabelInfo &info = m_labelInfos.back();
|
|
LabelMap labels = info.labels; // shallow copy
|
|
|
|
for (unsigned int i = 0; i < info.gotos.size(); i++) {
|
|
const GotoInfo &gotoInfo = info.gotos[i];
|
|
LabelMap::const_iterator iter = info.labels.find(gotoInfo.label);
|
|
if (iter == info.labels.end()) {
|
|
invalidateGoto(gotoInfo.stmt, UndefLabel);
|
|
error("'goto' to undefined label '%s': %s",
|
|
gotoInfo.label.c_str(), getMessage(gotoInfo.loc.get()).c_str());
|
|
continue;
|
|
}
|
|
const LabelStmtInfo &labelInfo = iter->second;
|
|
int labelScopeId = labelInfo.scopeId;
|
|
bool found = false;
|
|
for (int j = gotoInfo.scopes.size() - 1; j >= 0; j--) {
|
|
if (labelScopeId == gotoInfo.scopes[j]) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
invalidateGoto(gotoInfo.stmt, InvalidBlock);
|
|
error("'goto' into loop or switch statement "
|
|
"is disallowed: %s", getMessage(gotoInfo.loc.get()).c_str());
|
|
continue;
|
|
} else {
|
|
labels.erase(gotoInfo.label);
|
|
}
|
|
}
|
|
|
|
// now invalidate all un-used labels
|
|
for (LabelMap::const_iterator it(labels.begin());
|
|
it != labels.end();
|
|
++it) {
|
|
invalidateLabel(it->second.stmt);
|
|
}
|
|
|
|
m_labelInfos.pop_back();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|