From 8209b35814c5f5cfbbe03a3283ae356f9315e926 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 18 Feb 2009 12:13:57 +0100 Subject: [PATCH 1/3] Fun with the binding pass. --- tests/manual/binding/binding.pro | 20 +++++++ tests/manual/binding/c++ | 8 +++ tests/manual/binding/conf.c++ | 8 +++ tests/manual/binding/main.cpp | 92 ++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 tests/manual/binding/binding.pro create mode 100755 tests/manual/binding/c++ create mode 100644 tests/manual/binding/conf.c++ create mode 100644 tests/manual/binding/main.cpp diff --git a/tests/manual/binding/binding.pro b/tests/manual/binding/binding.pro new file mode 100644 index 00000000000..10f637cf89a --- /dev/null +++ b/tests/manual/binding/binding.pro @@ -0,0 +1,20 @@ +QT = # +macx:CONFIG -= app_bundle +TARGET = cplusplus0 +*-g++*:QMAKE_CXXFLAGS += -fno-rtti -fno-exceptions -O2 + +include(../../../src/shared/cplusplus/cplusplus.pri) + +# Input +SOURCES += main.cpp + +unix { + debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared + release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared + + debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared + release:MOC_DIR = $${OUT_PWD}/.moc/release-shared + + RCC_DIR = $${OUT_PWD}/.rcc/ + UI_DIR = $${OUT_PWD}/.uic/ +} diff --git a/tests/manual/binding/c++ b/tests/manual/binding/c++ new file mode 100755 index 00000000000..dcdbeef64de --- /dev/null +++ b/tests/manual/binding/c++ @@ -0,0 +1,8 @@ +#!/bin/sh +me=$(dirname $0) +t=$(mktemp -t c++) +echo "Generating $t" +${CPP-gcc} -xc++ -E -include $me/conf.c++ $* > $t +echo "Parsing $t" +$me/cplusplus0 $t + diff --git a/tests/manual/binding/conf.c++ b/tests/manual/binding/conf.c++ new file mode 100644 index 00000000000..c179f979272 --- /dev/null +++ b/tests/manual/binding/conf.c++ @@ -0,0 +1,8 @@ +#define __extension__ +#define __context__ +#define __range__ +#define __asm(a...) +#define __asm__(a...) +#define restrict +#define __restrict +#define __weak diff --git a/tests/manual/binding/main.cpp b/tests/manual/binding/main.cpp new file mode 100644 index 00000000000..451d7f14204 --- /dev/null +++ b/tests/manual/binding/main.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.3, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int usage() +{ + std::cerr << "cplusplus0: no input files" << std::endl; + return EXIT_FAILURE; +} + +int main(int argc, char *argv[]) +{ + if (argc == 1) + return usage(); + + std::fstream in(argv[1]); + + if (! in) + return usage(); + + in.seekg(0, std::ios::end); + const size_t size = in.tellg(); + in.seekp(0, std::ios::beg); + + std::vector source(size + 1); + in.read(&source[0], size); + source[size] = '\0'; + + Control control; + StringLiteral *fileId = control.findOrInsertFileName(argv[1]); + TranslationUnit unit(&control, fileId); + unit.setObjCEnabled(true); + unit.setSource(&source[0], source.size()); + unit.parse(); + if (! unit.ast()) + return EXIT_FAILURE; + + TranslationUnitAST *ast = unit.ast()->asTranslationUnit(); + assert(ast != 0); + + Scope globalScope; + Semantic sem(&control); + for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) { + sem.check(decl, &globalScope); + } + + return EXIT_SUCCESS; +} From 01faad422841f17517ae70e62ada65825b0a370a Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 18 Feb 2009 14:12:43 +0100 Subject: [PATCH 2/3] updated the pro file --- tests/manual/binding/binding.pro | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/manual/binding/binding.pro b/tests/manual/binding/binding.pro index 10f637cf89a..56741107c28 100644 --- a/tests/manual/binding/binding.pro +++ b/tests/manual/binding/binding.pro @@ -1,20 +1,20 @@ -QT = # +QT = macx:CONFIG -= app_bundle TARGET = cplusplus0 -*-g++*:QMAKE_CXXFLAGS += -fno-rtti -fno-exceptions -O2 - +*-g++*:QMAKE_CXXFLAGS += -fno-rtti \ + -fno-exceptions \ + -O2 include(../../../src/shared/cplusplus/cplusplus.pri) # Input -SOURCES += main.cpp - -unix { +SOURCES += main.cpp \ + LinkedNamespace.cpp +unix { debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared - debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared release:MOC_DIR = $${OUT_PWD}/.moc/release-shared - RCC_DIR = $${OUT_PWD}/.rcc/ UI_DIR = $${OUT_PWD}/.uic/ } +HEADERS += LinkedNamespace.h From 764379deb72cb07d6704327d9b2577075b0f35d9 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Thu, 19 Feb 2009 12:09:38 +0100 Subject: [PATCH 3/3] Initial work on the binder. --- tests/manual/binding/binding.pro | 14 +- tests/manual/binding/main.cpp | 296 ++++++++++++++++++++++++++++++- 2 files changed, 302 insertions(+), 8 deletions(-) diff --git a/tests/manual/binding/binding.pro b/tests/manual/binding/binding.pro index 56741107c28..2ac26f337ae 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 451d7f14204..8e889b6b514 100644 --- a/tests/manual/binding/main.cpp +++ b/tests/manual/binding/main.cpp @@ -38,6 +38,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -46,6 +50,288 @@ #include #include + +//////////////////////////////////////////////////////////////////////////////// +// 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 children; + + /// This binding's namespace symbols. + Array 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 ""; + + std::string s; + + s.append(parent->qualifiedId()); + s.append("::"); + + if (Identifier *id = identifier()) + s.append(id->chars(), id->size()); + + else + s.append(""); + + 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; }