diff --git a/tests/manual/binding/binding.pro b/tests/manual/binding/binding.pro index 56741107c2809312c11bf9d668a45b2537ce8e02..2ac26f337aef0e9ae78bca66ddedcfeb66559f79 100644 --- a/tests/manual/binding/binding.pro +++ b/tests/manual/binding/binding.pro @@ -1,14 +1,14 @@ QT = + macx:CONFIG -= app_bundle + TARGET = cplusplus0 + *-g++*:QMAKE_CXXFLAGS += -fno-rtti \ - -fno-exceptions \ - -O2 + -fno-exceptions + include(../../../src/shared/cplusplus/cplusplus.pri) -# Input -SOURCES += main.cpp \ - LinkedNamespace.cpp unix { debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared @@ -17,4 +17,6 @@ unix { RCC_DIR = $${OUT_PWD}/.rcc/ UI_DIR = $${OUT_PWD}/.uic/ } -HEADERS += LinkedNamespace.h + +# Input +SOURCES += main.cpp diff --git a/tests/manual/binding/main.cpp b/tests/manual/binding/main.cpp index 451d7f142046d5fbfdb113cf7fa358ae966771d9..8e889b6b514e2098da831e43ecb5f2bad20c4804 100644 --- a/tests/manual/binding/main.cpp +++ b/tests/manual/binding/main.cpp @@ -38,6 +38,10 @@ #include <Semantic.h> #include <TranslationUnit.h> #include <PrettyPrinter.h> +#include <Symbolvisitor.h> +#include <Names.h> +#include <Symbols.h> +#include <Literals.h> #include <cstdio> #include <cstdlib> @@ -46,6 +50,288 @@ #include <fstream> #include <sstream> + +//////////////////////////////////////////////////////////////////////////////// +// NamespaceBinding +//////////////////////////////////////////////////////////////////////////////// + +class NamespaceBinding +{ +public: + /// Constructs a binding with the given parent. + NamespaceBinding(NamespaceBinding *parent = 0); + + /// Destroys the binding. + ~NamespaceBinding(); + + /// Returns this binding's name. + NameId *name() const; + + /// Returns this binding's identifier. + Identifier *identifier() const; + + /// Returns the binding for the global namespace (aka ::). + NamespaceBinding *globalNamespaceBinding(); + + /// Returns the binding for the given namespace symbol. + NamespaceBinding *findNamespaceBinding(Name *name); + + /// Returns the binding associated with the given symbol. + NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); + + /// Helpers. + std::string qualifiedId() const; + void dump(); + +private: + NamespaceBinding *findNamespaceBindingForNameId(NameId *name); + +public: // attributes + /// This binding's parent. + NamespaceBinding *parent; + + /// Binding for anonymous namespace symbols. + NamespaceBinding *anonymousNamespaceBinding; + + /// This binding's connections. + Array<NamespaceBinding *> children; + + /// This binding's namespace symbols. + Array<Namespace *> symbols; +}; + +NamespaceBinding::NamespaceBinding(NamespaceBinding *parent) + : parent(parent), + anonymousNamespaceBinding(0) +{ + if (parent) + parent->children.push_back(this); +} + +NamespaceBinding::~NamespaceBinding() +{ + for (unsigned i = 0; i < children.size(); ++i) { + NamespaceBinding *binding = children.at(i); + + delete binding; + } +} + +NameId *NamespaceBinding::name() const +{ + if (symbols.size()) { + if (Name *name = symbols.at(0)->name()) { + NameId *nameId = name->asNameId(); + assert(nameId != 0); + + return nameId; + } + } + + return 0; +} + +Identifier *NamespaceBinding::identifier() const +{ + if (NameId *nameId = name()) + return nameId->identifier(); + + return 0; +} + +NamespaceBinding *NamespaceBinding::globalNamespaceBinding() +{ + NamespaceBinding *it = this; + + for (; it; it = it->parent) { + if (! it->parent) + break; + } + + return it; +} + +NamespaceBinding *NamespaceBinding::findNamespaceBinding(Name *name) +{ + if (! name) + return anonymousNamespaceBinding; + + else if (NameId *nameId = name->asNameId()) + return findNamespaceBindingForNameId(nameId); + + // invalid binding + return 0; +} + +NamespaceBinding *NamespaceBinding::findNamespaceBindingForNameId(NameId *name) +{ + for (unsigned i = 0; i < children.size(); ++i) { + NamespaceBinding *binding = children.at(i); + Name *bindingName = binding->name(); + + if (! bindingName) + continue; + + if (NameId *bindingNameId = bindingName->asNameId()) { + if (name->isEqualTo(bindingNameId)) + return binding; + } + } + + return 0; +} + +NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symbol) +{ + if (NamespaceBinding *binding = findNamespaceBinding(symbol->name())) { + unsigned index = 0; + + for (; index < binding->symbols.size(); ++index) { + Namespace *ns = binding->symbols.at(index); + + if (ns == symbol) + break; + } + + if (index == binding->symbols.size()) + binding->symbols.push_back(symbol); + + return binding; + } + + NamespaceBinding *binding = new NamespaceBinding(this); + binding->symbols.push_back(symbol); + + if (! symbol->name()) { + assert(! anonymousNamespaceBinding); + + anonymousNamespaceBinding = binding; + } + + return binding; +} + +// ### rewrite me +std::string NamespaceBinding::qualifiedId() const +{ + if (! parent) + return "<root>"; + + std::string s; + + s.append(parent->qualifiedId()); + s.append("::"); + + if (Identifier *id = identifier()) + s.append(id->chars(), id->size()); + + else + s.append("<anonymous>"); + + return s; +} + +void NamespaceBinding::dump() +{ + static int depth; + + std::cout << std::string(depth, ' ') << qualifiedId() + << " # " << symbols.size() << std::endl; + ++depth; + + for (unsigned i = 0; i < children.size(); ++i) + children.at(i)->dump(); + + --depth; +} + +//////////////////////////////////////////////////////////////////////////////// +// Binder +//////////////////////////////////////////////////////////////////////////////// + +class Binder: protected SymbolVisitor +{ +public: + Binder(); + virtual ~Binder(); + + NamespaceBinding *operator()(Symbol *symbol) + { return bind(symbol, 0); } + +protected: + NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding); + NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); + + NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding); + + using SymbolVisitor::visit; + + virtual bool visit(Namespace *); + virtual bool visit(Class *); + virtual bool visit(Function *); + virtual bool visit(Block *); + +private: + NamespaceBinding *namespaceBinding; +}; + +Binder::Binder() + : namespaceBinding(0) +{ } + +Binder::~Binder() +{ } + +NamespaceBinding *Binder::bind(Symbol *symbol, NamespaceBinding *binding) +{ + NamespaceBinding *previousBinding = switchNamespaceBinding(binding); + accept(symbol); + return switchNamespaceBinding(previousBinding); +} + +NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol) +{ + if (namespaceBinding) + return namespaceBinding->findOrCreateNamespaceBinding(symbol); + + namespaceBinding = new NamespaceBinding; + namespaceBinding->symbols.push_back(symbol); + return namespaceBinding; +} + +NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding) +{ + NamespaceBinding *previousBinding = namespaceBinding; + namespaceBinding = binding; + return previousBinding; +} + +bool Binder::visit(Namespace *symbol) +{ + NamespaceBinding *binding = findOrCreateNamespaceBinding(symbol); + + for (unsigned i = 0; i < symbol->memberCount(); ++i) { + Symbol *member = symbol->memberAt(i); + + bind(member, binding); + } + + return false; +} + +bool Binder::visit(Class *) +{ return false; } + +bool Binder::visit(Function *) +{ return false; } + +bool Binder::visit(Block *) +{ return false; } + +//////////////////////////////////////////////////////////////////////////////// +// Entry point +//////////////////////////////////////////////////////////////////////////////// + static int usage() { std::cerr << "cplusplus0: no input files" << std::endl; @@ -82,11 +368,17 @@ int main(int argc, char *argv[]) TranslationUnitAST *ast = unit.ast()->asTranslationUnit(); assert(ast != 0); - Scope globalScope; + Namespace *globalNamespace = control.newNamespace(0, 0); // namespace symbol for `::' Semantic sem(&control); for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) { - sem.check(decl, &globalScope); + sem.check(decl, globalNamespace->members()); } + // bind + Binder bind; + NamespaceBinding *binding = bind(globalNamespace); + binding->dump(); + delete binding; + return EXIT_SUCCESS; }