absorb comments on namespaces

This test didn't really intentionally test this, but it caught us not eating comments on namespaces.

I don't understand the difference between ##ParserBase## and ##Parser##. Maybe this belongs here? It needed to be here to have access to ##pushComment##.
Esse commit está contido em:
Paul Tarjan
2013-05-10 23:55:15 -07:00
commit de Sara Golemon
commit 1e0f032ba7
7 arquivos alterados com 149 adições e 128 exclusões
+108 -1
Ver Arquivo
@@ -157,7 +157,7 @@ StatementListPtr Parser::ParseString(CStrRef input, AnalysisResultPtr ar,
Parser::Parser(Scanner &scanner, const char *fileName,
AnalysisResultPtr ar, int fileSize /* = 0 */)
: ParserBase(scanner, fileName), m_ar(ar), m_lambdaMode(false),
m_closureGenerator(false) {
m_closureGenerator(false), m_nsState(SeenNothing) {
string md5str = Eval::FileRepository::unitMd5(scanner.getMd5());
MD5 md5 = MD5(md5str.c_str());
@@ -1650,6 +1650,113 @@ void Parser::onTypeSpecialization(Token& type, char specialization) {
}
}
///////////////////////////////////////////////////////////////////////////////
// namespace support
void Parser::nns(int token) {
if (m_nsState == SeenNamespaceStatement && token != ';') {
error("No code may exist outside of namespace {}: %s",
getMessage().c_str());
return;
}
if (m_nsState == SeenNothing && token != T_DECLARE) {
m_nsState = SeenNonNamespaceStatement;
}
}
void Parser::onNamespaceStart(const std::string &ns,
bool file_scope /* =false */) {
if (m_nsState == SeenNonNamespaceStatement) {
error("Namespace declaration statement has to be the very first "
"statement in the script: %s", getMessage().c_str());
return;
}
if (m_nsState != SeenNothing && file_scope != m_nsFileScope) {
error("Cannot mix bracketed namespace declarations with unbracketed "
"namespace declarations");
}
m_nsState = InsideNamespace;
m_nsFileScope = file_scope;
m_aliases.clear();
pushComment();
m_namespace = ns;
}
void Parser::onNamespaceEnd() {
m_nsState = SeenNamespaceStatement;
}
void Parser::onUse(const std::string &ns, const std::string &as) {
if (m_aliases.find(as) != m_aliases.end()) {
error("Cannot use %s as %s because the name is already in use: %s",
ns.c_str(), as.c_str(), getMessage().c_str());
return;
}
string key = as;
if (key.empty()) {
size_t pos = ns.rfind(NAMESPACE_SEP);
if (pos == string::npos) {
key = ns;
} else {
key = ns.substr(pos + 1);
}
}
m_aliases[key] = ns;
}
std::string Parser::nsDecl(const std::string &name) {
if (m_namespace.empty()) {
return name;
}
return m_namespace + NAMESPACE_SEP + name;
}
std::string Parser::resolve(const std::string &ns, bool cls) {
// try import rules first
string alias = ns;
size_t pos = ns.find(NAMESPACE_SEP);
if (pos != string::npos) {
alias = ns.substr(0, pos);
}
hphp_string_imap<std::string>::const_iterator iter = m_aliases.find(alias);
if (iter != m_aliases.end()) {
if (pos != string::npos) {
return iter->second + ns.substr(pos);
}
return iter->second;
}
// Classes are special. They don't fallback to the global namespace.
if (cls) {
if (!strcasecmp("self", ns.c_str()) ||
!strcasecmp("parent", ns.c_str())) {
return ns;
}
// Don't prefix with \ because that isn't the real classname and we don't
// need a flag to signal fallback.
return nsDecl(ns);
}
// if qualified name, prepend current namespace
if (pos != string::npos) {
return nsDecl(ns);
}
// unqualified name in global namespace
if (m_namespace.empty()) {
return ns;
}
if (!strcasecmp("true", ns.c_str()) ||
!strcasecmp("false", ns.c_str()) ||
!strcasecmp("null", ns.c_str())) {
return ns;
}
return nsDecl(ns);
}
void Parser::invalidateGoto(TStatementPtr stmt, GotoError error) {
GotoStatement *gs = (GotoStatement*) stmt;
assert(gs);
+20
Ver Arquivo
@@ -254,6 +254,14 @@ public:
void onTypeList(Token& type1, const Token& type2);
void onTypeSpecialization(Token& type, char specialization);
// for namespace support
void onNamespaceStart(const std::string &ns, bool file_scope = false);
void onNamespaceEnd();
void onUse(const std::string &ns, const std::string &as);
void nns(int token = 0);
std::string nsDecl(const std::string &name);
std::string resolve(const std::string &ns, bool cls);
virtual void invalidateGoto(TStatementPtr stmt, GotoError error);
virtual void invalidateLabel(TStatementPtr stmt);
@@ -325,6 +333,18 @@ private:
void checkAssignThis(Token &var);
void addStatement(StatementPtr stmt, StatementPtr new_stmt);
// for namespace support
enum NamespaceState {
SeenNothing,
SeenNonNamespaceStatement,
SeenNamespaceStatement,
InsideNamespace,
};
NamespaceState m_nsState;
bool m_nsFileScope;
std::string m_namespace; // current namespace
hphp_string_imap<std::string> m_aliases;
};
///////////////////////////////////////////////////////////////////////////////
+1 -107
Ver Arquivo
@@ -73,7 +73,7 @@ void ParserBase::Reset() {
///////////////////////////////////////////////////////////////////////////////
ParserBase::ParserBase(Scanner &scanner, const char *fileName)
: m_scanner(scanner), m_fileName(fileName), m_nsState(SeenNothing) {
: m_scanner(scanner), m_fileName(fileName) {
if (m_fileName == nullptr) m_fileName = "";
// global scope
@@ -284,111 +284,5 @@ void ParserBase::popLabelInfo() {
m_labelInfos.pop_back();
}
///////////////////////////////////////////////////////////////////////////////
// namespace support
void ParserBase::nns(int token) {
if (m_nsState == SeenNamespaceStatement && token != ';') {
error("No code may exist outside of namespace {}: %d %s",
token, getMessage().c_str());
return;
}
if (m_nsState == SeenNothing && token != T_DECLARE) {
m_nsState = SeenNonNamespaceStatement;
}
}
void ParserBase::onNamespaceStart(const std::string &ns,
bool file_scope /* =false */) {
if (m_nsState == SeenNonNamespaceStatement) {
error("Namespace declaration statement has to be the very first "
"statement in the script: %s", getMessage().c_str());
return;
}
if (m_nsState != SeenNothing && file_scope != m_nsFileScope) {
error("Cannot mix bracketed namespace declarations with unbracketed "
"namespace declarations");
}
m_nsState = InsideNamespace;
m_nsFileScope = file_scope;
m_aliases.clear();
m_namespace = ns;
}
void ParserBase::onNamespaceEnd() {
m_nsState = SeenNamespaceStatement;
}
void ParserBase::onUse(const std::string &ns, const std::string &as) {
if (m_aliases.find(as) != m_aliases.end()) {
error("Cannot use %s as %s because the name is already in use: %s",
ns.c_str(), as.c_str(), getMessage().c_str());
return;
}
string key = as;
if (key.empty()) {
size_t pos = ns.rfind(NAMESPACE_SEP);
if (pos == string::npos) {
key = ns;
} else {
key = ns.substr(pos + 1);
}
}
m_aliases[key] = ns;
}
std::string ParserBase::nsDecl(const std::string &name) {
if (m_namespace.empty()) {
return name;
}
return m_namespace + NAMESPACE_SEP + name;
}
std::string ParserBase::resolve(const std::string &ns, bool cls) {
// try import rules first
string alias = ns;
size_t pos = ns.find(NAMESPACE_SEP);
if (pos != string::npos) {
alias = ns.substr(0, pos);
}
hphp_string_imap<std::string>::const_iterator iter = m_aliases.find(alias);
if (iter != m_aliases.end()) {
if (pos != string::npos) {
return iter->second + ns.substr(pos);
}
return iter->second;
}
// Classes are special. They don't fallback to the global namespace.
if (cls) {
if (!strcasecmp("self", ns.c_str()) ||
!strcasecmp("parent", ns.c_str())) {
return ns;
}
// Don't prefix with \ because that isn't the real classname and we don't
// need a flag to signal fallback.
return nsDecl(ns);
}
// if qualified name, prepend current namespace
if (pos != string::npos) {
return nsDecl(ns);
}
// unqualified name in global namespace
if (m_namespace.empty()) {
return ns;
}
if (!strcasecmp("true", ns.c_str()) ||
!strcasecmp("false", ns.c_str()) ||
!strcasecmp("null", ns.c_str())) {
return ns;
}
return nsDecl(ns);
}
///////////////////////////////////////////////////////////////////////////////
}
-20
Ver Arquivo
@@ -168,14 +168,6 @@ public:
ScannerToken *stmt);
void popLabelInfo();
// for namespace support
void onNamespaceStart(const std::string &ns, bool file_scope = false);
void onNamespaceEnd();
void onUse(const std::string &ns, const std::string &as);
void nns(int token = 0);
std::string nsDecl(const std::string &name);
std::string resolve(const std::string &ns, bool cls);
enum GotoError {
UndefLabel = 1,
InvalidBlock,
@@ -228,18 +220,6 @@ protected:
};
std::vector<LabelInfo> m_labelInfos; // stack by function
// for namespace support
enum NamespaceState {
SeenNothing,
SeenNonNamespaceStatement,
SeenNamespaceStatement,
InsideNamespace,
};
NamespaceState m_nsState;
bool m_nsFileScope;
std::string m_namespace; // current namespace
hphp_string_imap<std::string> m_aliases;
// for closure hidden name
static Mutex s_mutex;
static std::map<int64_t, int> s_closureIds;
+20
Ver Arquivo
@@ -515,6 +515,26 @@ struct Parser : ParserBase {
void onTypeSpecialization(const Token& type, char specialization) {
X(type, specialization);
}
// for namespace support
void onNamespaceStart(const std::string &ns, bool file_scope = false) {
X(ns, file_scope);
}
void onNamespaceEnd() {}
void onUse(const std::string &ns, const std::string &as) {
X(ns, as);
}
void nns(bool declare = false) {
X(declare);
}
std::string nsDecl(const std::string &name) {
X(name);
return name;
}
std::string resolve(const std::string &ns, bool cls) {
X(ns, cls);
return ns;
}
};
//////////////////////////////////////////////////////////////////////