diff --git a/src/shared/cplusplus/ASTVisitor.cpp b/src/shared/cplusplus/ASTVisitor.cpp index 7b9ca1ed7faeb251e911a61803594198790a6bd2..d08d1c4d93d17a471c03f4c591d58ec4c9aa580e 100644 --- a/src/shared/cplusplus/ASTVisitor.cpp +++ b/src/shared/cplusplus/ASTVisitor.cpp @@ -77,12 +77,7 @@ int ASTVisitor::tokenKind(unsigned index) const { return translationUnit()->tokenKind(index); } const char *ASTVisitor::spell(unsigned index) const -{ - if (! index) - return 0; - - return translationUnit()->tokenAt(index).spell(); -} +{ return translationUnit()->spell(index); } Identifier *ASTVisitor::identifier(unsigned index) const { return translationUnit()->identifier(index); } diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp index f8ddde8b48e8b8162ba29888fafd067633dbcf79..038583c27d4bab26a0448e3548f0042953ac8cbf 100644 --- a/src/shared/cplusplus/CheckDeclaration.cpp +++ b/src/shared/cplusplus/CheckDeclaration.cpp @@ -389,6 +389,11 @@ bool CheckDeclaration::visit(UsingDirectiveAST *ast) UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name); ast->symbol = u; _scope->enterSymbol(u); + + if (! (_scope->isBlockScope() || _scope->isNamespaceScope())) + translationUnit()->error(ast->firstToken(), + "using-directive not within namespace or block scope"); + return false; } diff --git a/src/shared/cplusplus/TranslationUnit.cpp b/src/shared/cplusplus/TranslationUnit.cpp index 40a95c0f05d7f49860012e780ec2cc7ad75583f9..ebadf35c75a9d2cfaf485b4034838ae656bc0075 100644 --- a/src/shared/cplusplus/TranslationUnit.cpp +++ b/src/shared/cplusplus/TranslationUnit.cpp @@ -134,6 +134,14 @@ const Token &TranslationUnit::tokenAt(unsigned index) const int TranslationUnit::tokenKind(unsigned index) const { return _tokens->at(index).kind; } +const char *TranslationUnit::spell(unsigned index) const +{ + if (! index) + return 0; + + return _tokens->at(index).spell(); +} + Identifier *TranslationUnit::identifier(unsigned index) const { return _tokens->at(index).identifier; } diff --git a/src/shared/cplusplus/TranslationUnit.h b/src/shared/cplusplus/TranslationUnit.h index aa490701ef9d01ab7ad6478571bd10e996e6c674..7a57950ac34078034cc5ef76b68d9a0d2a2e596b 100644 --- a/src/shared/cplusplus/TranslationUnit.h +++ b/src/shared/cplusplus/TranslationUnit.h @@ -87,6 +87,7 @@ public: unsigned tokenCount() const; const Token &tokenAt(unsigned index) const; int tokenKind(unsigned index) const; + const char *spell(unsigned index) const; unsigned matchingBrace(unsigned index) const; Identifier *identifier(unsigned index) const; diff --git a/tests/manual/binding/main.cpp b/tests/manual/binding/main.cpp index 8e889b6b514e2098da831e43ecb5f2bad20c4804..77aa298b0e09227e9e4c2e303551a7c46d903417 100644 --- a/tests/manual/binding/main.cpp +++ b/tests/manual/binding/main.cpp @@ -43,6 +43,8 @@ #include <Symbols.h> #include <Literals.h> +#include <vector> + #include <cstdio> #include <cstdlib> #include <cassert> @@ -79,6 +81,11 @@ public: /// Returns the binding associated with the given symbol. NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); + NamespaceBinding *resolveNamespace(QualifiedNameId *q, unsigned index, + unsigned count); + + NamespaceBinding *resolveNamespace(Name *name, bool lookAtParent = true); + /// Helpers. std::string qualifiedId() const; void dump(); @@ -96,6 +103,9 @@ public: // attributes /// This binding's connections. Array<NamespaceBinding *> children; + /// This binding's usings + Array<NamespaceBinding *> usings; + /// This binding's namespace symbols. Array<Namespace *> symbols; }; @@ -211,6 +221,99 @@ NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symb return binding; } +static void closure(NamespaceBinding *binding, Name *name, + Array<NamespaceBinding *> *bindings) +{ + for (unsigned i = 0; i < bindings->size(); ++i) { + NamespaceBinding *b = bindings->at(i); + + if (b == binding) + return; + } + + bindings->push_back(binding); + + assert(name->isNameId()); + + Identifier *id = name->asNameId()->identifier(); + bool ignoreUsingDirectives = false; + + for (unsigned i = 0; i < binding->symbols.size(); ++i) { + Namespace *symbol = binding->symbols.at(i); + Scope *scope = symbol->members(); + + for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) { + if (symbol->isUsingDeclaration() || symbol->isUsingNamespaceDirective()) + continue; + + //printf("found declaration at %s:%d\n", symbol->fileName(), symbol->line()); + + // ### FIXME: ignoreUsingDirectives = true; + break; + } + } + + if (ignoreUsingDirectives) + return; + + for (unsigned i = 0; i < binding->usings.size(); ++i) { + NamespaceBinding *u = binding->usings.at(i); + + closure(u, name, bindings); + } +} + + +NamespaceBinding *NamespaceBinding::resolveNamespace(Name *name, bool lookAtParent) +{ + if (! name) + return 0; + + else if (NameId *nameId = name->asNameId()) { + Array<NamespaceBinding *> bindings; + closure(this, nameId, &bindings); + + Array<NamespaceBinding *> results; + + for (unsigned i = 0; i < bindings.size(); ++i) { + NamespaceBinding *binding = bindings.at(i); + + if (NamespaceBinding *b = binding->findNamespaceBinding(nameId)) + results.push_back(b); + } + + if (results.size() == 1) + return results.at(0); + + else if (results.size() > 1) { + // ### FIXME: return 0; + return results.at(0); + } + + else if (parent && lookAtParent) + return parent->resolveNamespace(name); + + } else if (QualifiedNameId *q = name->asQualifiedNameId()) { + if (q->nameCount() == 1) { + assert(q->isGlobal()); + + return globalNamespaceBinding()->resolveNamespace(q->nameAt(0)); + } + + NamespaceBinding *current = this; + if (q->isGlobal()) + current = globalNamespaceBinding(); + + current = current->resolveNamespace(q->nameAt(0)); + for (unsigned i = 1; current && i < q->nameCount(); ++i) + current = current->resolveNamespace(q->nameAt(i), false); + + return current; + } + + return 0; +} + // ### rewrite me std::string NamespaceBinding::qualifiedId() const { @@ -255,28 +358,38 @@ public: Binder(); virtual ~Binder(); - NamespaceBinding *operator()(Symbol *symbol) - { return bind(symbol, 0); } + NamespaceBinding *operator()(TranslationUnit *u, Namespace *globals) + { + TranslationUnit *previousUnit = unit; + unit = u; + NamespaceBinding *binding = bind(globals, 0); + unit = previousUnit; + return binding; + } protected: NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding); NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); + NamespaceBinding *resolveNamespace(Name *name); NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding); using SymbolVisitor::visit; virtual bool visit(Namespace *); + virtual bool visit(UsingNamespaceDirective *); virtual bool visit(Class *); virtual bool visit(Function *); virtual bool visit(Block *); private: NamespaceBinding *namespaceBinding; + TranslationUnit *unit; }; Binder::Binder() - : namespaceBinding(0) + : namespaceBinding(0), + unit(0) { } Binder::~Binder() @@ -299,6 +412,15 @@ NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol) return namespaceBinding; } +NamespaceBinding *Binder::resolveNamespace(Name *name) +{ + if (! namespaceBinding) + return 0; + + return namespaceBinding->resolveNamespace(name); +} + + NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding) { NamespaceBinding *previousBinding = namespaceBinding; @@ -319,6 +441,20 @@ bool Binder::visit(Namespace *symbol) return false; } +bool Binder::visit(UsingNamespaceDirective *u) +{ + NamespaceBinding *resolved = resolveNamespace(u->name()); + + if (! resolved) { + unit->error(u->sourceLocation(), "expected namespace-name"); + return false; + } + + namespaceBinding->usings.push_back(resolved); + + return false; +} + bool Binder::visit(Class *) { return false; } @@ -376,7 +512,7 @@ int main(int argc, char *argv[]) // bind Binder bind; - NamespaceBinding *binding = bind(globalNamespace); + NamespaceBinding *binding = bind(&unit, globalNamespace); binding->dump(); delete binding;