From 29c3a2eb5fd5b4cbc5ed4786af8ff260e7f98426 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 30 Sep 2010 17:42:53 +0200 Subject: [PATCH 001/118] Fixed some usebuilder / declarationbuilder stuff with global variables --- duchain/declarationbuilder.cpp | 7 ++++--- duchain/usebuilder.cpp | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index ab4fe16..6dc16aa 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -106,16 +106,17 @@ void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) { Python::AstDefaultVisitor::visitIdentifierTarget(node); - QList existingDeclarations; + QList existingLocalDeclarations; { DUChainWriteLocker lock( DUChain::lock() ); RangeInRevision range = editorFindRange(node, node); CursorInRevision stopSearching = range.start; QualifiedIdentifier id = identifierForNode(node->identifier); - existingDeclarations = currentContext()->findDeclarations(id, stopSearching); + existingLocalDeclarations = currentContext()->findLocalDeclarations(id.last(), stopSearching); } - if ( ! existingDeclarations.length() ) { + + if ( ! existingLocalDeclarations.length() ) { openDeclaration( node->identifier, node); closeDeclaration(); } diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index fd03b39..845a018 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -57,17 +57,27 @@ void UseBuilder::visitIdentifier(IdentifierAst* node) QualifiedIdentifier id = identifierForNode(node); RangeInRevision range = editorFindRange(node, node); CursorInRevision until = range.start; - QList dec = currentContext()->findDeclarations(id, until); - - kDebug() << "-- identifier: " << node->identifier.toAscii(); - kDebug() << "declaration count: " << dec.length(); - kDebug() << "is type: " << node->parent->astType; + QList allDeclarations = currentContext()->findDeclarations(id, until); + + Declaration *globalDeclaration = 0; + foreach ( Declaration* dec, allDeclarations ) { + if ( dec->context() == dec->topContext() ) { + kDebug() << "There's already a global declaration for" << node->identifier; + globalDeclaration = dec; + } + } // only highlight the top level properties; maybe we find a way to do the others later - // but it'll be difficult + // but it'll be difficult and it'll require a TypeBuilder if ( node->parent->astType == Python::Ast::AtomAst ) { - if ( dec.length() ) { - UseBuilderBase::newUse(node, dec.last()); + // if there's a local declaration, use the last one of those + if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { + UseBuilderBase::newUse(node, allDeclarations.last()); + } + // otherwise, use the global one. + // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 + else if ( globalDeclaration ) { + UseBuilderBase::newUse(node, globalDeclaration); } } } From c0cdeb24926de2c511c8acb9e918fa7f4387e1b7 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 1 Oct 2010 01:09:29 +0200 Subject: [PATCH 002/118] some (stupid!) tooltip tests --- pythonlanguagesupport.cpp | 19 +++++++++++++++++++ pythonlanguagesupport.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/pythonlanguagesupport.cpp b/pythonlanguagesupport.cpp index b421039..cb48806 100644 --- a/pythonlanguagesupport.cpp +++ b/pythonlanguagesupport.cpp @@ -48,6 +48,10 @@ #include "duchain/pythoneditorintegrator.h" #include +#include +#include +#include +#include using namespace KDevelop; @@ -93,6 +97,21 @@ KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const return m_highlighting; } +QWidget* LanguageSupport::specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position) +{ + kDebug() << "Navigation widget requested *** "; + // QWidget* navWidget = ILanguageSupport::specialLanguageObjectNavigationWidget(url, position); +// kDebug() << navWidget; + QWidget *navWidget = new QWidget(); + QLabel *label = new QLabel(); + QHBoxLayout *layout = new QHBoxLayout(); + label->setText("Foo!"); + layout->addWidget(label); + navWidget->setLayout(layout); + return navWidget; +} + + } #include "pythonlanguagesupport.moc" diff --git a/pythonlanguagesupport.h b/pythonlanguagesupport.h index a7d8291..bb70246 100644 --- a/pythonlanguagesupport.h +++ b/pythonlanguagesupport.h @@ -61,6 +61,8 @@ class LanguageSupport : public KDevelop::IPlugin, public KDevelop::ILanguageSupp KDevelop::ILanguage *language(); /*the code highlighter*/ KDevelop::ICodeHighlighting* codeHighlighting() const; + + virtual QWidget* specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position); private: Highlighting* m_highlighting; From d7571990d0690788bc1e8311b7458b600bb99104 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 9 Oct 2010 15:01:05 +0200 Subject: [PATCH 003/118] Added a code completion outline thingy which does not work --- .kdev_include_paths | 6 ++-- CMakeLists.txt | 7 ++-- codecompletion/CMakeLists.txt | 19 +++++++++++ .../pythoncodecompletioncontext.cpp | 18 +++++++++++ codecompletion/pythoncodecompletioncontext.h | 14 ++++++++ codecompletion/pythoncodecompletionmodel.cpp | 22 +++++++++++++ codecompletion/pythoncodecompletionmodel.h | 19 +++++++++++ codecompletion/pythoncodecompletionworker.cpp | 13 ++++++++ codecompletion/pythoncodecompletionworker.h | 16 ++++++++++ codecompletion/pythoncompletionexport.h | 16 ++++++++++ duchain/CMakeLists.txt | 3 +- duchain/usebuilder.cpp | 32 ++++++++++++------- duchain/usebuilder.h | 3 +- pythonlanguagesupport.cpp | 24 +++++++------- pythonlanguagesupport.h | 2 +- 15 files changed, 180 insertions(+), 34 deletions(-) create mode 100644 codecompletion/CMakeLists.txt create mode 100644 codecompletion/pythoncodecompletioncontext.cpp create mode 100644 codecompletion/pythoncodecompletioncontext.h create mode 100644 codecompletion/pythoncodecompletionmodel.cpp create mode 100644 codecompletion/pythoncodecompletionmodel.h create mode 100644 codecompletion/pythoncodecompletionworker.cpp create mode 100644 codecompletion/pythoncodecompletionworker.h create mode 100644 codecompletion/pythoncompletionexport.h diff --git a/.kdev_include_paths b/.kdev_include_paths index a42a356..93a055e 100644 --- a/.kdev_include_paths +++ b/.kdev_include_paths @@ -1,3 +1,5 @@ -../kdevelop/ -../kdevplatform/ +../kdevelop +../kdevplatform /home/sven/projects/.build/kde4/python/parser +/home/sven/projects/kde4/kdevplatform +/home/sven/projects/kde4/kdevelop diff --git a/CMakeLists.txt b/CMakeLists.txt index fc5af3b..5d9aadc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${kdevpython_SOURCE_DIR}/cmake/) #complain about the FindKDevelop-PG.cmake file not findable. find_package(KDE4 REQUIRED) -find_package(KDevPlatform 0.9.80 REQUIRED) +find_package(KDevPlatform 1.0.0 REQUIRED) include_directories( ${KDEVPLATFORM_INCLUDE_DIR} @@ -30,6 +30,7 @@ include_directories( add_subdirectory(parser) add_subdirectory(duchain) +add_subdirectory(codecompletion) set(kdevpythonlanguagesupport_PART_SRCS pythonlanguagesupport.cpp @@ -47,11 +48,9 @@ target_link_libraries(kdevpythonlanguagesupport ${KDE4_KTEXTEDITOR_LIBS} kdev4pythonparser kdev4pythonduchain + kdev4phpcompletion ) install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) - - - diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt new file mode 100644 index 0000000..ff2aa22 --- /dev/null +++ b/codecompletion/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories( + ${CMAKE_CURRENT_BINRAY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +set(completion_SRCS + pythoncodecompletioncontext.cpp + pythoncodecompletionmodel.cpp + pythoncodecompletionworker.cpp +) + +kde4_add_library(kdev4pythoncompletion SHARED ${completion_SRCS}) + +target_link_libraries(kdev4pythoncompletion + ${KDE4_KDECORE_LIBS} + ${KDEVPLATFORM_LANGUAGE_LIBRARIES} +) + +install(TARGETS ${kdev4pythoncompletion} DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp new file mode 100644 index 0000000..3d3ab5c --- /dev/null +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -0,0 +1,18 @@ +#include "pythoncodecompletioncontext.h" +#include +#include +#include +#include + +using namespace KDevelop; + +QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) +{ + QList items; + + CompletionTreeItem* item = new CompletionTreeItem(); + items << CompletionTreeItemPointer( item ); + + return items; +} + diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h new file mode 100644 index 0000000..c706e21 --- /dev/null +++ b/codecompletion/pythoncodecompletioncontext.h @@ -0,0 +1,14 @@ +#ifndef PYTHONCODECOMPLETIONCONTEXT_H +#define PYTHONCODECOMPLETIONCONTEXT_H + +#include + + +class PythonCodeCompletionContext : public KDevelop::CodeCompletionContext +{ + +public: + virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); +}; + +#endif // PYTHONCODECOMPLETIONCONTEXT_H diff --git a/codecompletion/pythoncodecompletionmodel.cpp b/codecompletion/pythoncodecompletionmodel.cpp new file mode 100644 index 0000000..16ecb00 --- /dev/null +++ b/codecompletion/pythoncodecompletionmodel.cpp @@ -0,0 +1,22 @@ +#include "pythoncodecompletionmodel.h" +#include "pythoncodecompletionworker.h" +#include "ktexteditor/view.h" + +PythonCodeCompletionModel::PythonCodeCompletionModel(QObject* parent) + : CodeCompletionModel(parent) +{ + +} + +PythonCodeCompletionModel::~PythonCodeCompletionModel() { } + + +KTextEditor::Range PythonCodeCompletionModel::completionRange(KTextEditor::View* view, const KTextEditor::Cursor& position) +{ + return KTextEditor::CodeCompletionModelControllerInterface3::completionRange(view, position); +} + +KDevelop::CodeCompletionWorker* PythonCodeCompletionModel::createCompletionWorker() +{ + return new PythonCodeCompletionWorker(this); +} diff --git a/codecompletion/pythoncodecompletionmodel.h b/codecompletion/pythoncodecompletionmodel.h new file mode 100644 index 0000000..212af1a --- /dev/null +++ b/codecompletion/pythoncodecompletionmodel.h @@ -0,0 +1,19 @@ +#ifndef PYTHONCODECOMPLETIONMODEL_H +#define PYTHONCODECOMPLETIONMODEL_H + +#include +#include +#include "pythoncompletionexport.h" + +class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionModel : public KDevelop::CodeCompletionModel +{ + +public: + PythonCodeCompletionModel(QObject* parent); + virtual ~PythonCodeCompletionModel(); + + virtual KDevelop::CodeCompletionWorker* createCompletionWorker(); + KTextEditor::Range completionRange(KTextEditor::View* view, const KTextEditor::Cursor &position); +}; + +#endif // PYTHONCODECOMPLETIONMODEL_H diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp new file mode 100644 index 0000000..7009e8d --- /dev/null +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -0,0 +1,13 @@ +#include "pythoncodecompletionworker.h" +#include "pythoncodecompletionmodel.h" + +PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel *parent) + : KDevelop::CodeCompletionWorker(parent) +{ + +} + +KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const +{ + return KDevelop::CodeCompletionWorker::createCompletionContext(context, contextText, followingText, position); +} diff --git a/codecompletion/pythoncodecompletionworker.h b/codecompletion/pythoncodecompletionworker.h new file mode 100644 index 0000000..6894fed --- /dev/null +++ b/codecompletion/pythoncodecompletionworker.h @@ -0,0 +1,16 @@ +#ifndef PYTHONCODECOMPLETIONWORKER_H +#define PYTHONCODECOMPLETIONWORKER_H + +#include "pythoncodecompletionmodel.h" +#include +#include + +class PythonCodeCompletionWorker : public KDevelop::CodeCompletionWorker +{ + +public: + PythonCodeCompletionWorker(PythonCodeCompletionModel *parent); + virtual KDevelop::CodeCompletionContext* createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const; +}; + +#endif // PYTHONCODECOMPLETIONWORKER_H diff --git a/codecompletion/pythoncompletionexport.h b/codecompletion/pythoncompletionexport.h new file mode 100644 index 0000000..c4dc416 --- /dev/null +++ b/codecompletion/pythoncompletionexport.h @@ -0,0 +1,16 @@ +#ifndef PYTHONCOMPLETIONEXPORT_H +#define PYTHONCOMPLETIONEXPORT_H + +/* needed for KDE_EXPORT macros */ +#include + + +#ifndef KDEVPYTHONCOMPLETION_EXPORT +# ifdef MAKE_KDEV4PYTHONCOMPLETION_LIB +# define KDEVPYTHONCOMPLETION_EXPORT KDE_EXPORT +# else +# define KDEVPYTHONCOMPLETION_EXPORT KDE_IMPORT +# endif +#endif + +#endif \ No newline at end of file diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 5fe750f..e970cd3 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -3,7 +3,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) -set(duchain_SRCS +set(duchain_SRCS + navigationwidget.cpp contextbuilder.cpp pythoneditorintegrator.cpp declarationbuilder.cpp diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 845a018..3d07a99 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -59,6 +59,9 @@ void UseBuilder::visitIdentifier(IdentifierAst* node) CursorInRevision until = range.start; QList allDeclarations = currentContext()->findDeclarations(id, until); + kDebug() << " >> scanning " << node->identifier; + kDebug() << " > searching for declaration until" << until.line << ":" << until.column << "; " << allDeclarations.length() << "Declarations found"; + Declaration *globalDeclaration = 0; foreach ( Declaration* dec, allDeclarations ) { if ( dec->context() == dec->topContext() ) { @@ -67,21 +70,26 @@ void UseBuilder::visitIdentifier(IdentifierAst* node) } } - // only highlight the top level properties; maybe we find a way to do the others later - // but it'll be difficult and it'll require a TypeBuilder - if ( node->parent->astType == Python::Ast::AtomAst ) { - // if there's a local declaration, use the last one of those - if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { - UseBuilderBase::newUse(node, allDeclarations.last()); - } - // otherwise, use the global one. - // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 - else if ( globalDeclaration ) { - UseBuilderBase::newUse(node, globalDeclaration); - } + // if there's a local declaration, use the last one of those + if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { + kDebug() << " ++ Created a use of local declaration for node" << node->identifier; + UseBuilderBase::newUse(node, allDeclarations.last()); + } + // otherwise, use the global one. + // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 + else if ( globalDeclaration ) { + kDebug() << " ++ Created a use of global declaration for node" << node->identifier; + UseBuilderBase::newUse(node, globalDeclaration); } } +void UseBuilder::visitIdentifierTarget(IdentifierTargetAst* node) +{ + kDebug() << "Target variable identifier: " << node->identifier->identifier.toAscii(); + UseBuilderBase::visitIdentifierTarget(node); +} + + void UseBuilder::openContext(DUContext * newContext) { UseBuilderBase::openContext(newContext); diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 96f9511..5e6605a 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -47,7 +47,8 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase virtual void openContext(KDevelop::DUContext* newContext); virtual void closeContext(); - virtual void visitIdentifier(IdentifierAst *node); + virtual void visitIdentifier(IdentifierAst* node); + virtual void visitIdentifierTarget(IdentifierTargetAst* node); private: ParseSession* m_session; // void newUse(std::size_t name, Ast *rangenode); diff --git a/pythonlanguagesupport.cpp b/pythonlanguagesupport.cpp index cb48806..e7c6911 100644 --- a/pythonlanguagesupport.cpp +++ b/pythonlanguagesupport.cpp @@ -97,19 +97,17 @@ KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const return m_highlighting; } -QWidget* LanguageSupport::specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position) -{ - kDebug() << "Navigation widget requested *** "; - // QWidget* navWidget = ILanguageSupport::specialLanguageObjectNavigationWidget(url, position); -// kDebug() << navWidget; - QWidget *navWidget = new QWidget(); - QLabel *label = new QLabel(); - QHBoxLayout *layout = new QHBoxLayout(); - label->setText("Foo!"); - layout->addWidget(label); - navWidget->setLayout(layout); - return navWidget; -} +// QWidget* LanguageSupport::specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position) +// { +// kDebug() << "Navigation widget requested *** "; +// QFrame* frame = new QFrame(); +// QLabel* label = new QLabel(); +// QHBoxLayout *layout = new QHBoxLayout(); +// label->setText("Foo"); +// frame->setLayout(layout); +// layout->addWidget(label); +// return frame; +// } } diff --git a/pythonlanguagesupport.h b/pythonlanguagesupport.h index bb70246..8434b21 100644 --- a/pythonlanguagesupport.h +++ b/pythonlanguagesupport.h @@ -62,7 +62,7 @@ class LanguageSupport : public KDevelop::IPlugin, public KDevelop::ILanguageSupp /*the code highlighter*/ KDevelop::ICodeHighlighting* codeHighlighting() const; - virtual QWidget* specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position); +// virtual QWidget* specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position); private: Highlighting* m_highlighting; From 9d266d01e45685ef5c56c275975088c4fcc554d3 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 9 Oct 2010 15:36:00 +0200 Subject: [PATCH 004/118] Removed navigationwidget.cpp from CMake --- duchain/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index e970cd3..7461d8e 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -4,7 +4,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ) set(duchain_SRCS - navigationwidget.cpp +# navigationwidget.cpp contextbuilder.cpp pythoneditorintegrator.cpp declarationbuilder.cpp From 738bbc964e1a3ee3f0e89c228c91959a0df17295 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 9 Oct 2010 16:01:07 +0200 Subject: [PATCH 005/118] Don't link against kdevphpsupport. oO --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d9aadc..26080e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ target_link_libraries(kdevpythonlanguagesupport ${KDE4_KTEXTEDITOR_LIBS} kdev4pythonparser kdev4pythonduchain - kdev4phpcompletion + kdev4pythoncompletion ) install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) From 24455489de56bb783204d92ee326df90a0c94685 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 9 Oct 2010 21:34:45 +0200 Subject: [PATCH 006/118] Fixed cmake problem (kdev4pythoncompletion was not installed) --- CMakeLists.txt | 2 +- codecompletion/CMakeLists.txt | 4 ++-- codecompletion/pythoncodecompletioncontext.cpp | 3 +++ codecompletion/pythoncodecompletioncontext.h | 6 +++++- codecompletion/pythoncodecompletionmodel.cpp | 4 ++++ codecompletion/pythoncodecompletionmodel.h | 4 ++++ codecompletion/pythoncodecompletionworker.cpp | 6 ++++++ codecompletion/pythoncodecompletionworker.h | 7 ++++++- pythonlanguagesupport.cpp | 6 ++++++ 9 files changed, 37 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26080e2..dda0955 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,9 +46,9 @@ target_link_libraries(kdevpythonlanguagesupport ${KDEVPLATFORM_LANGUAGE_LIBRARIES} ${KDE4_THREADWEAVER_LIBRARIES} ${KDE4_KTEXTEDITOR_LIBS} + kdev4pythoncompletion kdev4pythonparser kdev4pythonduchain - kdev4pythoncompletion ) install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index ff2aa22..f905c41 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories( - ${CMAKE_CURRENT_BINRAY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) @@ -16,4 +16,4 @@ target_link_libraries(kdev4pythoncompletion ${KDEVPLATFORM_LANGUAGE_LIBRARIES} ) -install(TARGETS ${kdev4pythoncompletion} DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS kdev4pythoncompletion DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 3d3ab5c..a8604fc 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -6,6 +6,8 @@ using namespace KDevelop; +namespace Python { + QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { QList items; @@ -16,3 +18,4 @@ QList PythonCodeCompletionContext::completionItems(bo return items; } +} \ No newline at end of file diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index c706e21..dc7f10b 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -2,13 +2,17 @@ #define PYTHONCODECOMPLETIONCONTEXT_H #include +#include "pythoncompletionexport.h" +namespace Python { -class PythonCodeCompletionContext : public KDevelop::CodeCompletionContext +class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop::CodeCompletionContext { public: virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); }; +} + #endif // PYTHONCODECOMPLETIONCONTEXT_H diff --git a/codecompletion/pythoncodecompletionmodel.cpp b/codecompletion/pythoncodecompletionmodel.cpp index 16ecb00..acb2c98 100644 --- a/codecompletion/pythoncodecompletionmodel.cpp +++ b/codecompletion/pythoncodecompletionmodel.cpp @@ -2,6 +2,8 @@ #include "pythoncodecompletionworker.h" #include "ktexteditor/view.h" +namespace Python { + PythonCodeCompletionModel::PythonCodeCompletionModel(QObject* parent) : CodeCompletionModel(parent) { @@ -20,3 +22,5 @@ KDevelop::CodeCompletionWorker* PythonCodeCompletionModel::createCompletionWorke { return new PythonCodeCompletionWorker(this); } + +} \ No newline at end of file diff --git a/codecompletion/pythoncodecompletionmodel.h b/codecompletion/pythoncodecompletionmodel.h index 212af1a..77805e5 100644 --- a/codecompletion/pythoncodecompletionmodel.h +++ b/codecompletion/pythoncodecompletionmodel.h @@ -5,6 +5,8 @@ #include #include "pythoncompletionexport.h" +namespace Python { + class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionModel : public KDevelop::CodeCompletionModel { @@ -16,4 +18,6 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionModel : public KDevelop::C KTextEditor::Range completionRange(KTextEditor::View* view, const KTextEditor::Cursor &position); }; +} + #endif // PYTHONCODECOMPLETIONMODEL_H diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp index 7009e8d..0c3fe5d 100644 --- a/codecompletion/pythoncodecompletionworker.cpp +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -1,6 +1,9 @@ #include "pythoncodecompletionworker.h" #include "pythoncodecompletionmodel.h" + +namespace Python { + PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel *parent) : KDevelop::CodeCompletionWorker(parent) { @@ -11,3 +14,6 @@ KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionCon { return KDevelop::CodeCompletionWorker::createCompletionContext(context, contextText, followingText, position); } + + +} \ No newline at end of file diff --git a/codecompletion/pythoncodecompletionworker.h b/codecompletion/pythoncodecompletionworker.h index 6894fed..0cef1b0 100644 --- a/codecompletion/pythoncodecompletionworker.h +++ b/codecompletion/pythoncodecompletionworker.h @@ -4,8 +4,11 @@ #include "pythoncodecompletionmodel.h" #include #include +#include "pythoncompletionexport.h" -class PythonCodeCompletionWorker : public KDevelop::CodeCompletionWorker +namespace Python { + +class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionWorker : public KDevelop::CodeCompletionWorker { public: @@ -14,3 +17,5 @@ class PythonCodeCompletionWorker : public KDevelop::CodeCompletionWorker }; #endif // PYTHONCODECOMPLETIONWORKER_H + +} \ No newline at end of file diff --git a/pythonlanguagesupport.cpp b/pythonlanguagesupport.cpp index e7c6911..51701f9 100644 --- a/pythonlanguagesupport.cpp +++ b/pythonlanguagesupport.cpp @@ -43,9 +43,13 @@ #include #include +#include +#include + #include "pythonparsejob.h" #include "pythonhighlighting.h" #include "duchain/pythoneditorintegrator.h" +#include "codecompletion/pythoncodecompletionmodel.h" #include #include @@ -68,6 +72,8 @@ LanguageSupport::LanguageSupport( QObject* parent, const QVariantList& /*args*/ KDEV_USE_EXTENSION_INTERFACE( KDevelop::ILanguageSupport ) m_highlighting = new Highlighting( this ); + PythonCodeCompletionModel* codeCompletion = new PythonCodeCompletionModel(this); + new KDevelop::CodeCompletion(this, codeCompletion, "Python"); } LanguageSupport::~LanguageSupport() From 0256c742e826d0ce29cd445e3930bb7bcad22f32 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 9 Oct 2010 22:11:17 +0200 Subject: [PATCH 007/118] Some more changes heading for a basic code completion support --- codecompletion/CMakeLists.txt | 4 +++- codecompletion/pythoncodecompletioncontext.cpp | 10 ++++++++-- duchain/CMakeLists.txt | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index f905c41..1a03ac5 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -3,7 +3,8 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -set(completion_SRCS +set(completion_SRCS + importfileitem.cpp pythoncodecompletioncontext.cpp pythoncodecompletionmodel.cpp pythoncodecompletionworker.cpp @@ -14,6 +15,7 @@ kde4_add_library(kdev4pythoncompletion SHARED ${completion_SRCS}) target_link_libraries(kdev4pythoncompletion ${KDE4_KDECORE_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} + kdev4pythonduchain ) install(TARGETS kdev4pythoncompletion DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index a8604fc..1b7151e 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include "navigationwidget.h" +#include "importfileitem.h" using namespace KDevelop; @@ -12,8 +15,11 @@ QList PythonCodeCompletionContext::completionItems(bo { QList items; - CompletionTreeItem* item = new CompletionTreeItem(); - items << CompletionTreeItemPointer( item ); + kDebug() << "Adding testing item to completion list"; + + IncludeItem item; + item.name = "Foo"; + items << CompletionTreeItemPointer( new ImportFileItem(item) ); return items; } diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 7461d8e..e970cd3 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -4,7 +4,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ) set(duchain_SRCS -# navigationwidget.cpp + navigationwidget.cpp contextbuilder.cpp pythoneditorintegrator.cpp declarationbuilder.cpp From 0c8c5ea872f7b05071ab226f5f9dfda23242fdfd Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 10 Oct 2010 13:42:19 +0200 Subject: [PATCH 008/118] "Abstract" code completion now works (no real features yet) --- codecompletion/pythoncodecompletioncontext.cpp | 6 ++++++ codecompletion/pythoncodecompletioncontext.h | 5 ++++- codecompletion/pythoncodecompletionworker.cpp | 4 +++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 1b7151e..a0ab6b1 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -24,4 +24,10 @@ QList PythonCodeCompletionContext::completionItems(bo return items; } +PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth): CodeCompletionContext(context, text, position, depth) +{ + +} + + } \ No newline at end of file diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index dc7f10b..fa6c8be 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -3,13 +3,16 @@ #include #include "pythoncompletionexport.h" +#include + +using namespace KDevelop; namespace Python { class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop::CodeCompletionContext { - public: + PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); }; diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp index 0c3fe5d..80ade49 100644 --- a/codecompletion/pythoncodecompletionworker.cpp +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -1,5 +1,6 @@ #include "pythoncodecompletionworker.h" #include "pythoncodecompletionmodel.h" +#include "pythoncodecompletioncontext.h" namespace Python { @@ -12,7 +13,8 @@ PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const { - return KDevelop::CodeCompletionWorker::createCompletionContext(context, contextText, followingText, position); + PythonCodeCompletionContext* completionContext = new PythonCodeCompletionContext(context, contextText, position, 0); + return completionContext; } From b8dbe8dd8b903b1555fb75ecbc1bf096b0686666 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 10 Oct 2010 14:07:16 +0200 Subject: [PATCH 009/118] Very basic code completion implementation (works!) --- .../pythoncodecompletioncontext.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index a0ab6b1..2268da4 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -1,20 +1,36 @@ #include "pythoncodecompletioncontext.h" + #include -#include #include -#include #include +#include + +#include +#include + #include "navigationwidget.h" #include "importfileitem.h" using namespace KDevelop; +typedef QPair DeclarationDepthPair; + namespace Python { QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { QList items; + QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); + + Declaration* currentDeclaration; + int count = declarations.length(); + for ( int i = 0; i < count; i++ ) { + currentDeclaration = declarations.at(i).first; + DeclarationPointer ptr(currentDeclaration); + items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(ptr) ); + } + kDebug() << "Adding testing item to completion list"; IncludeItem item; From 11ac68e15af29e31598af9b88cee8f10dcd1ecdf Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 15 Oct 2010 11:38:24 +0200 Subject: [PATCH 010/118] Builtin functions code completion; done badly, but there --- .kdev4/python.kdev4 | 35 +++++++++++++++++++ codecompletion/importfileitem.cpp | 16 +++++++++ codecompletion/importfileitem.h | 24 +++++++++++++ .../pythoncodecompletioncontext.cpp | 17 +++++++++ duchain/declarationbuilder.cpp | 6 +++- duchain/navigationwidget.cpp | 20 +++++++++++ duchain/navigationwidget.h | 20 +++++++++++ python_helpers/README | 1 + python_helpers/get_builtins.py | 5 +++ 9 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 .kdev4/python.kdev4 create mode 100644 codecompletion/importfileitem.cpp create mode 100644 codecompletion/importfileitem.h create mode 100644 duchain/navigationwidget.cpp create mode 100644 duchain/navigationwidget.h create mode 100755 python_helpers/README create mode 100755 python_helpers/get_builtins.py diff --git a/.kdev4/python.kdev4 b/.kdev4/python.kdev4 new file mode 100644 index 0000000..9051ffe --- /dev/null +++ b/.kdev4/python.kdev4 @@ -0,0 +1,35 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x0c\x00p\x00y\x00t\x00h\x00o\x00n) + +[CMake] +BuildDirs=/home/sven/projects/kde4/python/build +CMakeDir=/usr/share/cmake/Modules +Current CMake Binary=file:///usr/bin/cmake +CurrentBuildDir=file:///home/sven/projects/kde4/python/build +CurrentBuildType=Debug +CurrentInstallDir= +Extra Arguments= +ProjectRootRelative=./ + +[Launch] +Launch Configurations=Launch Configuration 0 + +[Launch][Launch Configuration 0] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=New Native Application Configuration +Type=Native Application + +[Launch][Launch Configuration 0][Data] +Arguments=-c kdevelop ~/test.py +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) +Dependency Action=Nothing +EnvironmentGroup=default +Executable=file:///bin/bash +External Terminal=konsole --noclose --workdir %workdir -e %exe +Use External Terminal=false +Working Directory= +isExecutable=true + +[Project] +VersionControlSupport=kdevgit diff --git a/codecompletion/importfileitem.cpp b/codecompletion/importfileitem.cpp new file mode 100644 index 0000000..4e17478 --- /dev/null +++ b/codecompletion/importfileitem.cpp @@ -0,0 +1,16 @@ +#include "importfileitem.h" + +namespace Python { + +ImportFileItem::~ImportFileItem() +{ + +} + +void ImportFileItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) +{ + kDebug() << "ImportFileItem executed"; +} + + +} \ No newline at end of file diff --git a/codecompletion/importfileitem.h b/codecompletion/importfileitem.h new file mode 100644 index 0000000..31b8300 --- /dev/null +++ b/codecompletion/importfileitem.h @@ -0,0 +1,24 @@ +#ifndef IMPORTFILEITEM_H +#define IMPORTFILEITEM_H + +#include +#include "navigationwidget.h" + +namespace Python { + +typedef KDevelop::AbstractIncludeFileCompletionItem IncludeFileItemBase; + +class ImportFileItem : public IncludeFileItemBase +{ + +public: + ImportFileItem(const KDevelop::IncludeItem& include) + : IncludeFileItemBase(include) {}; + virtual ~ImportFileItem(); + + virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); +}; + +#endif // IMPORTFILEITEM_H + +} \ No newline at end of file diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 2268da4..f05fe46 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -10,6 +10,7 @@ #include "navigationwidget.h" #include "importfileitem.h" +#include using namespace KDevelop; @@ -37,6 +38,22 @@ QList PythonCodeCompletionContext::completionItems(bo item.name = "Foo"; items << CompletionTreeItemPointer( new ImportFileItem(item) ); + // Regardless of the context, we can always use builtin functions. We can get them from python: + QProcess getBuiltins; + getBuiltins.start("./python_helpers/get_builtins.py"); + if ( ! getBuiltins.waitForFinished() ) { + kError() << getBuiltins.errorString(); + Q_ASSERT(false); + } + QString builtins_str = getBuiltins.readAllStandardOutput(); + QList builtins = builtins_str.split("\n"); + + for ( int i = 0; i < builtins.length(); i++ ) { + IncludeItem item; + item.name = builtins.at(i); + items << CompletionTreeItemPointer( new ImportFileItem(item) ); + } + return items; } diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 6dc16aa..baaecbd 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -117,8 +117,12 @@ void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) } if ( ! existingLocalDeclarations.length() ) { - openDeclaration( node->identifier, node); + Declaration *dec = openDeclaration( node->identifier, node); closeDeclaration(); + { + DUChainWriteLocker lock(DUChain::lock()); + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); + } } else { kDebug() << "Declaration does already exist, not updating" << node->identifier->identifier.toAscii(); diff --git a/duchain/navigationwidget.cpp b/duchain/navigationwidget.cpp new file mode 100644 index 0000000..1cb3c94 --- /dev/null +++ b/duchain/navigationwidget.cpp @@ -0,0 +1,20 @@ +#include "navigationwidget.h" +#include +#include + +NavigationWidget::NavigationWidget() +{ + +} + +NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) +{ + kDebug() << "Navigation widget requested"; +} + +NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext) +{ + +} + +#include "navigationwidget.moc" diff --git a/duchain/navigationwidget.h b/duchain/navigationwidget.h new file mode 100644 index 0000000..34c31e5 --- /dev/null +++ b/duchain/navigationwidget.h @@ -0,0 +1,20 @@ +#ifndef NAVIGATIONWIDGET_H +#define NAVIGATIONWIDGET_H + +#include +#include "pythonduchainexport.h" +#include + +class KDEVPYTHONDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavigationWidget +{ +Q_OBJECT +public: + NavigationWidget(); + NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); + NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext); + + static QString shortDescription(KDevelop::Declaration* declaration) { return "Test"; }; + static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; +}; + +#endif // NAVIGATIONWIDGET_H diff --git a/python_helpers/README b/python_helpers/README new file mode 100755 index 0000000..001111a --- /dev/null +++ b/python_helpers/README @@ -0,0 +1 @@ +Those python scripts give dynamic information for autocompletion. They always give one entry per line. diff --git a/python_helpers/get_builtins.py b/python_helpers/get_builtins.py new file mode 100755 index 0000000..23e60ca --- /dev/null +++ b/python_helpers/get_builtins.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +import __builtin__ +for item in dir(__builtin__): + print item From fcaf23d2493e60b9c2034fa385d2ff7bc2c45e70 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 15 Oct 2010 18:12:45 +0200 Subject: [PATCH 011/118] Trying to fix a bug with not --- .kdev4/python.kdev4 | 2 +- codecompletion/pythoncodecompletioncontext.cpp | 16 ---------------- parser/astbuilder.cpp | 13 ++++++++++++- python_helpers/README | 1 - 4 files changed, 13 insertions(+), 19 deletions(-) delete mode 100755 python_helpers/README diff --git a/.kdev4/python.kdev4 b/.kdev4/python.kdev4 index 9051ffe..03baba4 100644 --- a/.kdev4/python.kdev4 +++ b/.kdev4/python.kdev4 @@ -21,7 +21,7 @@ Name=New Native Application Configuration Type=Native Application [Launch][Launch Configuration 0][Data] -Arguments=-c kdevelop ~/test.py +Arguments=-c kdevelop /home/sven/projects/kde4/python/python_helpers/generate_docs.py Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) Dependency Action=Nothing EnvironmentGroup=default diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index f05fe46..ce98954 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -38,22 +38,6 @@ QList PythonCodeCompletionContext::completionItems(bo item.name = "Foo"; items << CompletionTreeItemPointer( new ImportFileItem(item) ); - // Regardless of the context, we can always use builtin functions. We can get them from python: - QProcess getBuiltins; - getBuiltins.start("./python_helpers/get_builtins.py"); - if ( ! getBuiltins.waitForFinished() ) { - kError() << getBuiltins.errorString(); - Q_ASSERT(false); - } - QString builtins_str = getBuiltins.readAllStandardOutput(); - QList builtins = builtins_str.split("\n"); - - for ( int i = 0; i < builtins.length(); i++ ) { - IncludeItem item; - item.name = builtins.at(i); - items << CompletionTreeItemPointer( new ImportFileItem(item) ); - } - return items; } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 55760ea..4578efc 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -1193,8 +1193,19 @@ void AstBuilder::visitNotTest(PythonParser::NotTestAst *node) { BooleanNotOperationAst* ast = createAst( node ); mNodeStack.push( ast ); + visitNode( node->notTest ); - ast->op = safeNodeCast( mNodeStack.pop() ); + + Ast* tmp = mNodeStack.pop(); + // maybe it's an atom, then there's nothing left to do + if ( tmp->astType != Ast::AtomAst ) { + kDebug() << "Using boolean operator"; + ast->op = safeNodeCast( tmp ); + } + else { + kDebug() << "Using NULL operator"; + ast->op = 0; + } }else { visitNode( node->comparison ); diff --git a/python_helpers/README b/python_helpers/README deleted file mode 100755 index 001111a..0000000 --- a/python_helpers/README +++ /dev/null @@ -1 +0,0 @@ -Those python scripts give dynamic information for autocompletion. They always give one entry per line. From dffde350c98d60db24d707e0327d2e58c1da8123 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 15 Oct 2010 23:16:46 +0200 Subject: [PATCH 012/118] Attempt to use the python parser instead of kdev-pg-qt --- pythonpythonparser.py | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 pythonpythonparser.py diff --git a/pythonpythonparser.py b/pythonpythonparser.py new file mode 100644 index 0000000..a805fa7 --- /dev/null +++ b/pythonpythonparser.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python2.6 + +import ast +from xml.dom.minidom import Document +import types + +class NodeContainer(): + identifier = 0 + node = None + + def __init__(self, node): + self.node = node + +class KDevelopNodeVisitor(ast.NodeVisitor): + xmlrepr = Document() + basenode = None + currentnode = None + nodecnt = 0 + searching = [] + + def __init__(self, *arg, **args): + super(KDevelopNodeVisitor, self).__init__(*arg, **args) + self.basenode = self.xmlrepr.createElement("pythonast") + self.xmlrepr.appendChild(self.basenode) + self.currentnode = self.basenode + + def generic_visit(self, node): + self.nodecnt += 1 + + node_xmlrepr = self.xmlrepr.createElement(node.__class__.__name__ + "Node") + node_xmlrepr.setAttribute('nodecnt', str(self.nodecnt)) + self.currentnode.appendChild(node_xmlrepr) + + save_currentnode = self.currentnode + self.currentnode = node_xmlrepr + + fields = list(node._attributes) + fields.extend(list(node._fields)) + + searching_locally = [] + for field in fields: + value = getattr(node, field) + if type(value) not in [types.IntType, types.StringType]: + search = NodeContainer(value) + self.searching.append(search) + continue + node_xmlrepr.setAttribute(field.lower(), str(value)) + + super(KDevelopNodeVisitor, self).generic_visit(node) + + for field in fields: + value = getattr(node, field) + + self.currentnode = save_currentnode + +f = open('/home/sven/test.py').read() +v = KDevelopNodeVisitor() +v.visit(ast.parse(f)) +print v.xmlrepr.toprettyxml(indent = " ") From 86761cb7e586394503b07b65bfbf2c623674a45f Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 16 Oct 2010 00:28:47 +0200 Subject: [PATCH 013/118] =?UTF-8?q?pythonpythonparser.py=20now=20generates?= =?UTF-8?q?=20awesome=E2=84=A2=20XML=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pythonpythonparser.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index a805fa7..448cc3e 100644 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -16,7 +16,7 @@ class KDevelopNodeVisitor(ast.NodeVisitor): basenode = None currentnode = None nodecnt = 0 - searching = [] + childNodeMap = {} def __init__(self, *arg, **args): super(KDevelopNodeVisitor, self).__init__(*arg, **args) @@ -27,7 +27,9 @@ def __init__(self, *arg, **args): def generic_visit(self, node): self.nodecnt += 1 - node_xmlrepr = self.xmlrepr.createElement(node.__class__.__name__ + "Node") + self.childNodeMap[self.nodecnt] = node + + node_xmlrepr = self.xmlrepr.createElement(node.__class__.__name__ + "Ast") node_xmlrepr.setAttribute('nodecnt', str(self.nodecnt)) self.currentnode.appendChild(node_xmlrepr) @@ -40,17 +42,30 @@ def generic_visit(self, node): searching_locally = [] for field in fields: value = getattr(node, field) - if type(value) not in [types.IntType, types.StringType]: - search = NodeContainer(value) - self.searching.append(search) + if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: continue node_xmlrepr.setAttribute(field.lower(), str(value)) super(KDevelopNodeVisitor, self).generic_visit(node) + key = '**WARNING::Undefined key' for field in fields: + multiple_keys = [] value = getattr(node, field) - + if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: + if type(value) == types.ListType: + for currentValue in value: + for currentKey, currentItem in self.childNodeMap.iteritems(): + if currentItem == currentValue: + multiple_keys.append(str(currentKey)) + key = ','.join(multiple_keys) + else: + for currentKey, currentItem in self.childNodeMap.iteritems(): + if currentItem == value: + key = currentKey + node_xmlrepr.setAttribute(field.lower(), str(key)) + + self.currentnode = save_currentnode f = open('/home/sven/test.py').read() From 7ba2a0fe6e1917dff51a699495e5c7522bf0a95b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 16 Oct 2010 10:45:27 +0200 Subject: [PATCH 014/118] python parser now two times faster --- pythonpythonparser.py | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 448cc3e..27b7967 100644 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -3,13 +3,7 @@ import ast from xml.dom.minidom import Document import types - -class NodeContainer(): - identifier = 0 - node = None - - def __init__(self, node): - self.node = node +import sys class KDevelopNodeVisitor(ast.NodeVisitor): xmlrepr = Document() @@ -27,7 +21,8 @@ def __init__(self, *arg, **args): def generic_visit(self, node): self.nodecnt += 1 - self.childNodeMap[self.nodecnt] = node + #self.childNodeMap[self.nodecnt] = node + self.childNodeMap[node] = self.nodecnt node_xmlrepr = self.xmlrepr.createElement(node.__class__.__name__ + "Ast") node_xmlrepr.setAttribute('nodecnt', str(self.nodecnt)) @@ -48,27 +43,29 @@ def generic_visit(self, node): super(KDevelopNodeVisitor, self).generic_visit(node) - key = '**WARNING::Undefined key' + key = 'None' for field in fields: multiple_keys = [] value = getattr(node, field) if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: if type(value) == types.ListType: for currentValue in value: - for currentKey, currentItem in self.childNodeMap.iteritems(): - if currentItem == currentValue: - multiple_keys.append(str(currentKey)) + try: + multiple_keys.append(str(self.childNodeMap[currentValue])) + except KeyError: + multiple_keys.append('None') key = ','.join(multiple_keys) else: - for currentKey, currentItem in self.childNodeMap.iteritems(): - if currentItem == value: - key = currentKey + try: + key = self.childNodeMap[value] + except KeyError: + key = 'None' node_xmlrepr.setAttribute(field.lower(), str(key)) self.currentnode = save_currentnode -f = open('/home/sven/test.py').read() +f = open('/usr/lib/entropy/libraries/entropy/cache.py').read() v = KDevelopNodeVisitor() v.visit(ast.parse(f)) -print v.xmlrepr.toprettyxml(indent = " ") +print v.xmlrepr.toprettyxml(indent = " ") From 6a027131cb924e7f0378c556cd67d76b68472c26 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 16 Oct 2010 11:51:11 +0200 Subject: [PATCH 015/118] Trying to integrate the python parser --- parser/astbuilder.cpp | 1861 +-------------------------------------- parser/astbuilder.h | 110 +-- parser/parsesession.cpp | 8 +- pythonpythonparser.py | 2 +- 4 files changed, 31 insertions(+), 1950 deletions(-) mode change 100644 => 100755 pythonpythonparser.py diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 4578efc..6e0ce50 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -24,1859 +24,36 @@ #include "pythonparser.h" #include "ast.h" -#include #include +#include +#include namespace Python { - -//TODO: Check that created AST nodes are pushed onto the stack _before_ visiting subnodes to make sure their parent is correct - -template static T* safeNodeCast( Ast* node ) -{ - T* ast = dynamic_cast(node); - Q_ASSERT(ast || !node); - return ast; -} - -static QList targetAstListFromExpressionAstList( const QList& list ) -{ - QList l; - foreach( ExpressionAst* ast, list ) - { - switch( ast->astType ) - { - case Ast::IdentifierAst: - { - IdentifierTargetAst* target = new IdentifierTargetAst( ast->parent ); - target->identifier = safeNodeCast( ast ); - target->start = ast->start; - target->end = ast->end; - target->startCol = ast->startCol; - target->startLine = ast->startLine; - target->endCol = ast->endCol; - target->endLine = ast->endLine; - l << target; - break; - } - case Ast::SubscriptAst: - { - SubscriptTargetAst* target = new SubscriptTargetAst( ast->parent ); - target->subscript = safeNodeCast( ast ); - target->start = ast->start; - target->end = ast->end; - target->startCol = ast->startCol; - target->startLine = ast->startLine; - target->endCol = ast->endCol; - target->endLine = ast->endLine; - l << target; - break; - } - case Ast::AttributeReferenceAst: - { - AttributeReferenceTargetAst* target = new AttributeReferenceTargetAst( ast->parent ); - target->attribute = safeNodeCast( ast ); - target->start = ast->start; - target->end = ast->end; - target->startCol = ast->startCol; - target->startLine = ast->startLine; - target->endCol = ast->endCol; - target->endLine = ast->endLine; - l << target; - break; - } - case Ast::ExtendedSliceAst: - //fall through - case Ast::SimpleSliceAst: - { - SliceTargetAst* target = new SliceTargetAst( ast->parent ); - target->slice = safeNodeCast( ast ); - target->start = ast->start; - target->end = ast->end; - target->startCol = ast->startCol; - target->startLine = ast->startLine; - target->endCol = ast->endCol; - target->endLine = ast->endLine; - l << target; - break; - } - case Ast::AtomAst: - { - AtomAst* atom = dynamic_cast( ast ); - IdentifierTargetAst* target = new IdentifierTargetAst( ast->parent ); - target->identifier = atom->identifier; - target->start = atom->start; - target->end = atom->end; - target->startCol = atom->startCol; - target->endCol = atom->endCol; - target->startLine = atom->startLine; - target->endLine = atom->endLine; - l << target; - delete atom; - break; - } - default: - kDebug() << ast->astType; - Q_ASSERT_X( false, "create_targetlist", "Ooops, found an expression that we can't convert to a target ast, check the code! " ); - } - } - return l; -} - -template static QList generateSpecializedList( const QList& list ) -{ - QList l; - foreach( Ast* ast, list ) - { - T* temp = safeNodeCast( ast ); - l << temp; - } - return l; -} - -IdentifierAst* AstBuilder::createIdentifier( Ast* parent, qint64 idx ) -{ - IdentifierAst* ast = new IdentifierAst( parent ); - ast->start = parser->tokenStream->token( idx ).begin; - ast->end = parser->tokenStream->token( idx ).end; - parser->tokenStream->startPosition( idx, &ast->startLine, &ast->startCol ); - parser->tokenStream->endPosition( idx, &ast->endLine, &ast->endCol ); - ast->identifier = tokenText( idx ); - return ast; -} - -QList AstBuilder::identifierListFromTokenList( Ast* parent, const KDevPG::ListNode* sequence ) -{ - QList identifiers; - for( int i = 0; i < sequence->count(); i++ ) - { - identifiers << createIdentifier( parent, sequence->at(i)->element ); - } - return identifiers; -} - -void AstBuilder::setStartEnd( Ast* ast, PythonParser::AstNode* node ) -{ - ast->start = parser->tokenStream->token( node->startToken ).begin; - ast->end = parser->tokenStream->token( node->endToken ).end; - parser->tokenStream->startPosition( node->startToken, &ast->startLine, &ast->startCol ); - parser->tokenStream->endPosition( node->endToken, &ast->endLine, &ast->endCol ); -} - -QString AstBuilder::tokenText( qint64 tokenidx ) -{ - // -1 means this is not a valid token idx and thus return an empty string; - if( tokenidx == -1 ) - return ""; - KDevPG::TokenStream::Token token = parser->tokenStream->token( tokenidx ); - return parser->tokenText( token.begin, token.end ); -} - -AstBuilder::AstBuilder(PythonParser::Parser* p) - : parser(p) -{ -} - -void AstBuilder::visitAndExpr(PythonParser::AndExprAst *node) -{ - kDebug() << "visitAndExpr start"; - visitNode( node->andExpr ); - if( node->anddShifExprSequence && node->anddShifExprSequence->count() > 0 ) - { - BinaryExpressionAst* ast = createAst( node ); - ast->opType = ArithmeticExpressionAst::BinaryAnd; - ast->lhs = safeNodeCast( mNodeStack.pop() ); - int count = node->anddShifExprSequence->count(); - BinaryExpressionAst* curast = ast; - for( int i = 0; i < count; i++ ) - { - visitNode( node->anddShifExprSequence->at(i)->element ); - if( i+1 < count ) - { - BinaryExpressionAst* tmp = createAst( - node->anddShifExprSequence->at(i)->element ); - curast->opType = ArithmeticExpressionAst::BinaryAnd; - tmp->lhs = safeNodeCast( mNodeStack.pop() ); - curast->rhs = tmp; - curast = tmp; - }else - { - curast->rhs = safeNodeCast( mNodeStack.pop() ); - } - } - mNodeStack.push( ast ); - } - kDebug() << "visitAndExpr end"; -} - -void AstBuilder::visitAndTest(PythonParser::AndTestAst *node) -{ - kDebug() << "visitAndTest start"; - visitNode( node->notTestSequence->at(0)->element ); - if( node->notTestSequence->count() > 1 ) - { - BooleanAndOperationAst* ast = createAst( node ); - ast->lhs = safeNodeCast( mNodeStack.pop() ); - int count = node->notTestSequence->count(); - BooleanAndOperationAst* curast = ast; - for( int i = 1; i < count; i++ ) - { - visitNode( node->notTestSequence->at(i)->element ); - if( i+1 < count ) - { - BooleanAndOperationAst* tmp = createAst( - node->notTestSequence->at(i)->element ); - tmp->lhs = safeNodeCast( mNodeStack.pop() ); - curast->rhs = tmp; - curast = tmp; - }else - { - curast->rhs = safeNodeCast( mNodeStack.pop() ); - } - } - mNodeStack.push( ast ); - } - kDebug() << "visitAndTest end"; -} - -void AstBuilder::visitArglist(PythonParser::ArglistAst *node) -{ - kDebug() << "visitArglist start"; - QList args; - visitNode( node->argListBegin ); - if( dynamic_cast( mNodeStack.top() ) ) - { - args << mNodeStack.pop(); - mListStack.push( args ); - // Early return because a Generator expression was found, thats the only - // thing in this "argumentlist" then - return; - } - if( node->argListBegin ) - { - args += mListStack.pop(); - } - if( node->arglistStar ) - { - ArgumentAst* ast = createAst( node->arglistStar ); - ast->argumentType = ArgumentAst::ListArgument; - visitNode( node->arglistStar ); - ast->argumentExpression = safeNodeCast( mNodeStack.pop() ); - args << ast; - } - if( node->arglistDoublestar ) - { - ArgumentAst* ast = createAst( node->arglistDoublestar ); - ast->argumentType = ArgumentAst::DictArgument; - visitNode( node->arglistDoublestar ); - ast->argumentExpression = safeNodeCast( mNodeStack.pop() ); - args << ast; - } - mListStack.push( args ); - kDebug() << "visitArglist end"; -} - -void AstBuilder::visitArgument(PythonParser::ArgumentAst *node) -{ - kDebug() << "visitArgument start"; - visitNode( node->argumentTest ); - if( node->argumentEqualTest ) - { - ArgumentAst* ast = createAst( node ); - ast->argumentType = ArgumentAst::KeywordArgument; - AtomAst *argumentName = safeNodeCast( mNodeStack.pop() ); - ast->keywordName = safeNodeCast( argumentName->identifier ); - visitNode( node->argumentEqualTest ); - ast->argumentExpression = safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( ast ); - }else if( node->genFor ) - { - GeneratorAst* ast = createAst( node ); - ast->generatedValue = safeNodeCast( mNodeStack.pop() ); - visitNode( node->genFor ); - ast->generator = safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( ast ); - }else - { - ArgumentAst* ast = createAst( node ); - ast->argumentType = ArgumentAst::PositionalArgument; - ast->argumentExpression = safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( ast ); - } - kDebug() << "visitArgument end"; -} - -void AstBuilder::visitArithExpr(PythonParser::ArithExprAst *node) -{ - kDebug() << "visitArithExpr start"; - visitNode( node->arithTerm ); - if( node->arithOpListSequence && node->arithOpListSequence->count() > 0 && node->arithTermListSequence->count() > 0 ) - { - Q_ASSERT_X( node->arithOpListSequence->count() == node->arithTermListSequence->count(), - "visitArithExpr", "different number of operators and operands" ); - BinaryExpressionAst* ast = createAst( node ); - Ast *dbg_node = mNodeStack.pop(); - ast->lhs = safeNodeCast( dbg_node ); - BinaryExpressionAst* cur = ast; - int count = node->arithOpListSequence->count(); - for( int i = 0; i < count; i++ ) - { - switch( node->arithOpListSequence->at(i)->element->arithOp ) - { - case PythonParser::PlusOp: - cur->opType = BinaryExpressionAst::BinaryPlus; - break; - case PythonParser::MinusOp: - cur->opType = BinaryExpressionAst::BinaryMinus; - break; - default: - //Should never reach here, unless somebody changed the grammer and not the builder - Q_ASSERT(false); - } - visitNode( node->arithTermListSequence->at(i)->element ); - if( i+1 < count ) - { - BinaryExpressionAst* tmp = createAst( node->arithTermListSequence->at(i)->element ); - cur->rhs = tmp; - cur = tmp; - cur->lhs = safeNodeCast( mNodeStack.pop() ); - }else - { - cur->rhs = safeNodeCast( mNodeStack.pop() ); - } - } - mNodeStack.push( ast ); - } - kDebug() << "visitArithExpr end"; -} - -void AstBuilder::visitAssertStmt(PythonParser::AssertStmtAst *node) -{ - kDebug() << "visitAssertStmt start"; - AssertAst* ast = createAst( node ); - visitNode( node->assertNotTest ); - ast->assertTest = safeNodeCast(mNodeStack.pop()); - if( node->assertRaiseTest ) - { - visitNode( node->assertRaiseTest ); - ast->exceptionValue = safeNodeCast(mNodeStack.pop()); - } - mNodeStack.push(ast); - kDebug() << "visitAssertStmt end"; -} - -void AstBuilder::visitAtom(PythonParser::AtomAst *node) -{ - kDebug() << "visitAtom start"; - AtomAst* ast = createAst( node ); - if( node->atomIdentifierName >= 0 || node->number || (node->stringliteralSequence && node->stringliteralSequence->count() > 0) ) - { - if( node->atomIdentifierName >= 0 ) - { - IdentifierAst* id = createIdentifier( ast, node->atomIdentifierName ); - ast->identifier = id; - }else if( node->number ) - { - visitNode( node->number ); - ast->literal = safeNodeCast( mNodeStack.pop() ); - }else if ( node->stringliteralSequence ) - { - LiteralAst* lit = createAst( node ); - lit->parent = ast; - lit->literalType = LiteralAst::String; - for( int i = 0; i < node->stringliteralSequence->count(); i++ ) - { - lit->value += tokenText( node->stringliteralSequence->at(i)->element ); - } - ast->literal = lit; - } - }else if( node->listmaker ) - { - EnclosureAst* enc = createAst( node->listmaker ); - enc->parent = ast; - visitNode( node->listmaker ); - enc->encType = EnclosureAst::List; - enc->list = safeNodeCast( mNodeStack.pop() ); - ast->enclosure = enc; - }else if( node->codeexpr ) - { - EnclosureAst* enc = createAst( node->codeexpr ); - visitNode( node->codeexpr ); - enc->parent = ast; - enc->encType = EnclosureAst::StringConversion; - enc->stringConversion = generateSpecializedList( mListStack.pop() ); - ast->enclosure = enc; - }else if( node->dictmaker ) - { - EnclosureAst* enc = createAst( node->dictmaker ); - enc->parent = ast; - visitNode( node->dictmaker ); - enc->encType = EnclosureAst::Dictionary; - enc->dict = safeNodeCast( mNodeStack.pop() ); - ast->enclosure = enc; - }else if( node->yield ) - { - visitNode( node->yield ); - EnclosureAst* enc = createAst( node->yield ); - enc->parent = ast; - enc->encType = EnclosureAst::Yield; - enc->yield = safeNodeCast( mNodeStack.pop() ); - ast->enclosure = enc; - }else - { - EnclosureAst* enc; - visitNode( node->testlist ); - if( node->genFor ) - { - enc = createAst( node ); - enc->encType = EnclosureAst::Generator; - QList l = generateSpecializedList( mListStack.pop() ); - GeneratorAst* gen = createAst( node ); - gen->generatedValue = l.first(); - visitNode( node->genFor ); - gen->generator = safeNodeCast( mNodeStack.pop() ); - enc->generator = gen; - enc->parent = ast; - ast->enclosure = enc; - }else - { - enc = createAst( node ); - enc->encType = EnclosureAst::ParenthesizedForm; - enc->parent = ast; - QList dbg_node = mListStack.top(); - enc->parenthesizedform = generateSpecializedList( mListStack.pop() ); - ast->enclosure = enc; - } - } - mNodeStack.push( ast ); - kDebug() << "visitAtom end"; -} - -void AstBuilder::visitBreakStmt(PythonParser::BreakStmtAst *node) -{ - kDebug() << "visitBreakStmt start"; - StatementAst* ast = createAst( node, Ast::BreakAst ); - mNodeStack.push( ast ); - kDebug() << "visitBreakStmt end"; -} - -void AstBuilder::visitClassdef(PythonParser::ClassdefAst *node) -{ - kDebug() << "visitClassdef start"; - ClassDefinitionAst* ast = createAst( node ); - ast->className = createIdentifier( ast, node->className ); - if( node->testlist ) - { - visitNode( node->testlist ); - ast->inheritance = generateSpecializedList( mListStack.pop() ); - } - visitNode( node->classSuite ); - ast->classBody = generateSpecializedList( mListStack.pop() ); - mNodeStack.push(ast); - kDebug() << "visitClassdef end"; -} - -void AstBuilder::visitComparison(PythonParser::ComparisonAst *node) -{ - kDebug() << "visitComparison start"; - visitNode( node->compExpr ); - if( node->compOpSequence && node->compOpSequence->count() > 0 && node->compOpExprSequence->count() > 0 ) - { - ComparisonAst* ast = createAst( node ); - ast->firstComparator = safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( ast ); - Q_ASSERT( node->compOpSequence->count() == node->compOpExprSequence->count() ); - int count = node->compOpSequence->count(); - for( int i = 0; i < count; i++ ) - { - QPair pair; - switch( node->compOpSequence->at(i)->element->compOp ) - { - case PythonParser::LessOp: - pair.first = ComparisonAst::LessThanOp; - break; - case PythonParser::GreaterOp: - pair.first = ComparisonAst::GreaterThanOp; - break; - case PythonParser::IsEqualOp: - pair.first = ComparisonAst::EqualOp; - break; - case PythonParser::GreaterEqOp: - pair.first = ComparisonAst::GreaterEqualOp; - break; - case PythonParser::LessEqOp: - pair.first = ComparisonAst::LessEqualOp; - break; - case PythonParser::UnEqualOp: - pair.first = ComparisonAst::UnequalOp; - break; - case PythonParser::InOp: - pair.first = ComparisonAst::InOp; - break; - case PythonParser::NotInOp: - pair.first = ComparisonAst::NotInOp; - break; - case PythonParser::IsNotOp: - pair.first = ComparisonAst::IsNotOp; - break; - case PythonParser::IsOp: - pair.first = ComparisonAst::IsOp; - break; - default: - //Should never reach here, unless somebody changed the grammer and not the builder - Q_ASSERT(false); - } - visitNode( node->compOpExprSequence->at(i)->element ); - pair.second = safeNodeCast( mNodeStack.pop() ); - ast->comparatorList << pair; - } - } - kDebug() << "visitComparison end"; -} - -void AstBuilder::visitCompoundStmt(PythonParser::CompoundStmtAst *node) -{ - kDebug() << "visitCompoundStmt start"; - PythonParser::DefaultVisitor::visitCompoundStmt( node ); - kDebug() << "visitCompoundStmt end"; -} - -void AstBuilder::visitContinueStmt(PythonParser::ContinueStmtAst *node) -{ - kDebug() << "visitContinueStmt start"; - StatementAst* ast = createAst( node, Ast::ContinueAst ); - mNodeStack.push( ast ); - kDebug() << "visitContinueStmt end"; -} - -void AstBuilder::visitDottedName(PythonParser::DottedNameAst *node) { - // no idea why this is meant to be a list, - // i've never seen something like "qualified decorators" in python... TODO check this - IdentifierAst *ast = createAst( node ); - QList l; - l << ast; - mListStack.push(l); -} - -void AstBuilder::visitDecorator(PythonParser::DecoratorAst *node) -{ - kDebug() << "visitDecorator start"; - DecoratorAst* ast = createAst( node ); - visitNode( node->decoratorName ); - ast->dottedName = generateSpecializedList( mListStack.pop() ); - if( node->arguments ) - { - visitNode( node->arguments ); - ast->arguments = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitDecorator end"; -} - -void AstBuilder::visitDecorators(PythonParser::DecoratorsAst *node) -{ - kDebug() << "visitDecorators start"; - QList l; - int count = node->decoratorSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->decoratorSequence->at(i)->element ); - l << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( l ); - kDebug() << "visitDecorators end"; -} - -void AstBuilder::visitDefparam(PythonParser::DefparamAst *node) -{ - - kDebug() << "visitDefparam start"; - if( node->paramname != -1 ) - { - IdentifierParameterPartAst* ast = createAst( node ); - ast->name = createIdentifier( ast, node->paramname ); - mNodeStack.push( ast ); - }else - { - ListParameterPartAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->fplist ); - ast->parameternames = generateSpecializedList( mListStack.pop() ); - } - kDebug() << "visitDefparam start"; -} - -void AstBuilder::visitDelStmt(PythonParser::DelStmtAst *node) -{ - kDebug() << "visitDelStmt start"; - DelAst* ast = createAst( node ); - visitNode( node->delList ); - ast->deleteObjects = generateSpecializedList( mListStack.pop() ); - mNodeStack.push( ast ); - kDebug() << "visitDelStmt end"; -} - -void AstBuilder::visitDictmaker(PythonParser::DictmakerAst *node) -{ - kDebug() << "visitDictmaker start"; - DictionaryAst* ast = createAst( node ); - mNodeStack.push(ast); - int count = node->keyListSequence ? node->keyListSequence->count() : 0; - Q_ASSERT( count == (node->valueListSequence ? node->valueListSequence->count() : 0) ); - for( int i = 0; i < count; i++ ) - { - visitNode( node->keyListSequence->at(i)->element ); - ExpressionAst* key = safeNodeCast( mNodeStack.pop() ); - visitNode( node->valueListSequence->at(i)->element ); - ast->dictionary.insert( key, safeNodeCast( mNodeStack.pop() ) ); - } - - kDebug() << "visitDictmaker end"; -} - -void AstBuilder::visitExceptClause(PythonParser::ExceptClauseAst *node) -{ - kDebug() << "visitExceptClause start"; - ExceptAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->exceptTest ); - ast->exceptionDeclaration = safeNodeCast( mNodeStack.pop() ); - visitNode( node->exceptTargetTest ); - ast->exceptionValue = safeNodeCast( mNodeStack.pop() ); - kDebug() << "visitExceptClause end"; -} - -void AstBuilder::visitExecStmt(PythonParser::ExecStmtAst *node) -{ - kDebug() << "visitExecStmt start"; - ExecAst* ast = createAst( node ); - visitNode( node->execCode ); - ast->executable = safeNodeCast( mNodeStack.pop() ); - if( node->globalDictExec ) - { - visitNode( node->globalDictExec ); - ast->globalsAndLocals = safeNodeCast( mNodeStack.pop() ); - } - if( node->localDictExec ) - { - visitNode( node->localDictExec ); - ast->localsOnly = safeNodeCast( mNodeStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitExecStmt end"; -} - -void AstBuilder::visitExpr(PythonParser::ExprAst *node) -{ - kDebug() << "visitExpr start"; - visitNode( node->expr ); - if( node->orrExprSequence && node->orrExprSequence->count() > 0 ) - { - BinaryExpressionAst* ast = createAst( node ); - ast->opType = ArithmeticExpressionAst::BinaryOr; - ast->lhs = safeNodeCast( mNodeStack.pop() ); - int count = node->orrExprSequence->count(); - BinaryExpressionAst* curast = ast; - for( int i = 0; i < count; i++ ) - { - visitNode( node->orrExprSequence->at(i)->element ); - if( i+1 < count ) - { - BinaryExpressionAst* tmp = createAst( - node->orrExprSequence->at(i)->element ); - curast->opType = ArithmeticExpressionAst::BinaryOr; - tmp->lhs = safeNodeCast( mNodeStack.pop() ); - curast->rhs = tmp; - curast = tmp; - }else - { - curast->rhs = safeNodeCast( mNodeStack.pop() ); - } - } - mNodeStack.push( ast ); - } - kDebug() << "visitExpr end"; -} - -void AstBuilder::visitExprStmt(PythonParser::ExprStmtAst *node) -{ - kDebug() << "visitExprStmt start"; - visitNode( node->testlist ); - if( node->augassign ) - { - // Augmented assignments cannot have multiple targets, so the testlist needs to contain only 1 element - Q_ASSERT( mListStack.top().count() == 1 ); - AssignmentAst* a = createAst( node ); - QList l = targetAstListFromExpressionAstList( - generateSpecializedList( mListStack.pop() ) ); - AssignmentAst::OpType op; - switch( node->augassign->assignOp ) - { - case PythonParser::PlusEqOp: - op = AssignmentAst::AddEqualOp; - break; - case PythonParser::MinusEqOp: - op = AssignmentAst::SubEqualOp; - break; - case PythonParser::StarEqOp: - op = AssignmentAst::MultiplyEqualOp; - break; - case PythonParser::SlashEqOp: - op = AssignmentAst::DivideEqualOp; - break; - case PythonParser::ModuloEqOp: - op = AssignmentAst::ModuloEqualOp; - break; - case PythonParser::AndEqOp: - op = AssignmentAst::AndEqualOp; - break; - case PythonParser::OrEqOp: - op = AssignmentAst::OrEqualOp; - break; - case PythonParser::HatEqOp: - op = AssignmentAst::XorEqualOp; - break; - case PythonParser::LeftShiftEqOp: - op = AssignmentAst::LeftShiftEqualOp; - break; - case PythonParser::RightShiftEqOp: - op = AssignmentAst::RightShiftEqualOp; - break; - case PythonParser::DoublestarEqOp: - op = AssignmentAst::PowEqualOp; - break; - case PythonParser::DoubleslashEqOp: - op = AssignmentAst::FloorEqualOp; - break; - default: - //Should never reach here, unless somebody changed the grammer and not the builder - Q_ASSERT(false); - } - a->targets.append( qMakePair( l, op ) ); - if( node->yield ) - { - visitNode( node->yield ); - a->yieldValue = safeNodeCast( mNodeStack.pop() ); - }else - { - visitNode( node->anugassignTestlist ); - a->value = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( a ); - }else if( node->yield || ( node->equalTestlistSequence && node->equalTestlistSequence->count() ) > 0 ) - { - AssignmentAst* a = createAst( node ); - QList l = targetAstListFromExpressionAstList( - generateSpecializedList( mListStack.pop() ) ); - a->targets.append( qMakePair( l, AssignmentAst::AssignmentOp) ); - - int count = node->equalTestlistSequence->count(); - if( count > 0 ) - { - for( int i = 0; i < count; i++ ) - { - if( !node->yield && i == count-1 ) - { - // We have no yield statement, so the last element in the - // list is the actual expression for the assignment - break; - } - visitNode( node->equalTestlistSequence->at(i)->element ); - l = targetAstListFromExpressionAstList( - generateSpecializedList( mListStack.pop() ) ); - a->targets.append( qMakePair( l, AssignmentAst::AssignmentOp ) ); - } - } - if( node->yield ) - { - visitNode( node->yield ); - a->yieldValue = safeNodeCast( mNodeStack.pop() ); - }else - { - visitNode( node->equalTestlistSequence->at( count-1 )->element ); - a->value = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( a ); - }else - { - ExpressionStatementAst *ast = createAst( node ); - ast->expressions = generateSpecializedList( mListStack.pop() ); - mNodeStack.push( ast ); - } - kDebug() << "visitExprStmt end"; -} - -void AstBuilder::visitExprlist(PythonParser::ExprlistAst *node) -{ - kDebug() << "visitExprlist start"; - QList l; - int count = node->exprSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->exprSequence->at(i)->element ); - l << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( l ); - kDebug() << "visitExprlist end"; -} - -void AstBuilder::visitFactor(PythonParser::FactorAst *node) -{ - kDebug() << "visitFactor start"; - if( node->power ) - { - visitNode( node->power ); - }else - { - UnaryExpressionAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->factor ); - switch( node->factOp->op ) - { - case PythonParser::UnaryPlusOp: - ast->opType = ArithmeticExpressionAst::UnaryPlus; - break; - case PythonParser::UnaryTildeOp: - ast->opType = ArithmeticExpressionAst::UnaryTilde; - break; - case PythonParser::UnaryMinusOp: - ast->opType = ArithmeticExpressionAst::UnaryMinus; - break; - default: - //Shouldn't reach this, unless someone changes the grammar and didn't update here - Q_ASSERT(false); - } - ast->operand = safeNodeCast( mNodeStack.pop() ); - } - kDebug() << "visitFactor end"; -} - -void AstBuilder::visitFlowStmt(PythonParser::FlowStmtAst *node) -{ - kDebug() << "visitFlowStmt start"; - PythonParser::DefaultVisitor::visitFlowStmt( node ); - kDebug() << "visitFlowStmt end"; -} - -void AstBuilder::visitForStmt(PythonParser::ForStmtAst *node) -{ - kDebug() << "visitForStmt start"; - ForAst* ast = createAst( node ); - visitNode( node->forExpr ); - ast->assignedTargets = targetAstListFromExpressionAstList( generateSpecializedList( mListStack.pop() ) ); - visitNode( node->forTestlist ); - ast->iterable = generateSpecializedList( mListStack.pop() ); - visitNode( node->forSuite ); - ast->forBody = generateSpecializedList( mListStack.pop() ); - if( node->forElseSuite ) - { - visitNode( node->forElseSuite ); - ast->elseBody = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitForStmt end"; -} - -void AstBuilder::visitFpDef(PythonParser::FpDefAst *node) -{ - kDebug() << "visitFpDef start"; - DefaultParameterAst* ast = createAst( node ); - - mNodeStack.push( ast ); - visitNode( node->defparam ); - ast->name = safeNodeCast( mNodeStack.pop() ); - if( node->fpDefTest ) - { - visitNode( node->fpDefTest ); - ast->value = safeNodeCast( mNodeStack.pop() ); - } - kDebug() << "visitFpDef end"; -} - -void AstBuilder::visitFplist(PythonParser::FplistAst *node) -{ - kDebug() << "visitFplist start"; - int count = node->fplistFpdefSequence->count(); - QList l; - for( int i = 0; i < count; i++ ) - { - visitNode( node->fplistFpdefSequence->at(i)->element ); - l << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( l ); - kDebug() << "visitFplist end"; -} - -void AstBuilder::visitFuncdecl(PythonParser::FuncdeclAst *node) -{ - kDebug() << "visitFuncdecl start"; - FunctionDefinitionAst* ast = createAst( node ); - if( node->decorators ) - { - visitNode( node->decorators ); - ast->decorators = generateSpecializedList( mListStack.pop() ); - } - ast->functionName = createIdentifier( ast, node->funcName ); - if( node->funArgs ) - { - visitNode( node->funArgs ); - ast->parameters = generateSpecializedList( mListStack.pop() ); - } - visitNode( node->funSuite ); - ast->functionBody = generateSpecializedList( mListStack.pop() ); - mNodeStack.push( ast ); - kDebug() << "visitFuncdecl end"; -} - -void AstBuilder::visitFuncDef(PythonParser::FuncDefAst *node) -{ - kDebug() << "visitFuncDef start"; - QList l; - int count = node->fpDefSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->fpDefSequence->at(i)->element ); - l << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( l ); - kDebug() << "visitFuncDef end"; -} - -void AstBuilder::visitGenFor(PythonParser::GenForAst *node) -{ - kDebug() << "visitGenFor start"; - GeneratorForAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->exprlist ); - ast->assignedTargets = generateSpecializedList( mListStack.pop() ); - visitNode( node->test ); - ast->iterableObject = safeNodeCast( mNodeStack.pop() ); - if( node->genIter ) - { - visitNode( node->genIter ); - if( node->genIter->genFor ) - { - ast->nextGenerator = safeNodeCast( mNodeStack.pop() ); - }else - { - ast->nextCondition = safeNodeCast( mNodeStack.pop() ); - } - } - kDebug() << "visitGenFor end"; -} - -void AstBuilder::visitGenIf(PythonParser::GenIfAst *node) -{ - kDebug() << "visitGenIf start"; - GeneratorIfAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->test ); - ast->condition = safeNodeCast( mNodeStack.pop() ); - if( node->genIter ) - { - visitNode( node->genIter ); - if( node->genIter->genFor ) - { - ast->nextGenerator = safeNodeCast( mNodeStack.pop() ); - }else - { - ast->nextCondition = safeNodeCast( mNodeStack.pop() ); - } - } - kDebug() << "visitGenIf end"; -} - -void AstBuilder::visitGenIter(PythonParser::GenIterAst *node) -{ - kDebug() << "visitGenIter start"; - PythonParser::DefaultVisitor::visitGenIter(node); - kDebug() << "visitGenIter end"; -} - -void AstBuilder::visitGlobalStmt(PythonParser::GlobalStmtAst *node) -{ - kDebug() << "visitGlobalStmt start"; - GlobalAst* ast = createAst( node ); - ast->identifiers = identifierListFromTokenList( ast, node->globalNameSequence ); - mNodeStack.push( ast ); - kDebug() << "visitGlobalStmt end"; -} - -void AstBuilder::visitIfStmt(PythonParser::IfStmtAst *node) -{ - kDebug() << "visitIfStmt start"; - IfAst* ast = createAst( node ); - visitNode( node->ifTest ); - ast->ifCondition = safeNodeCast( mNodeStack.pop() ); - visitNode( node->ifSuite ); - ast->ifBody = generateSpecializedList( mListStack.pop() ); - if (node->elifTestSequence && node->elifSuiteSequence) { - Q_ASSERT( node->elifTestSequence->count() == node->elifSuiteSequence->count() ); - int count = node->elifTestSequence->count(); - for( int i = 0; i < count; i++) - { - visitNode( node->elifTestSequence->at(i)->element ); - ExpressionAst* expr = safeNodeCast( mNodeStack.pop() ); - visitNode( node->elifSuiteSequence->at(i)->element ); - ast->elseIfBodies.append( - qMakePair( expr , - generateSpecializedList( - mListStack.pop() ) ) ); - } - } - if( node->ifElseSuite ) - { - visitNode( node->ifElseSuite ); - ast->elseBody = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitIfStmt end"; -} - -void AstBuilder::visitImportFrom(PythonParser::ImportFromAst *node) -{ - kDebug() << "visitImportFrom start"; - if( !node->importAsNames ) - { - StarImportAst* ast = createAst( node ); - ast->modulePath = identifierListFromTokenList( ast, node->importFromName->dottedNameSequence ); - mNodeStack.push( ast ); - }else - { - FromImportAst* ast = createAst( node ); - ast->modulePath = identifierListFromTokenList( ast, node->importFromName->dottedNameSequence ); - const KDevPG::ListNode* idNames; - idNames = node->importAsNames->importAsNameSequence; - int count = idNames->count(); - for(int i = 0; i < count; i++) - { - PythonParser::ImportAsNameAst* namenode = idNames->at(i)->element; - kDebug() << "Fetching from-as:" << tokenText( namenode->importedName ); - ast->identifierAsName.append( qMakePair( - createIdentifier( ast, namenode->importedName ), - createIdentifier( ast, namenode->importedAs ) ) ); - } - mNodeStack.push( ast ); - } - kDebug() << "visitImportFrom end"; -} - -void AstBuilder::visitImportName(PythonParser::ImportNameAst *node) -{ - kDebug() << "visitImportName start"; - PlainImportAst* ast = createAst( node ); - const KDevPG::ListNode* importedmodules; - importedmodules = node->importName->dottedAsNameSequence; - int count = importedmodules->count(); - for( int i = 0; i < count ; i++ ) - { - PythonParser::DottedAsNameAst* import = importedmodules->at(i)->element; - QList modulepath = identifierListFromTokenList( ast, import->importDottedName->dottedNameSequence ); - ast->modulesAsName.append( qMakePair( modulepath, createIdentifier( ast, import->importedAs ) ) ); - } - mNodeStack.push( ast ); - kDebug() << "visitImportName end"; -} - -void AstBuilder::visitImportStmt(PythonParser::ImportStmtAst *node) -{ - kDebug() << "visitImportStmt start"; - PythonParser::DefaultVisitor::visitImportStmt( node ); - kDebug() << "visitImportStmt end"; -} - -void AstBuilder::visitLambdaDef(PythonParser::LambdaDefAst *node) -{ - kDebug() << "visitLambdaDef start"; - LambdaAst* ast = createAst( node ); - if( node->lambdaVarargslist ) - { - visitNode( node->lambdaVarargslist ); - ast->parameters = generateSpecializedList( mListStack.pop() ); - } - visitNode( node->lambdaTest ); - ast->expression = safeNodeCast( mNodeStack.pop() ); - kDebug() << "visitLambdaDef end"; -} - -void AstBuilder::visitListFor(PythonParser::ListForAst *node) -{ - kDebug() << "visitListFor start"; - ListForAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->exprlist ); - ast->assignedTargets = generateSpecializedList( mListStack.pop() ); - visitNode( node->testlistSafe ); - ast->iterableObject = generateSpecializedList( mListStack.pop() ); - if( node->listIter ) - { - visitNode( node->listIter ); - if( node->listIter->listFor ) - { - ast->nextGenerator = safeNodeCast( mNodeStack.pop() ); - }else - { - ast->nextCondition = safeNodeCast( mNodeStack.pop() ); - } - } - kDebug() << "visitListFor end"; -} - -void AstBuilder::visitListIf(PythonParser::ListIfAst *node) -{ - kDebug() << "visitListIf start"; - ListIfAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->test ); - ast->condition = safeNodeCast( mNodeStack.pop() ); - if( node->listIter ) - { - visitNode( node->listIter ); - if( node->listIter->listFor ) - { - ast->nextGenerator = safeNodeCast( mNodeStack.pop() ); - }else - { - ast->nextCondition = safeNodeCast( mNodeStack.pop() ); - } - } - - kDebug() << "visitListIf end"; -} - -void AstBuilder::visitListIter(PythonParser::ListIterAst *node) -{ - kDebug() << "visitListIter start"; - PythonParser::DefaultVisitor::visitListIter( node ); - kDebug() << "visitListIter end"; -} - -void AstBuilder::visitListmaker(PythonParser::ListmakerAst *node) -{ - kDebug() << "visitListmaker start"; - ListAst* ast = createAst( node ); - mNodeStack.push( ast ); - visitNode( node->listMakerTest ); - if ( node->listMakerTest ) { - ast->plainList = generateSpecializedList( mListStack.pop() ); - } - if( node->listFor ) - { - //We should have only 1 expression in the listMakerTest as we're having a list_comprehension - Q_ASSERT( node->listMakerTest->listTestSequence->count() == 1 ); - visitNode( node->listFor ); - ast->listGenerator = safeNodeCast( mNodeStack.pop() ); - } - kDebug() << "visitListmaker end"; -} - -void AstBuilder::visitListMakerTest(PythonParser::ListMakerTestAst *node) -{ - kDebug() << "visitListMakerTest start"; - QList l; - int count = node->listTestSequence->count(); - kDebug() << "Elements in list cnt: " << count; - for( int i = 0; i < count; i++ ) - { - visitNode( node->listTestSequence->at(i)->element ); - l << mNodeStack.pop(); - } - mListStack.push( l ); - kDebug() << "visitListMakerTest end"; -} - -void AstBuilder::visitNotTest(PythonParser::NotTestAst *node) + +CodeAst* AstBuilder::parse(KUrl filename) { - kDebug() << "visitNotTest start"; - if( node->notTest ) - { - BooleanNotOperationAst* ast = createAst( node ); - mNodeStack.push( ast ); - - visitNode( node->notTest ); - - Ast* tmp = mNodeStack.pop(); - // maybe it's an atom, then there's nothing left to do - if ( tmp->astType != Ast::AtomAst ) { - kDebug() << "Using boolean operator"; - ast->op = safeNodeCast( tmp ); - } - else { - kDebug() << "Using NULL operator"; - ast->op = 0; - } - }else - { - visitNode( node->comparison ); - } - kDebug() << "visitNotTest end"; + return parseXmlAst(getXmlForFile(filename)); } - -void AstBuilder::visitNumber(PythonParser::NumberAst *node) -{ - kDebug() << "visitNumber start"; - LiteralAst* ast = createAst( node ); - switch( node->numType ) - { - case PythonParser::IntegerNumeric: - ast->literalType = LiteralAst::Integer; - break; - case PythonParser::ImaginaryNumeric: - ast->literalType = LiteralAst::ImaginaryNumber; - break; - case PythonParser::FloatNumeric: - ast->literalType = LiteralAst::Float; - break; - } - ast->value = tokenText( node->value ); - mNodeStack.push( ast ); - kDebug() << "visitNumber end"; -} - -void AstBuilder::visitPassStmt(PythonParser::PassStmtAst *node) + +QString AstBuilder::getXmlForFile(KUrl filename) const { - kDebug() << "visitPassStmt start"; - StatementAst* ast = createAst( node, Ast::PassAst ); - mNodeStack.push( ast ); - kDebug() << "visitPassStmt end"; + QProcess parser; + parser.start("pythonpythonparser.py", QStringList(filename)); + parser.waitForFinished(); + QString result = parser.readAllStandardOutput(); + kDebug() << "XML for " << filename << ":" << result; + return result; } -void AstBuilder::visitPower(PythonParser::PowerAst *node) +CodeAst* AstBuilder::parseXmlAst(QString xml) { - kDebug() << "visitPower start"; - visitNode( node->atom ); - if( node->trailerSequence ) - { - int count = node->trailerSequence->count(); - if( count > 0 ) - { - for( int i = 0; i < count; i++ ) - { - visitTrailer( node->trailerSequence->at( i )->element ); - PrimaryAst* ast = safeNodeCast( mNodeStack.pop() ); - PrimaryAst* prim = safeNodeCast( mNodeStack.pop() ); - switch( ast->astType ) - { - case Ast::CallAst: - static_cast( ast )->callable = prim; - break; - case Ast::ExtendedSliceAst: - case Ast::SimpleSliceAst: - static_cast( ast )->primary = prim; - break; - case Ast::AttributeReferenceAst: - static_cast( ast )->primary = prim; - break; - case Ast::SubscriptAst: - static_cast( ast )->primary = prim; - break; - default: - Q_ASSERT_X(false, "visitTrailer", "OOOPS visitTrailer returned a PrimaryAst that is not known to have a primary in front of it, like an AtomAst or something new."); - break; - } - mNodeStack.push( ast ); - } - } - } - if( node->factor ) - { - BinaryExpressionAst* bast = createAst( node ); - bast->opType = ArithmeticExpressionAst::Power; - bast->lhs = safeNodeCast( mNodeStack.pop() ); - visitNode( node->factor ); - bast->rhs = safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( bast ); - } - kDebug() << "visitPower end"; + QDomDocument ast; + ast.setContent(xml); + QDomElement codeAst = ast.documentElement(); + kDebug() << codeAst; } - -void AstBuilder::visitPlainArgumentsList(PythonParser::PlainArgumentsListAst *node) -{ - kDebug() << "visitPlainArgumentsList start"; - QList l; - int count = node->argumentsSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->argumentsSequence->at(i)->element ); - if( dynamic_cast( mNodeStack.top() ) ) - { - l << safeNodeCast( mNodeStack.pop() ); - }else if( dynamic_cast( mNodeStack.top() ) ) - { - //Early return, we found a generator expression on the stack - return; - } - } - mListStack.push( l ); - kDebug() << "visitPlainArgumentsList end"; -} - -void AstBuilder::visitPrintStmt(PythonParser::PrintStmtAst *node) -{ - kDebug() << "visitPrintStmt start"; - PrintAst* ast = createAst( node ); - if( node->printArgsSequence->count() > 0 ) - { - int count = node->printArgsSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->printArgsSequence->at(i)->element ); - ast->printables.append( safeNodeCast( mNodeStack.pop() ) ); - } - }else - { - visitNode( node->rshiftArgsSequence->at(0)->element ); - ast->outfile = safeNodeCast( mNodeStack.pop() ); - int count = node->rshiftArgsSequence->count(); - for( int i = 1; i < count; i++ ) - { - visitNode( node->printArgsSequence->at(i)->element ); - ast->printables.append( safeNodeCast( mNodeStack.pop() ) ); - } - } - mNodeStack.push( ast ); - kDebug() << "visitPrintStmt end"; -} - -void AstBuilder::visitProject(PythonParser::ProjectAst *node) -{ - kDebug() << "visitProject start"; - CodeAst* code = new CodeAst(); - setStartEnd( code, node ); - mNodeStack.push( code ); - kDebug() << "Node stack count: " << mNodeStack.count(); - if( node->stmtSequence ) - { - int count = node->stmtSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->stmtSequence->at(i)->element ); - Ast* a = mNodeStack.pop(); - if( a ) - code->statements << safeNodeCast( a ); - kDebug() << "Node stack count: " << mNodeStack.count(); - } - } - kDebug() << "Node stack count: " << mNodeStack.count(); - kDebug() << "visitProject end"; -} - -void AstBuilder::visitRaiseStmt(PythonParser::RaiseStmtAst *node) -{ - kDebug() << "visitRaiseStmt start"; - RaiseAst* ast = createAst( node ); - if( node->type ) - { - visitNode( node->type ); - ast->exceptionType = safeNodeCast( mNodeStack.pop() ); - } - if( node->value ) - { - visitNode( node->value ); - ast->exceptionValue = safeNodeCast( mNodeStack.pop() ); - } - if( node->traceback ) - { - visitNode( node->traceback ); - ast->traceback = safeNodeCast( mNodeStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitRaiseStmt end"; -} - -void AstBuilder::visitReturnStmt(PythonParser::ReturnStmtAst *node) -{ - kDebug() << "visitReturnStmt start"; - ReturnAst* ast = createAst( node ); - visitNode( node->returnExpr ); - ast->returnValues = generateSpecializedList( mListStack.pop() ); - mNodeStack.push( ast ); - kDebug() << "visitReturnStmt end"; -} - -void AstBuilder::visitShiftExpr(PythonParser::ShiftExprAst *node) -{ - kDebug() << "visitShiftExpr start"; - visitNode( node->arithExpr ); - if( node->shiftOpListSequence ) - { - int count = node->shiftOpListSequence->count(); - if( count > 0 ) - { - Q_ASSERT( count == node->arithExprListSequence->count() ); - BinaryExpressionAst* ast = createAst( node ); - ast->lhs = safeNodeCast( mNodeStack.pop() ); - BinaryExpressionAst* cur = ast; - for( int i = 0; i < count; i++ ) - { - switch( node->shiftOpListSequence->at( i )->element->shiftOp ) - { - case PythonParser::LeftShiftOp: - cur->opType = ArithmeticExpressionAst::BinaryLeftShift; - break; - case PythonParser::RightShiftOp: - cur->opType = ArithmeticExpressionAst::BinaryRightShift; - break; - default: - Q_ASSERT_X(false, "visitShiftExpr", "OOOPS, shift operator was something other than left or right shifting!"); - } - visitNode( node->arithExprListSequence->at( i )->element ); - if( i == count - 1 ) - { - cur->rhs = safeNodeCast( mNodeStack.pop() ); - }else - { - cur->rhs = createAst( node->arithExprListSequence->at( i )->element ); - cur = safeNodeCast( cur->rhs ); - cur->lhs = safeNodeCast( mNodeStack.pop() ); - } - } - mNodeStack.push( ast ); - } - } - kDebug() << "visitShiftExpr end"; -} - -void AstBuilder::visitSimpleStmt(PythonParser::SimpleStmtAst *node) -{ - kDebug() << "visitSimpleStmt start"; - PythonParser::DefaultVisitor::visitSimpleStmt( node ); - kDebug() << "visitSimpleStmt end"; -} - -void AstBuilder::visitSmallStmt(PythonParser::SmallStmtAst *node) -{ - kDebug() << "visitSmallStmt start"; - PythonParser::DefaultVisitor::visitSmallStmt( node ); - kDebug() << "visitSmallStmt end"; -} - -void AstBuilder::visitStmt(PythonParser::StmtAst *node) -{ - kDebug() << "visitStmt start"; - if( node->simpleStmt || node->compoundStmt ) - { - PythonParser::DefaultVisitor::visitStmt( node ); - }else - { - // Pushing a 0 onto the stack so that visitProject and visitSuite can - // test for this case - mNodeStack.push( 0 ); - kDebug() << "Found linebreak"; - } - kDebug() << "visitStmt end"; -} - -void AstBuilder::visitSubscript(PythonParser::SubscriptAst *node) -{ - kDebug() << "visitSubscript start"; - if( node->isEllipsis || node->hasColon ) - { - if( node->isEllipsis ) - { - EllipsisSliceItemAst* ast = createAst( node ); - mNodeStack.push( ast ); - }else - { - ProperSliceItemAst* ast = createAst( node ); - mNodeStack.push( ast ); - if( node->begin ) - { - visitNode( node->begin ); - ast->bounds.first = safeNodeCast( mNodeStack.pop() ); - } - if( node->end ) - { - visitNode( node->end ); - ast->bounds.second = safeNodeCast( mNodeStack.pop() ); - } - if( node->step ) - { - visitNode( node->step ); - ast->stride = safeNodeCast( mNodeStack.pop() ); - } - } - }else if( node->begin ) - { - visitNode( node->begin ); - } - kDebug() << "visitSubscript end"; -} - -void AstBuilder::visitSubscriptlist(PythonParser::SubscriptlistAst *node) -{ - kDebug() << "visitSubscriptlist start"; - - if( node->hasComma ) - { - int count = node->subscriptSequence->count(); - PrimaryAst* curast = createAst( node ); - mNodeStack.push( curast ); - for( int i = 0; i < count; i++ ) - { - visitNode( node->subscriptSequence->at( i )->element ); - if( dynamic_cast( mNodeStack.top() ) == 0 - && curast->astType != Ast::ExtendedSliceAst ) - { - SubscriptAst* sast = safeNodeCast( curast ); - curast = createAst( node ); - ExtendedSliceAst* esast = safeNodeCast( curast ); - for( int j = 0; j < sast->subscription.count(); j++ ) - { - ExpressionSliceItemAst* esiast = createAst( - node->subscriptSequence->at(j)->element ); - esiast->sliceExpression = sast->subscription.at( j ); - esast->extendedSliceList << esiast; - } - delete sast; - } - - if( curast->astType == Ast::ExtendedSliceAst ) - { - if( dynamic_cast( mNodeStack.top() ) != 0 ) - { - ExpressionSliceItemAst* itemast = createAst( - node->subscriptSequence->at(i)->element ); - itemast->sliceExpression = safeNodeCast( mNodeStack.pop() ); - safeNodeCast( curast )->extendedSliceList << itemast; - }else - { - safeNodeCast( curast )->extendedSliceList << - safeNodeCast( mNodeStack.pop() ); - } - }else - { - safeNodeCast( curast )->subscription - << safeNodeCast( mNodeStack.pop() ); - } - } - }else - { - visitNode( node->subscriptSequence->at(0)->element ); - if( dynamic_cast( mNodeStack.top() ) ) - { - SubscriptAst* ast = createAst( node ); - ast->subscription << safeNodeCast( mNodeStack.pop() ); - mNodeStack.push( ast ); - }else - { - SimpleSliceAst* ast = createAst( node ); - ProperSliceItemAst* extslice = safeNodeCast( mNodeStack.pop() ); - ast->simpleSliceBounds.first = extslice->bounds.first; - ast->simpleSliceBounds.second = extslice->bounds.second; - delete extslice; - mNodeStack.push( ast ); - } - } - - kDebug() << "visitSubscriptlist end"; -} - -void AstBuilder::visitSuite(PythonParser::SuiteAst *node) -{ - kDebug() << "visitSuite start"; - QList l; - if( node->simpleStmt ) - { - visitNode( node->simpleStmt ); - l << mNodeStack.pop(); - } else - { - int count = node->stmtSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->stmtSequence->at(i)->element ); - Ast* a = mNodeStack.pop(); - if( a ) - l << a; - } - } - mListStack.push( l ); - kDebug() << "visitSuite end"; -} - -void AstBuilder::visitTerm(PythonParser::TermAst *node) -{ - kDebug() << "visitTerm start"; - visitNode( node->factor ); - if( node->factorsSequence ) - { - int count = node->factorsSequence->count(); - if( count > 0 ) - { - Q_ASSERT( count == node->termOpSequence->count() ); - BinaryExpressionAst* curast = createAst( node ); - curast->lhs = safeNodeCast( mNodeStack.pop() ); - // put the binary expression onto the stack now, so its still on the stack - // after the loop finishes - mNodeStack.push( curast ); - for( int i = 0; i < count; i++ ) - { - //Push current bin-expr on stack to be used as parent - mNodeStack.push( curast ); - visitNode( node->factorsSequence->at(i)->element ); - if( i == count-1 ) - { - curast->rhs = safeNodeCast( mNodeStack.pop() ); - }else - { - curast->rhs = createAst( node ); - switch( node->termOpSequence->at(i)->element->op ) - { - case PythonParser::StarOp: - curast->opType = ArithmeticExpressionAst::BinaryMultiply; - break; - case PythonParser::ModuloOp: - curast->opType = ArithmeticExpressionAst::BinaryModulo; - break; - case PythonParser::SlashOp: - curast->opType = ArithmeticExpressionAst::BinaryDivide; - break; - case PythonParser::DoubleSlashOp: - curast->opType = ArithmeticExpressionAst::BinaryFloor; - break; - default: - Q_ASSERT_X( false, "visitTerm", "OOPS, termop has an unknown value" ); - } - curast->lhs = safeNodeCast( mNodeStack.pop() ); - curast = safeNodeCast( curast->rhs ); - } - //pop parent from stack - mNodeStack.pop(); - } - } - } - kDebug() << "visitTerm end"; -} - -void AstBuilder::visitTest(PythonParser::TestAst *node) -{ - kDebug() << "visitTest start"; - if( node->lambdaDef ) - { - visitNode( node->lambdaDef ); - }else - { - visitNode( node->andTestSequence->at(0)->element ); - if( node->andTestSequence->count() > 1 ) - { - BooleanOrOperationAst* ast = createAst( node ); - ast->lhs = safeNodeCast( mNodeStack.pop() ); - int count = node->andTestSequence->count(); - mNodeStack.push( ast ); - for( int i = 1; i < count; i++ ) - { - visitNode( node->andTestSequence->at(i)->element ); - if( i+1 < count ) - { - BooleanOrOperationAst* tmp = createAst( - node->andTestSequence->at(i)->element ); - tmp->lhs = safeNodeCast( mNodeStack.pop() ); - ast->rhs = tmp; - ast = tmp; - }else - { - ast->rhs = safeNodeCast( mNodeStack.pop() ); - } - } - } - } - kDebug() << "visitTest end"; -} - -void AstBuilder::visitTestlist(PythonParser::TestlistAst *node) -{ - kDebug() << "visitTestlist start"; - QList expressions; - int count = node->testsSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->testsSequence->at( i )->element ); - expressions << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( expressions ); - kDebug() << "visitTestlist end"; -} - -void AstBuilder::visitCodeexpr(PythonParser::CodeexprAst *node) -{ - kDebug() << "visitCodeexpr start"; - QList l; - int count = node->testSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->testSequence->at(i)->element ); - l << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( l ); - kDebug() << "visitCodeexpr end"; -} - -void AstBuilder::visitTestlistSafe(PythonParser::TestlistSafeAst *node) -{ - kDebug() << "visitTestlistSafe start"; - QList expressions; - int count = node->testSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->testSequence->at( i )->element ); - expressions << safeNodeCast( mNodeStack.pop() ); - } - mListStack.push( expressions ); - kDebug() << "visitTestlistSafe end"; -} - -void AstBuilder::visitTrailer(PythonParser::TrailerAst *node) -{ - kDebug() << "visitTrailer start"; - if( node->trailerArglist ) - { - CallAst* ast = createAst( node ); - visitNode( node->trailerArglist ); - QList tmp = mListStack.pop(); - if( tmp.count() == 1 && tmp.at( 0 )->astType == Ast::GeneratorAst ) - { - //generator in the call - ast->generator = safeNodeCast( tmp.at( 0 ) ); - }else - { - ast->arguments = generateSpecializedList( tmp ); - } - mNodeStack.push( ast ); - }else if( node->trailerDotName ) - { - AttributeReferenceAst* ast = createAst( node ); - ast->identifier = createIdentifier( ast, node->trailerDotName ); - mNodeStack.push( ast ); - } - kDebug() << "visitTrailer end"; -} - -void AstBuilder::visitTryStmt(PythonParser::TryStmtAst *node) -{ - kDebug() << "visitTryStmt start"; - TryAst* ast = createAst( node ); - visitNode( node->trySuite ); - ast->tryBody = generateSpecializedList( mListStack.pop() ); - if( node->finallySuite ) - { - ast->finallyBody = generateSpecializedList( mListStack.pop() ); - }else - { - int count = node->exceptClauseSequence->count(); - for( int i = 1; i < count; i++ ) - { - visitNode( node->exceptClauseSequence->at(i)->element ); - ExceptAst* ex = safeNodeCast( mNodeStack.pop() ); - visitNode( node->exceptSuiteSequence->at(i)->element ); - ex->exceptionBody = generateSpecializedList( mListStack.pop() ); - ast->exceptions.append( ex ); - } - if( node->tryElseSuite ) - { - visitNode( node->tryElseSuite ); - ast->elseBody = generateSpecializedList( mListStack.pop() ); - } - } - mNodeStack.push( ast ); - kDebug() << "visitTryStmt end"; -} - -void AstBuilder::visitVarargslist(PythonParser::VarargslistAst *node) -{ - kDebug() << "visitVarargslist start"; - QList l; - if( node->funcDef ) - { - visitNode( node->funcDef ); - l += mListStack.pop(); - } - if( node->funPosParam ) - { - if( node->funPosParam->listParam ) - { - ListParameterAst* ast = createAst( node->funPosParam->listParam ); - ast->name = createIdentifier( ast, node->funPosParam->listParam->starId ); - l << ast; - } - if( node->funPosParam->dictParam ) - { - DictionaryParameterAst* ast = createAst( node->funPosParam->dictParam ); - ast->name = createIdentifier( ast, node->funPosParam->dictParam->doubleStarId ); - l << ast; - } - } - mListStack.push( l ); - kDebug() << "visitVarargslist end"; -} - -void AstBuilder::visitWhileStmt(PythonParser::WhileStmtAst *node) -{ - kDebug() << "visitWhileStmt start"; - WhileAst* ast = createAst( node ); - visitNode( node->whileTest ); - ast->condition = safeNodeCast( mNodeStack.pop() ); - visitNode( node->whileSuite ); - ast->whileBody = generateSpecializedList( mListStack.pop() );; - if( node->whileElseSuite ) - { - visitNode( node->whileElseSuite ); - ast->elseBody = generateSpecializedList( mListStack.pop() ); - } - mNodeStack.push( ast ); - kDebug() << "visitWhileStmt end"; -} - -void AstBuilder::visitXorExpr(PythonParser::XorExprAst *node) -{ - kDebug() << "visitXorExpr start"; - visitNode( node->xorExpr ); - if( node->hatXorExprSequence && node->hatXorExprSequence->count() > 0 ) - { - BinaryExpressionAst* curast = createAst( node ); - mNodeStack.push( curast ); - int count = node->hatXorExprSequence->count(); - for( int i = 0; i < count; i++ ) - { - visitNode( node->hatXorExprSequence->at(i)->element ); - if( i == count - 1 ) - { - curast->rhs = safeNodeCast( mNodeStack.pop() ); - }else - { - BinaryExpressionAst* bin = createAst( node->hatXorExprSequence->at(i)->element ); - bin->lhs = safeNodeCast( mNodeStack.pop() ); - curast->rhs = bin; - curast = bin; - } - } - } - kDebug() << "visitXorExpr end"; -} - -void AstBuilder::visitYieldExpr( PythonParser::YieldExprAst * node ) -{ - kDebug() << "visitYieldExpr start"; - YieldAst* ast = createAst( node ); - visitNode( node->expr ); - ast->yieldValue = generateSpecializedList( mListStack.pop() ); - mNodeStack.push( ast ); - kDebug() << "visitYieldExpr end"; -} - -void AstBuilder::visitYieldStmt(PythonParser::YieldStmtAst *node) -{ - kDebug() << "visitYieldStmt start"; - visitNode( node->yield ); - kDebug() << "visitYieldStmt end"; -} - -CodeAst* AstBuilder::codeAst() -{ - return safeNodeCast( mNodeStack.top() ); -} - - + } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 827e9c2..d5c214f 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -23,10 +23,8 @@ #include -#include - -#include "pythondefaultvisitor.h" #include "ast.h" +#include namespace PythonParser { @@ -40,110 +38,16 @@ namespace Python class CodeAst; -class AstBuilder : public PythonParser::DefaultVisitor +class AstBuilder { + public: - AstBuilder(PythonParser::Parser*); - CodeAst* codeAst(); - - virtual void visitAndExpr(PythonParser::AndExprAst *node); - virtual void visitAndTest(PythonParser::AndTestAst *node); - virtual void visitArglist(PythonParser::ArglistAst *node); - virtual void visitArgument(PythonParser::ArgumentAst *node); - virtual void visitArithExpr(PythonParser::ArithExprAst *node); - virtual void visitAssertStmt(PythonParser::AssertStmtAst *node); - virtual void visitAtom(PythonParser::AtomAst *node); - virtual void visitBreakStmt(PythonParser::BreakStmtAst *node); - virtual void visitClassdef(PythonParser::ClassdefAst *node); - virtual void visitCodeexpr(PythonParser::CodeexprAst *node); - virtual void visitComparison(PythonParser::ComparisonAst *node); - virtual void visitCompoundStmt(PythonParser::CompoundStmtAst *node); - virtual void visitContinueStmt(PythonParser::ContinueStmtAst *node); - virtual void visitDottedName(PythonParser::DottedNameAst *node); - virtual void visitDecorator(PythonParser::DecoratorAst *node); - virtual void visitDecorators(PythonParser::DecoratorsAst *node); - virtual void visitDefparam(PythonParser::DefparamAst *node); - virtual void visitDelStmt(PythonParser::DelStmtAst *node); - virtual void visitDictmaker(PythonParser::DictmakerAst *node); - virtual void visitExceptClause(PythonParser::ExceptClauseAst *node); - virtual void visitExecStmt(PythonParser::ExecStmtAst *node); - virtual void visitExpr(PythonParser::ExprAst *node); - virtual void visitExprStmt(PythonParser::ExprStmtAst *node); - virtual void visitExprlist(PythonParser::ExprlistAst *node); - virtual void visitFactor(PythonParser::FactorAst *node); - virtual void visitFlowStmt(PythonParser::FlowStmtAst *node); - virtual void visitForStmt(PythonParser::ForStmtAst *node); - virtual void visitFpDef(PythonParser::FpDefAst *node); - virtual void visitFplist(PythonParser::FplistAst *node); - virtual void visitFuncdecl(PythonParser::FuncdeclAst *node); - virtual void visitFuncDef(PythonParser::FuncDefAst *node); - virtual void visitGenFor(PythonParser::GenForAst *node); - virtual void visitGenIf(PythonParser::GenIfAst *node); - virtual void visitGenIter(PythonParser::GenIterAst *node); - virtual void visitGlobalStmt(PythonParser::GlobalStmtAst *node); - virtual void visitIfStmt(PythonParser::IfStmtAst *node); - virtual void visitImportFrom(PythonParser::ImportFromAst *node); - virtual void visitImportName(PythonParser::ImportNameAst *node); - virtual void visitImportStmt(PythonParser::ImportStmtAst *node); - virtual void visitLambdaDef(PythonParser::LambdaDefAst *node); - virtual void visitListFor(PythonParser::ListForAst *node); - virtual void visitListIf(PythonParser::ListIfAst *node); - virtual void visitListIter(PythonParser::ListIterAst *node); - virtual void visitListmaker(PythonParser::ListmakerAst *node); - virtual void visitListMakerTest(PythonParser::ListMakerTestAst *node); - virtual void visitNotTest(PythonParser::NotTestAst *node); - virtual void visitNumber(PythonParser::NumberAst *node); - virtual void visitPassStmt(PythonParser::PassStmtAst *node); - virtual void visitPlainArgumentsList(PythonParser::PlainArgumentsListAst *node); - virtual void visitPower(PythonParser::PowerAst *node); - virtual void visitPrintStmt(PythonParser::PrintStmtAst *node); - virtual void visitProject(PythonParser::ProjectAst *node); - virtual void visitRaiseStmt(PythonParser::RaiseStmtAst *node); - virtual void visitReturnStmt(PythonParser::ReturnStmtAst *node); - virtual void visitShiftExpr(PythonParser::ShiftExprAst *node); - virtual void visitSimpleStmt(PythonParser::SimpleStmtAst *node); - virtual void visitSmallStmt(PythonParser::SmallStmtAst *node); - virtual void visitStmt(PythonParser::StmtAst *node); - virtual void visitSubscript(PythonParser::SubscriptAst *node); - virtual void visitSubscriptlist(PythonParser::SubscriptlistAst *node); - virtual void visitSuite(PythonParser::SuiteAst *node); - virtual void visitTerm(PythonParser::TermAst *node); - virtual void visitTest(PythonParser::TestAst *node); - virtual void visitTestlist(PythonParser::TestlistAst *node); - virtual void visitTestlistSafe(PythonParser::TestlistSafeAst *node); - virtual void visitTrailer(PythonParser::TrailerAst *node); - virtual void visitTryStmt(PythonParser::TryStmtAst *node); - virtual void visitVarargslist(PythonParser::VarargslistAst *node); - virtual void visitWhileStmt(PythonParser::WhileStmtAst *node); - virtual void visitXorExpr(PythonParser::XorExprAst *node); - virtual void visitYieldStmt(PythonParser::YieldStmtAst *node); - virtual void visitYieldExpr(PythonParser::YieldExprAst *node); - - QStack mNodeStack; + CodeAst* parse(KUrl filename); private: - QStack > mListStack; - PythonParser::Parser* parser; - void setStartEnd( Ast* ast, PythonParser::AstNode* node ); - QString tokenText( qint64 tokenidx ); - - template T* createAst( PythonParser::AstNode* node, Ast::AstType t ) - { - T* ast = new T( mNodeStack.top(), t ); - setStartEnd( ast, node ); - return ast; - } - - template T* createAst( PythonParser::AstNode* node ) - { - T* ast = new T( mNodeStack.top() ); - setStartEnd( ast, node ); - return ast; - } - QList identifierListFromTokenList( Ast* parent, const KDevPG::ListNode* sequence ); - IdentifierAst* createIdentifier( Ast* parent, qint64 idx ); + CodeAst* parseXmlAst(QString xml); + QString getXmlForFile(KUrl filename) const; }; } -#endif - +#endif \ No newline at end of file diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index b8b715b..403a306 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -26,6 +26,7 @@ #include "pythondriver.h" #include +#include "astbuilder.h" using namespace KDevelop; @@ -62,10 +63,9 @@ void ParseSession::setContents( const QString& contents ) bool ParseSession::parse( Python::CodeAst** ast ) { - Python::Driver d; - d.setContent( m_contents ); - kDebug() << m_contents; - return d.parse( ast ); + AstBuilder parser; + ast = parser.parse(m_currentDocument); + Q_ASSERT(false); } } diff --git a/pythonpythonparser.py b/pythonpythonparser.py old mode 100644 new mode 100755 index 27b7967..c33c76e --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -65,7 +65,7 @@ def generic_visit(self, node): self.currentnode = save_currentnode -f = open('/usr/lib/entropy/libraries/entropy/cache.py').read() +f = open(sys.argv[1]).read() v = KDevelopNodeVisitor() v.visit(ast.parse(f)) print v.xmlrepr.toprettyxml(indent = " ") From e2787391b50412a68372a0f0f62864dfd5aabea9 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 16 Oct 2010 17:55:17 +0200 Subject: [PATCH 016/118] A very minimal new AST tree --- parser/CMakeLists.txt | 53 +-- parser/ast.cpp | 314 -------------- parser/ast.h | 906 +++------------------------------------- parser/astbuilder.cpp | 74 +++- parser/astbuilder.h | 21 +- parser/parsesession.cpp | 6 +- parser/parsesession.h | 7 +- pythonparsejob.cpp | 6 +- pythonpythonparser.py | 3 +- 9 files changed, 176 insertions(+), 1214 deletions(-) diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index f0290e3..e61bb70 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -1,57 +1,40 @@ - - - include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) set(parser_STAT_SRCS - pythondriver.cpp parsesession.cpp - pythonlexer.cpp - kwcheck.cpp - numbercheck.cpp ast.cpp astdefaultvisitor.cpp astvisitor.cpp astbuilder.cpp - astprinter.cpp - ) - -kdevpgqt_generate(_kdevpgList python NAMESPACE PythonParser - "${kdevpython_SOURCE_DIR}/parser/python.g" - "${kdevpython_SOURCE_DIR}/parser/pythonlexer.h" ) -add_custom_target( debuginfo - ${KDEVPG_EXECUTABLE} --terminals - "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">terminals" - COMMAND ${KDEVPG_EXECUTABLE} --symbols - "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">symbols" - COMMAND ${KDEVPG_EXECUTABLE} --rules - "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">rules" "2>errors" - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" -) -set( parser_SRCS - ${_kdevpgList} -) +# kdevpgqt_generate(_kdevpgList python NAMESPACE PythonParser +# "${kdevpython_SOURCE_DIR}/parser/python.g" +# "${kdevpython_SOURCE_DIR}/parser/pythonlexer.h" +# ) + +# add_custom_target( debuginfo +# ${KDEVPG_EXECUTABLE} --terminals +# "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">terminals" +# COMMAND ${KDEVPG_EXECUTABLE} --symbols +# "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">symbols" +# COMMAND ${KDEVPG_EXECUTABLE} --rules +# "${CMAKE_CURRENT_SOURCE_DIR}/parser/python.g" ">rules" "2>errors" +# WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +# ) +# set( parser_SRCS +# ${_kdevpgList} +# ) #add_subdirectory(tests) kde4_add_library( kdev4pythonparser SHARED ${parser_SRCS} ${parser_STAT_SRCS} ) -target_link_libraries( - kdev4pythonparser +target_link_libraries(kdev4pythonparser ${KDE4_KDECORE_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} -) - -kde4_add_executable( python-parser main.cpp ) - -target_link_libraries( - python-parser ${QT_QTCORE_LIBRARY} - kdev4pythonparser ) -install(TARGETS python-parser ${INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS kdev4pythonparser DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/parser/ast.cpp b/parser/ast.cpp index 79a03a6..69910b7 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -32,320 +32,6 @@ Ast::~Ast() { } -CodeAst::CodeAst() - : Ast( 0, Ast::CodeAst ) -{ -} -FunctionDefinitionAst::FunctionDefinitionAst( Ast* parent ) - : StatementAst( parent, Ast::FunctionDefinitionAst ), functionName( 0 ) -{ -} -DecoratorAst::DecoratorAst( Ast* parent ) - : Ast( parent, Ast::DecoratorAst ) -{ -} -ArgumentAst::ArgumentAst( Ast* parent ) - : Ast( parent, Ast::ArgumentAst ), argumentExpression( 0 ), keywordName( 0 ) -{ -} -ParameterAst::ParameterAst( Ast* parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} -StatementAst::StatementAst( Ast* parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} -IfAst::IfAst( Ast* parent ) - : StatementAst( parent, Ast::IfAst ), ifCondition( 0 ) -{ -} -WhileAst::WhileAst( Ast* parent ) - : StatementAst( parent, Ast::WhileAst ), condition( 0 ) -{ -} -ForAst::ForAst( Ast* parent ) - : StatementAst( parent, Ast::ForAst ) -{ -} -ClassDefinitionAst::ClassDefinitionAst( Ast* parent ) - : StatementAst( parent, Ast::ClassDefinitionAst ), className( 0 ) -{ -} -TryAst::TryAst( Ast* parent ) - : StatementAst( parent, Ast::TryAst ) -{ -} -ExceptAst::ExceptAst( Ast* parent ) - : Ast( parent, Ast::ExceptAst ), exceptionDeclaration( 0 ), exceptionValue( 0 ) -{ -} -WithAst::WithAst( Ast* parent ) - : StatementAst( parent, Ast::WithAst ), context( 0 ), name( 0 ) -{ -} -ExecAst::ExecAst( Ast* parent ) - : StatementAst( parent, Ast::ExecAst ), executable( 0 ), globalsAndLocals( 0 ), localsOnly( 0 ) -{ -} -GlobalAst::GlobalAst( Ast* parent ) - : StatementAst( parent, Ast::GlobalAst ) -{ -} -ImportAst::ImportAst( Ast* parent, Ast::AstType type ) - : StatementAst( parent, type ) -{ -} -PlainImportAst::PlainImportAst( Ast* parent ) - : ImportAst( parent, Ast::PlainImportAst ) -{ -} -StarImportAst::StarImportAst( Ast* parent ) - : ImportAst( parent, Ast::StarImportAst ) -{ -} -FromImportAst::FromImportAst( Ast* parent ) - : ImportAst( parent, Ast::FromImportAst ) -{ -} -RaiseAst::RaiseAst( Ast* parent ) - : StatementAst( parent, Ast::RaiseAst ), exceptionType( 0 ), exceptionValue( 0 ), traceback( 0 ) -{ -} -PrintAst::PrintAst( Ast* parent ) - : StatementAst( parent, Ast::PrintAst ), outfile( 0 ) -{ -} - -ReturnAst::ReturnAst( Ast* parent ) - : StatementAst( parent, Ast::ReturnAst ) -{ -} -YieldAst::YieldAst( Ast* parent ) - : StatementAst( parent, Ast::YieldAst ) -{ -} -DelAst::DelAst( Ast* parent ) - : StatementAst( parent, Ast::DelAst ) -{ -} -AssertAst::AssertAst( Ast* parent ) - : StatementAst( parent, Ast::AssertAst ), assertTest( 0 ), exceptionValue( 0 ) -{ -} -ExpressionStatementAst::ExpressionStatementAst( Ast* parent ) - : StatementAst( parent, Ast::ExpressionStatementAst ) -{ -} -AssignmentAst::AssignmentAst( Ast* parent ) - : StatementAst( parent, Ast::AssignmentAst ), yieldValue( 0 ) -{ -} -TargetAst::TargetAst( Ast* parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} -AtomAst::AtomAst( Ast* parent ) - : PrimaryAst( parent, Ast::AtomAst ), identifier( 0 ), literal( 0 ), enclosure( 0 ) -{ -} -EnclosureAst::EnclosureAst( Ast* parent ) - : Ast( parent, Ast::EnclosureAst ), list( 0 ), generator( 0 ), dict( 0 ), yield( 0 ) -{ -} -ListAst::ListAst( Ast* parent ) - : Ast( parent, Ast::ListAst ), listGenerator( 0 ) -{ -} -ListForAst::ListForAst( Ast* parent ) - : Ast( parent, Ast::ListForAst ), nextGenerator( 0 ), nextCondition( 0 ) -{ -} -ListIfAst::ListIfAst( Ast* parent ) - : Ast( parent, Ast::ListIfAst ), condition( 0 ), nextGenerator( 0 ), nextCondition( 0 ) -{ -} -GeneratorAst::GeneratorAst( Ast* parent ) - : Ast( parent, Ast::GeneratorAst ), generatedValue( 0 ), generator( 0 ) -{ -} -GeneratorForAst::GeneratorForAst( Ast* parent ) - : Ast( parent, Ast::GeneratorForAst ), iterableObject( 0 ), - nextGenerator( 0 ), nextCondition( 0 ) -{ -} -GeneratorIfAst::GeneratorIfAst( Ast* parent ) - : Ast( parent, Ast::GeneratorIfAst ), condition( 0 ), nextGenerator( 0 ), nextCondition( 0 ) -{ -} -DictionaryAst::DictionaryAst( Ast* parent ) - : Ast( parent, Ast::DictionaryAst ) -{ -} -PrimaryAst::PrimaryAst( Ast* parent, Ast::AstType type ) - : ExpressionAst( parent, type ) -{ -} -AttributeReferenceAst::AttributeReferenceAst( Ast* parent ) - : PrimaryAst( parent, Ast::AttributeReferenceAst ), primary( 0 ), identifier( 0 ) -{ -} -SubscriptAst::SubscriptAst( Ast* parent ) - : PrimaryAst( parent, Ast::SubscriptAst ), primary( 0 ) -{ -} -SliceAst::SliceAst( Ast* parent, Ast::AstType type ) - : PrimaryAst( parent, type ), primary( 0 ) -{ -} -ExtendedSliceAst::ExtendedSliceAst( Ast* parent ) - : SliceAst( parent, Ast::ExtendedSliceAst ) -{ -} -SimpleSliceAst::SimpleSliceAst( Ast* parent ) - : SliceAst( parent, Ast::SimpleSliceAst ) -{ -} -SliceItemAst::SliceItemAst( Ast* parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} -ProperSliceItemAst::ProperSliceItemAst( Ast* parent ) - : SliceItemAst( parent, Ast::ProperSliceItemAst ), stride( 0 ) -{ -} -ExpressionSliceItemAst::ExpressionSliceItemAst( Ast* parent ) - : SliceItemAst( parent, Ast::ExpressionSliceItemAst ), sliceExpression( 0 ) -{ -} -EllipsisSliceItemAst::EllipsisSliceItemAst( Ast* parent ) - : SliceItemAst( parent, Ast::EllipsisSliceItemAst ) -{ -} -CallAst::CallAst( Ast* parent ) - : PrimaryAst( parent, Ast::CallAst ), callable( 0 ), generator( 0 ) -{ -} -ArithmeticExpressionAst::ArithmeticExpressionAst( Ast* parent, Ast::AstType type ) - : ExpressionAst( parent, type ) -{ -} -UnaryExpressionAst::UnaryExpressionAst( Ast* parent ) - : ArithmeticExpressionAst( parent, Ast::UnaryExpressionAst ), operand( 0 ) -{ -} -BinaryExpressionAst::BinaryExpressionAst( Ast* parent ) - : ArithmeticExpressionAst( parent, Ast::BinaryExpressionAst ), lhs( 0 ), rhs( 0 ) -{ -} -ComparisonAst::ComparisonAst( Ast* parent ) - : BooleanOperationAst( parent, Ast::ComparisonAst ), firstComparator( 0 ) -{ -} -BooleanOperationAst::BooleanOperationAst( Ast* parent, Ast::AstType type ) - : ExpressionAst( parent, type ) -{ -} -ExpressionAst::ExpressionAst( Ast* parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} -ConditionalExpressionAst::ConditionalExpressionAst( Ast* parent ) - : ExpressionAst( parent, Ast::ConditionalExpressionAst ), - mainExpression( 0 ), condition( 0 ), elseExpression( 0 ) -{ -} -LambdaAst::LambdaAst( Ast* parent ) - : ExpressionAst( parent, Ast::LambdaAst ), expression( 0 ) -{ -} - -DefaultParameterAst::DefaultParameterAst( Ast * parent ) - : ParameterAst( parent, Ast::DefaultParameterAst ), name( 0 ), value( 0 ) -{ -} - -ParameterPartAst::ParameterPartAst( Ast * parent, Ast::AstType type ) - : Ast( parent, type ) -{ -} - -IdentifierParameterPartAst::IdentifierParameterPartAst( Ast * parent ) - : ParameterPartAst( parent, Ast::IdentifierParameterPartAst ), name( 0 ) -{ -} - -ListParameterPartAst::ListParameterPartAst( Ast * parent ) - : ParameterPartAst( parent, Ast::ListParameterPartAst ) -{ -} - -DictionaryParameterAst::DictionaryParameterAst( Ast * parent ) - : ParameterAst( parent, Ast::DictionaryParameterAst ), name( 0 ) -{ -} - -ListParameterAst::ListParameterAst( Ast * parent ) - : ParameterAst( parent, Ast::ListParameterAst ), name( 0 ) -{ -} - -BooleanNotOperationAst::BooleanNotOperationAst( Ast * parent ) - : BooleanOperationAst( parent, Ast::BooleanNotOperationAst ), op( 0 ) -{ -} - -BooleanOrOperationAst::BooleanOrOperationAst( Ast * parent ) - : BooleanOperationAst( parent, Ast::BooleanOrOperationAst ), lhs( 0 ), rhs( 0 ) -{ -} - -BooleanAndOperationAst::BooleanAndOperationAst( Ast * parent ) - : BooleanOperationAst( parent, Ast::BooleanAndOperationAst ), lhs( 0 ), rhs( 0 ) -{ -} - -IdentifierAst::IdentifierAst( Ast * parent ) - : ExpressionAst( parent, Ast::IdentifierAst ) -{ -} - -LiteralAst::LiteralAst( Ast* parent ) - : Ast( parent, Ast::LiteralAst ) -{ -} - -IdentifierTargetAst::IdentifierTargetAst( Ast * parent ) - : TargetAst( parent, Ast::IdentifierTargetAst ), identifier( 0 ) -{ -} - -TupleTargetAst::TupleTargetAst( Ast * parent ) - : TargetAst( parent, Ast::TupleTargetAst ) -{ -} - -ListTargetAst::ListTargetAst( Ast * parent ) - : TargetAst( parent, Ast::ListTargetAst ) -{ -} - -AttributeReferenceTargetAst::AttributeReferenceTargetAst( Ast * parent ) - : TargetAst( parent, Ast::AttributeReferenceTargetAst ), attribute( 0 ) -{ -} - -SubscriptTargetAst::SubscriptTargetAst( Ast * parent ) - : TargetAst( parent, Ast::SubscriptTargetAst ), subscript( 0 ) -{ -} - -SliceTargetAst::SliceTargetAst( Ast * parent ) - : TargetAst( parent, Ast::SliceTargetAst ), slice( 0 ) -{ -} - - } diff --git a/parser/ast.h b/parser/ast.h index 892ae39..2ab98fe 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -38,890 +38,106 @@ namespace KDevelop namespace Python { - - -class Ast; -class CodeAst; -class FunctionDefinitionAst; -class DecoratorAst; -class ArgumentAst; -class StatementAst; -class IfAst; -class WhileAst; -class ForAst; -class ClassDefinitionAst; -class TryAst; -class ExceptAst; -class WithAst; -class ExecAst; -class GlobalAst; -class ImportAst; -class PlainImportAst; -class StarImportAst; -class FromImportAst; -class RaiseAst; -class PrintAst; -class ReturnAst; -class YieldAst; -class DelAst; -class AssertAst; -class ExpressionStatementAst; -class AssignmentAst; -class TargetAst; -class AtomAst; -class EnclosureAst; -class ListAst; -class ListForAst; -class ListIfAst; -class IdentifierAst; -class ListParameterAst; -class GeneratorAst; -class GeneratorForAst; -class GeneratorIfAst; -class DictionaryAst; -class PrimaryAst; -class AttributeReferenceAst; -class SubscriptAst; -class SliceAst; -class ExtendedSliceAst; -class SimpleSliceAst; -class SliceItemAst; -class ProperSliceItemAst; -class ExpressionSliceAst; -class EllipsisSliceAst; -class CallAst; -class ArithmeticExpressionAst; -class UnaryExpressionAst; -class BinaryExpressionAst; -class ComparisonAst; -class BooleanOperationAst; -class ExpressionAst; -class ConditionalExpressionAst; -class LambdaAst; -class ParameterAst; -class ParameterPartAst; -class DefaultParameterAst; -class IdentifierParameterPartAst; -class ListParameterPartAst; -class DictionaryParameterAst; - -class KDEVPYTHONPARSER_EXPORT KDEVPYTHONPARSER_EXPORT Ast -{ -public: - enum AstType - { - ArgumentAst = 0, - AssertAst = 1, - AssignmentAst = 2, - AtomAst = 3, - AttributeReferenceAst = 4, - AttributeReferenceTargetAst = 5, - BinaryExpressionAst = 6, - BooleanAndOperationAst = 7, - BooleanNotOperationAst = 8, - BooleanOrOperationAst = 9, - BreakAst = 10, - CallAst = 11, - ClassDefinitionAst = 12, - CodeAst = 13, - ComparisonAst = 14, - ConditionalExpressionAst = 15, - ContinueAst = 16, - DecoratorAst = 17, - DefaultParameterAst = 18, - DelAst = 19, - DictionaryAst = 20, - DictionaryParameterAst = 21, - EllipsisSliceItemAst = 22, - EnclosureAst = 23, - ExceptAst = 24, - ExecAst = 25, - ExpressionSliceItemAst = 26, - ExpressionStatementAst = 27, - ExtendedSliceAst = 28, - ForAst = 29, - FromImportAst = 30, - FunctionDefinitionAst = 31, - GeneratorAst = 32, - GeneratorForAst = 33, - GeneratorIfAst = 34, - GlobalAst = 35, - IdentifierAst = 36, - IdentifierParameterPartAst = 37, - IdentifierTargetAst = 38, - IfAst = 39, - LambdaAst = 40, - ListAst = 41, - ListForAst = 42, - ListIfAst = 43, - ListParameterAst = 44, - ListParameterPartAst = 45, - ListTargetAst = 46, - LiteralAst = 47, - PassAst = 48, - PlainImportAst = 49, - PrintAst = 50, - ProperSliceItemAst = 51, - RaiseAst = 52, - ReturnAst = 53, - SimpleSliceAst = 54, - SliceTargetAst = 55, - StarImportAst = 56, - SubscriptAst = 57, - SubscriptTargetAst = 58, - TryAst = 59, - TupleTargetAst = 60, - UnaryExpressionAst = 61, - WhileAst = 62, - WithAst = 63, - YieldAst = 64 - }; - - Ast( Ast* parent, AstType type ); - virtual ~Ast(); - Ast* parent; - AstType astType; - /** - * This is the absolute position in the file that this Ast node starts at. - * - * Counting starts with 0. - */ - qint64 start; - - /** - * This is the absolute position in the file that this Ast node ends at. - * - * Counting starts with 0. - */ - qint64 end; - - /** - * This is the column in the starting line where this Ast node starts. - * - * Counting starts with 0. - */ - qint64 startCol; - - /** - * This is the line where this Ast node starts. - * - * Counting starts with 0. - */ - qint64 startLine; - - /** - * This is the column in the ending line where this Ast node ends. - * - * Counting starts with 0. - */ - qint64 endCol; - - /** - * This is the line where this Ast node ends. - * - * Counting starts with 0. - */ - qint64 endLine; - KDevelop::DUContext* context; -}; - -class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast -{ - -public: - CodeAst(); - QList statements; -}; - -class KDEVPYTHONPARSER_EXPORT StatementAst : public Ast -{ - -public: - StatementAst( Ast*, Ast::AstType type ); -}; - -class KDEVPYTHONPARSER_EXPORT ParameterAst : public Ast -{ -public: - ParameterAst( Ast* parent, Ast::AstType type ); -}; - -class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast -{ - -public: - ExpressionAst( Ast*, Ast::AstType type ); -}; - -class KDEVPYTHONPARSER_EXPORT IdentifierAst : public ExpressionAst -{ -public: - IdentifierAst( Ast* ); - QString identifier; -}; - - -class KDEVPYTHONPARSER_EXPORT ParameterPartAst : public Ast -{ -public: - ParameterPartAst( Ast*, Ast::AstType type ); -}; - - -class KDEVPYTHONPARSER_EXPORT ImportAst : public StatementAst -{ - -public: - ImportAst( Ast*, Ast::AstType type ); -}; - -class KDEVPYTHONPARSER_EXPORT PrimaryAst : public ExpressionAst -{ - -public: - PrimaryAst( Ast*, Ast::AstType type ); -}; - -class KDEVPYTHONPARSER_EXPORT SliceAst : public PrimaryAst -{ - -public: - SliceAst( Ast*, Ast::AstType type ); - Python::PrimaryAst* primary; -}; - - -class KDEVPYTHONPARSER_EXPORT SliceItemAst : public Ast -{ - -public: - SliceItemAst( Ast*, Ast::AstType type ); -}; - - -class KDEVPYTHONPARSER_EXPORT ArithmeticExpressionAst : public ExpressionAst -{ -public: - enum ArithmeticOperation - { - Power, - UnaryPlus, - UnaryMinus, - UnaryTilde, - BinaryPlus, - BinaryMinus, - BinaryMultiply, - BinaryDivide, - BinaryModulo, - BinaryFloor, - BinaryLeftShift, - BinaryRightShift, - BinaryAnd, - BinaryOr, - BinaryXor - }; - - ArithmeticExpressionAst( Ast*, Ast::AstType type ); - ArithmeticOperation opType; -}; - -class KDEVPYTHONPARSER_EXPORT BooleanOperationAst : public ExpressionAst -{ -public: - BooleanOperationAst( Ast* parent, Ast::AstType type ); -}; - - -class KDEVPYTHONPARSER_EXPORT TargetAst : public Ast -{ -public: - TargetAst( Ast*, Ast::AstType ); -}; - -class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst -{ - -public: - FunctionDefinitionAst( Ast* parent ); - Python::IdentifierAst* functionName; - QList parameters; - QList decorators; - QList functionBody; -}; - -class KDEVPYTHONPARSER_EXPORT IdentifierTargetAst : public TargetAst -{ -public: - IdentifierTargetAst( Ast* ); - Python::IdentifierAst* identifier; -}; - -class KDEVPYTHONPARSER_EXPORT TupleTargetAst : public TargetAst -{ -public: - TupleTargetAst( Ast* ); - QList items; -}; - -class KDEVPYTHONPARSER_EXPORT ListTargetAst : public TargetAst -{ -public: - ListTargetAst( Ast* ); - QList items; -}; - -class KDEVPYTHONPARSER_EXPORT AttributeReferenceTargetAst : public TargetAst -{ -public: - AttributeReferenceTargetAst( Ast* ); - Python::AttributeReferenceAst* attribute; -}; - -class KDEVPYTHONPARSER_EXPORT SubscriptTargetAst : public TargetAst -{ -public: - SubscriptTargetAst( Ast* ); - Python::SubscriptAst* subscript; -}; - -class KDEVPYTHONPARSER_EXPORT SliceTargetAst : public TargetAst -{ -public: - SliceTargetAst( Ast* ); - Python::SliceAst* slice; -}; - -class KDEVPYTHONPARSER_EXPORT DecoratorAst : public Ast -{ - -public: - DecoratorAst( Ast* parent ); - QList dottedName; - QList arguments; -}; - -class KDEVPYTHONPARSER_EXPORT ArgumentAst : public Ast -{ - -public: - enum ArgumentType - { - PositionalArgument, - KeywordArgument, - ListArgument, - DictArgument - }; - ArgumentAst( Ast* ); - Python::ExpressionAst* argumentExpression; - Python::IdentifierAst* keywordName; - ArgumentType argumentType; -}; - -class KDEVPYTHONPARSER_EXPORT DefaultParameterAst : public ParameterAst -{ -public: - DefaultParameterAst( Ast* ); - Python::ParameterPartAst* name; - Python::ExpressionAst* value; -}; - - -class KDEVPYTHONPARSER_EXPORT IdentifierParameterPartAst : public ParameterPartAst -{ -public: - IdentifierParameterPartAst( Ast* ); - Python::IdentifierAst* name; -}; - -class KDEVPYTHONPARSER_EXPORT ListParameterPartAst : public ParameterPartAst -{ -public: - ListParameterPartAst( Ast* ); - QList parameternames; -}; - -class KDEVPYTHONPARSER_EXPORT DictionaryParameterAst : public ParameterAst -{ -public: - DictionaryParameterAst( Ast* ); - Python::IdentifierAst* name; -}; - -class KDEVPYTHONPARSER_EXPORT ListParameterAst : public ParameterAst -{ -public: - ListParameterAst( Ast* ); - Python::IdentifierAst* name; -}; - -class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst -{ - -public: - IfAst( Ast* ); - ExpressionAst* ifCondition; - QList ifBody; - QList > > elseIfBodies; - QList elseBody; -}; - -class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst -{ - -public: - WhileAst( Ast* ); - Python::ExpressionAst* condition; - QList whileBody; - QList elseBody; -}; - -class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst -{ - -public: - ForAst( Ast* ); - QList assignedTargets; - QList iterable; - QList forBody; - QList elseBody; -}; - -class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst -{ - -public: - ClassDefinitionAst( Ast* parent ); - Python::IdentifierAst* className; - QList inheritance; - QList classBody; -}; - -class KDEVPYTHONPARSER_EXPORT TryAst : public StatementAst -{ - -public: - TryAst( Ast* ); - QList tryBody; - QList elseBody; - QList finallyBody; - QList exceptions; -}; - -class KDEVPYTHONPARSER_EXPORT ExceptAst : public Ast -{ - -public: - ExceptAst( Ast* ); - Python::ExpressionAst* exceptionDeclaration; - Python::TargetAst* exceptionValue; - QList exceptionBody; -}; - -class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst -{ - -public: - WithAst( Ast* ); - Python::ExpressionAst* context; - Python::TargetAst* name; - QList body; -}; - -class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst -{ - -public: - ExecAst( Ast* ); - Python::ArithmeticExpressionAst* executable; - Python::DictionaryAst* globalsAndLocals; - Python::ExpressionAst* localsOnly; -}; - -class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst -{ - -public: - GlobalAst( Ast* ); - QList identifiers; -}; - -class KDEVPYTHONPARSER_EXPORT PlainImportAst : public ImportAst -{ - -public: - PlainImportAst( Ast* ); - QList< QPair< QList, Python::IdentifierAst*> > modulesAsName; -}; - -class KDEVPYTHONPARSER_EXPORT StarImportAst : public ImportAst -{ - -public: - StarImportAst( Ast* ); - QList modulePath; -}; - -class KDEVPYTHONPARSER_EXPORT FromImportAst : public ImportAst -{ - -public: - FromImportAst( Ast* ); - QList modulePath; - int numLeadingDots; - QList< QPair > identifierAsName; -}; - -class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst -{ - -public: - RaiseAst( Ast* ); - Python::ExpressionAst* exceptionType; - Python::ExpressionAst* exceptionValue; - Python::ExpressionAst* traceback; -}; - -class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst -{ - -public: - PrintAst( Ast* ); - QList printables; - Python::ExpressionAst* outfile; -}; - -class KDEVPYTHONPARSER_EXPORT ReturnAst : public StatementAst -{ - + +class KDEVPYTHONPARSER_EXPORT Identifier { public: - ReturnAst( Ast* ); - QList returnValues; -}; - -class KDEVPYTHONPARSER_EXPORT YieldAst : public StatementAst -{ - -public: - YieldAst( Ast* ); - QList yieldValue; -}; - -class KDEVPYTHONPARSER_EXPORT DelAst : public StatementAst -{ - -public: - DelAst( Ast* ); - QList deleteObjects; -}; - -class KDEVPYTHONPARSER_EXPORT AssertAst : public StatementAst -{ - -public: - AssertAst( Ast* ); - Python::ExpressionAst* assertTest; - Python::ExpressionAst* exceptionValue; -}; - -class KDEVPYTHONPARSER_EXPORT ExpressionStatementAst : public StatementAst -{ - -public: - ExpressionStatementAst( Ast* ); - QList expressions; -}; - -class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst -{ -public: - - enum OpType - { - AddEqualOp, - SubEqualOp, - MultiplyEqualOp, - DivideEqualOp, - ModuloEqualOp, - PowEqualOp, - LeftShiftEqualOp, - RightShiftEqualOp, - XorEqualOp, - OrEqualOp, - AndEqualOp, - FloorEqualOp, - AssignmentOp - }; - AssignmentAst( Ast* ); - QList, OpType > > targets; - QList value; - Python::YieldAst* yieldValue; -}; - -class KDEVPYTHONPARSER_EXPORT LiteralAst : public Ast -{ -public: - enum LiteralType - { - String, - Float, - Integer, - ImaginaryNumber - }; - LiteralAst( Ast* ); + Identifier(QString value); QString value; - LiteralType literalType; }; -class KDEVPYTHONPARSER_EXPORT AtomAst : public PrimaryAst -{ - +// Abstract StatementAst class +class KDEVPYTHONPARSER_EXPORT StatementAst : public Ast { public: - AtomAst( Ast* ); - Python::IdentifierAst* identifier; - Python::LiteralAst* literal; - Python::EnclosureAst* enclosure; + virtual StatementAst(Ast* parent, Ast::AstType type) = 0; }; -class KDEVPYTHONPARSER_EXPORT EnclosureAst : public Ast -{ - +class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { public: - enum EnclosureType - { - ParenthesizedForm, - List, - Generator, - Dictionary, - StringConversion, - Yield - }; - EnclosureAst( Ast* ); - QList parenthesizedform; - Python::ListAst* list; - Python::GeneratorAst* generator; - Python::DictionaryAst* dict; - QList stringConversion; - Python::YieldAst* yield; - EnclosureType encType; + FunctionDefinitionAst(Ast* parent, Ast::AstType type); + IdentifierAst* name; + ArgumentsAst* arguments; }; -class KDEVPYTHONPARSER_EXPORT ListAst : public Ast -{ - +class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst { public: - ListAst( Ast* ); - QList plainList; - Python::ListForAst* listGenerator; + AssignmentAst(Ast* parent, Ast::AstType type); + QList targets; + ExpressionAst* value; }; -class KDEVPYTHONPARSER_EXPORT ListForAst : public Ast -{ - +class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { public: - ListForAst( Ast* ); - QList assignedTargets; - QList iterableObject; - Python::ListForAst* nextGenerator; - Python::ListIfAst* nextCondition; + PrintAst(Ast* parent, AstType type); + ExpressionAst* destination; + QList values; + bool newline; }; -class KDEVPYTHONPARSER_EXPORT ListIfAst : public Ast -{ - +class KDEVPYTHONPARSER_EXPORT PassAst : public StatementAst { public: - ListIfAst( Ast* ); - Python::ExpressionAst* condition; - Python::ListForAst* nextGenerator; - Python::ListIfAst* nextCondition; + PassAst(Ast* parent, AstType type); }; -class KDEVPYTHONPARSER_EXPORT GeneratorAst : public Ast -{ - -public: - GeneratorAst( Ast* ); - Python::ExpressionAst* generatedValue; - Python::GeneratorForAst* generator; -}; - -class KDEVPYTHONPARSER_EXPORT GeneratorForAst : public Ast -{ - -public: - GeneratorForAst( Ast* ); - QList assignedTargets; - Python::ConditionalExpressionAst * iterableObject; - Python::GeneratorForAst* nextGenerator; - Python::GeneratorIfAst* nextCondition; -}; - -class KDEVPYTHONPARSER_EXPORT GeneratorIfAst : public Ast -{ - -public: - GeneratorIfAst( Ast* ); - Python::ExpressionAst* condition; - Python::GeneratorForAst* nextGenerator; - Python::GeneratorIfAst* nextCondition; -}; - -class KDEVPYTHONPARSER_EXPORT DictionaryAst : public Ast -{ - -public: - DictionaryAst( Ast* ); - QMap dictionary; -}; - -class KDEVPYTHONPARSER_EXPORT AttributeReferenceAst : public PrimaryAst -{ - -public: - AttributeReferenceAst( Ast* ); - Python::PrimaryAst* primary; - Python::IdentifierAst* identifier; -}; - -class KDEVPYTHONPARSER_EXPORT SubscriptAst : public PrimaryAst -{ - -public: - SubscriptAst( Ast* ); - Python::PrimaryAst* primary; - QList subscription; -}; - -class KDEVPYTHONPARSER_EXPORT ExtendedSliceAst : public SliceAst -{ - -public: - ExtendedSliceAst( Ast* ); - QList extendedSliceList; -}; - -class KDEVPYTHONPARSER_EXPORT SimpleSliceAst : public SliceAst -{ - -public: - SimpleSliceAst( Ast* ); - QPair simpleSliceBounds; -}; - -class KDEVPYTHONPARSER_EXPORT ProperSliceItemAst : public SliceItemAst -{ - -public: - ProperSliceItemAst( Ast* ); - QPair bounds; - Python::ExpressionAst* stride; -}; - -class KDEVPYTHONPARSER_EXPORT ExpressionSliceItemAst : public SliceItemAst -{ - +class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { public: - ExpressionSliceItemAst( Ast* ); - Python::ExpressionAst* sliceExpression; + virtual ExpressionAst(Ast* parent, AstType type) = 0; + enum Context { + Load, // the object is read + Store, // the object is written + Delete, // the object is deleted + Parameter, // the object is passed as a parameter + AugLoad, AugStore // Apparently not used by python currently, I also dont know what they mean + }; }; -class KDEVPYTHONPARSER_EXPORT EllipsisSliceItemAst : public SliceItemAst -{ - +class KDEVPYTHONPARSER_EXPORT NameAst : public ExpressionAst { public: - EllipsisSliceItemAst( Ast* ); + NameAst(Ast* parent, AstType type); + IdentifierAst* identifier; + ExpressionAst::Context context; }; -class KDEVPYTHONPARSER_EXPORT CallAst : public PrimaryAst -{ - +class KDEVPYTHONPARSER_EXPORT CallAst : public ExpressionAst { public: - CallAst( Ast* ); - Python::PrimaryAst* callable; - QList arguments; - Python::GeneratorAst* generator; + CallAst(Ast* parent, AstType type); + ExpressionAst* function; + QList arguments; + QList keywords; + ExpressionAst* starArguments; + ExpressionAst* keywordArguments; }; - -class KDEVPYTHONPARSER_EXPORT UnaryExpressionAst : public ArithmeticExpressionAst -{ - +class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { public: - UnaryExpressionAst( Ast* ); - Python::ExpressionAst* operand; + AttributeAst(Ast* parent, AstType type); + ExpressionAst* value; + IdentifierAst* attribute; + ExpressionAst::Context context; }; -class KDEVPYTHONPARSER_EXPORT BinaryExpressionAst : public ArithmeticExpressionAst -{ -public: - BinaryExpressionAst( Ast* ); - Python::ExpressionAst* lhs; - Python::ExpressionAst* rhs; -}; -class KDEVPYTHONPARSER_EXPORT ComparisonAst : public BooleanOperationAst +class KDEVPYTHONPARSER_EXPORT Ast { public: - - enum ComparisonOperator + enum AstType { - LessThanOp, - GreaterThanOp, - EqualOp, - UnequalOp, - LessEqualOp, - GreaterEqualOp, - IsOp, - IsNotOp, - InOp, - NotInOp + }; - ComparisonAst( Ast* ); - Python::ExpressionAst* firstComparator; - QList< QPair > comparatorList; -}; -class KDEVPYTHONPARSER_EXPORT BooleanAndOperationAst : public BooleanOperationAst -{ -public: - BooleanAndOperationAst( Ast* ); - Python::BooleanOperationAst* lhs; - Python::BooleanOperationAst* rhs; -}; - -class KDEVPYTHONPARSER_EXPORT BooleanOrOperationAst : public BooleanOperationAst -{ -public: - BooleanOrOperationAst( Ast* ); - Python::BooleanOperationAst* lhs; - Python::BooleanOperationAst* rhs; -}; - -class KDEVPYTHONPARSER_EXPORT BooleanNotOperationAst : public BooleanOperationAst -{ -public: - BooleanNotOperationAst( Ast* ); - Python::BooleanOperationAst* op; -}; - -class KDEVPYTHONPARSER_EXPORT ConditionalExpressionAst : public ExpressionAst -{ - -public: - ConditionalExpressionAst( Ast* ); - Python::BooleanOperationAst* mainExpression; - Python::BooleanOperationAst* condition; - Python::ExpressionAst* elseExpression; -}; - -class KDEVPYTHONPARSER_EXPORT LambdaAst : public ExpressionAst -{ + Ast(Ast* parent, AstType type); + virtual ~Ast(); + Ast* parent; + AstType astType; -public: - LambdaAst( Ast* ); - QList parameters; - Python::ExpressionAst* expression; + qint64 start; + qint64 end; + qint64 startCol; + qint64 startLine; + qint64 endCol; + qint64 endLine; + + KDevelop::DUContext* context; }; } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 6e0ce50..f7edac5 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -28,6 +28,9 @@ #include #include #include +#include "kurl.h" +#include +#include namespace Python { @@ -37,22 +40,75 @@ CodeAst* AstBuilder::parse(KUrl filename) return parseXmlAst(getXmlForFile(filename)); } -QString AstBuilder::getXmlForFile(KUrl filename) const +QString AstBuilder::getXmlForFile(KUrl filename) { - QProcess parser; - parser.start("pythonpythonparser.py", QStringList(filename)); - parser.waitForFinished(); - QString result = parser.readAllStandardOutput(); + QProcess *parser = new QProcess(); + // we call a python script to parse the code for us. It returns an XML string with the AST + parser->start("/home/sven/projects/kde4/python/pythonpythonparser.py", QStringList(filename.path())); // TODO fix this + parser->waitForFinished(); + + if ( parser->error() ) { + kError() << parser->errorString(); + return ""; + } + + QString result = parser->readAllStandardOutput(); kDebug() << "XML for " << filename << ":" << result; + delete parser; return result; } CodeAst* AstBuilder::parseXmlAst(QString xml) { - QDomDocument ast; - ast.setContent(xml); - QDomElement codeAst = ast.documentElement(); - kDebug() << codeAst; + QXmlStreamReader* xmlast = new QXmlStreamReader(); + xmlast->addData(xml); + m_nodeMap = new QMap; + + parseXmlAstNode(xmlast, QXmlStreamReader::Invalid); + + Q_ASSERT(false); +} + +void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token) { + while ( ! xmlast->atEnd() && ! xmlast->hasError() ) { + // Advance to the next (first) token + QXmlStreamReader::TokenType token = xmlast->readNext(); + + // Store everything we need later into local variables + QString currentElementName = xmlast->name().toString(); + QString currentElementText = xmlast->text().toString(); + QList currentElementAttributes = xmlast->attributes().toList(); + + // We ignore startDocument and EndDocument + if ( token == QXmlStreamReader::StartDocument || token == QXmlStreamReader::EndDocument ) { + continue; + } + // We recursively continue parsing if we find another element + else if ( token == QXmlStreamReader::StartElement ) { + parseXmlAstNode(xmlast, token); + } + // Everything else (stuff between tags, comments...) is ignored + else continue; + + // Here we can now assemble an actual node with the attributes extracted above + kDebug() << "Token: " << token << "; " << "Name: " << currentElementName << "; Text: " << currentElementText; + for ( int i=0; i& attributes) +{ + Ast* ast; + switch ( name ) { + case "AssignAst": ast = createAssignmentAst(name, text, attributes); break; + case "NameAst": ast = createIdentifierAst(name, text, attributes); break; + case "StoreAst": break; + default: kError() << "Unknown AST type" << name; + } } } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index d5c214f..a60371b 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -25,6 +25,9 @@ #include "ast.h" #include +#include +#include "kdebug.h" +#include "QXmlStreamReader" namespace PythonParser { @@ -45,7 +48,23 @@ class AstBuilder CodeAst* parse(KUrl filename); private: CodeAst* parseXmlAst(QString xml); - QString getXmlForFile(KUrl filename) const; + QString getXmlForFile(KUrl filename); + void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); + void parseAstNode(QString name, QString text, const QList& attributes); + + QList m_nodeStack; + + template ASTType* createAst(QDomElement* startEnd = 0) { + ASTType* ast = new ASTType(); + if ( startEnd ) { + kDebug() << "would set start end now"; + } + } + + QMap m_nodeMap; + + AssignmentAst* createAssignmentAst(const QList& attributes); + IdentifierAst* createIdentifierAst(const QList& attributes); }; } diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index 403a306..6419f8c 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -40,14 +40,14 @@ ParseSession::~ParseSession() { } -void ParseSession::setCurrentDocument(IndexedString& filename) +void ParseSession::setCurrentDocument(KUrl& filename) { m_currentDocument = filename; } IndexedString ParseSession::currentDocument() { - return m_currentDocument; + return KDevelop::IndexedString(m_currentDocument.fileName()); } @@ -61,7 +61,7 @@ void ParseSession::setContents( const QString& contents ) m_contents = contents; } -bool ParseSession::parse( Python::CodeAst** ast ) +bool ParseSession::parse( Python::CodeAst* ast ) { AstBuilder parser; ast = parser.parse(m_currentDocument); diff --git a/parser/parsesession.h b/parser/parsesession.h index 7942a6f..613bf54 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -31,6 +31,7 @@ #include #include #include "ast.h" +#include "kurl.h" using namespace KDevelop; @@ -50,10 +51,10 @@ class KDEVPYTHONPARSER_EXPORT ParseSession void setContents( const QString& contents ); QString contents() const; - void setCurrentDocument(IndexedString& filename); + void setCurrentDocument(KUrl& filename); IndexedString currentDocument(); - bool parse( Python::CodeAst** ); + bool parse( Python::CodeAst* ); void mapAstUse(Ast* node, const SimpleUse& use) { @@ -63,7 +64,7 @@ class KDEVPYTHONPARSER_EXPORT ParseSession private: QString m_contents; - IndexedString m_currentDocument; + KUrl m_currentDocument; }; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 47347b4..03b67c9 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -102,12 +102,13 @@ void ParseJob::run() readContents(); m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); + m_session->setCurrentDocument(m_url); if ( abortRequested() ) return abortJob(); // 2) parse - bool matched = m_session->parse( &m_ast ); + bool matched = m_session->parse( m_ast ); if ( matched ) { @@ -123,8 +124,7 @@ void ParseJob::run() DeclarationBuilder builder( &editor ); IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); - m_session->setCurrentDocument(filename); - + editor.setParseSession(m_session); m_duContext = builder.build(filename, m_ast); diff --git a/pythonpythonparser.py b/pythonpythonparser.py index c33c76e..de74a1a 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -55,12 +55,13 @@ def generic_visit(self, node): except KeyError: multiple_keys.append('None') key = ','.join(multiple_keys) + node_xmlrepr.setAttribute("NRLST_" + field.lower(), str(key)) else: try: key = self.childNodeMap[value] except KeyError: key = 'None' - node_xmlrepr.setAttribute(field.lower(), str(key)) + node_xmlrepr.setAttribute("NR_" + field.lower(), str(key)) self.currentnode = save_currentnode From 8476a7aebdcba7a5fbd891e534810f2d6280b3f2 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 10:59:10 +0200 Subject: [PATCH 017/118] Re-implemented parts of astvisitor, more AST nodes --- parser/ast.cpp | 25 +- parser/ast.h | 104 ++++-- parser/astdefaultvisitor.cpp | 605 ++--------------------------------- parser/astdefaultvisitor.h | 76 +---- parser/astvisitor.cpp | 87 +---- parser/astvisitor.h | 81 +---- 6 files changed, 166 insertions(+), 812 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 69910b7..016261a 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -23,14 +23,25 @@ namespace Python { -Ast::Ast( Ast* parent, Ast::AstType type ) - : parent(parent), astType( type ) -{ -} +// We never need actual constructors for AST nodes, but it seems to be required, at least for some platforms +// so we provide pseudo implementations +// there's nothing happening here, don't bother reading the code + +Ast::Ast( Ast* parent, Ast::AstType type ) : parent(parent), astType( type ) { } +Ast::~Ast() { } +Identifier::Identifier(QString value) : value(value) { } +FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } +AssignmentAst::AssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } +PrintAst::PrintAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } +AttributeAst::AttributeAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } +CallAst::CallAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } +NameAst::NameAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } +PassAst::PassAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } +ArgumentsAst::ArgumentsAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } +ExpressionAst::ExpressionAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } +KeywordAst::KeywordAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } +StatementAst::StatementAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } -Ast::~Ast() -{ -} } diff --git a/parser/ast.h b/parser/ast.h index 2ab98fe..00d1b44 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -36,6 +36,24 @@ namespace KDevelop class DUContext; } +namespace Python { + class StatementAst; + class FunctionDefinitionAst; + class AssignmentAst; + class PrintAst; + class PassAst; + class ExpressionAst; + class NameAst; + class CallAst; + class AttributeAst; + class ArgumentsAst; + class KeywordAst; + + class ExpressionAst; + class StatementAst; + class Ast; +} + namespace Python { @@ -45,16 +63,56 @@ class KDEVPYTHONPARSER_EXPORT Identifier { QString value; }; -// Abstract StatementAst class +// Base class for all other Abstract Syntax Tree classes +class KDEVPYTHONPARSER_EXPORT Ast +{ +public: + enum AstType + { + FunctionDefinitionAstType, + AssignmentAstType, + PrintAstType, + PassAstType, + ExpressionAstType, + NameAstType, + CallAstType, + AttributeAstType, + ArgumentsAstType, + KeywordAstType, + }; + + Ast(Ast* parent, AstType type); + virtual ~Ast(); + Ast* parent; + AstType astType; + + qint64 start; + qint64 end; + qint64 startCol; + qint64 startLine; + qint64 endCol; + qint64 endLine; + + KDevelop::DUContext* context; +}; + +// this replaces ModuleAst +class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast { +public: + CodeAst(Ast* parent, AstType type); + QList body; +}; + +/** Statement classes **/ class KDEVPYTHONPARSER_EXPORT StatementAst : public Ast { public: - virtual StatementAst(Ast* parent, Ast::AstType type) = 0; + StatementAst(Ast* parent, Ast::AstType type); }; class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { public: FunctionDefinitionAst(Ast* parent, Ast::AstType type); - IdentifierAst* name; + Identifier* name; ArgumentsAst* arguments; }; @@ -78,9 +136,11 @@ class KDEVPYTHONPARSER_EXPORT PassAst : public StatementAst { PassAst(Ast* parent, AstType type); }; + +/** Expression classes **/ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { public: - virtual ExpressionAst(Ast* parent, AstType type) = 0; + ExpressionAst(Ast* parent, AstType type); enum Context { Load, // the object is read Store, // the object is written @@ -93,7 +153,7 @@ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { class KDEVPYTHONPARSER_EXPORT NameAst : public ExpressionAst { public: NameAst(Ast* parent, AstType type); - IdentifierAst* identifier; + Identifier* identifier; ExpressionAst::Context context; }; @@ -111,33 +171,25 @@ class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { public: AttributeAst(Ast* parent, AstType type); ExpressionAst* value; - IdentifierAst* attribute; + Identifier* attribute; ExpressionAst::Context context; }; - -class KDEVPYTHONPARSER_EXPORT Ast -{ +/** Independent classes **/ +class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { public: - enum AstType - { - - }; - - Ast(Ast* parent, AstType type); - virtual ~Ast(); - Ast* parent; - AstType astType; + ArgumentsAst(Ast* parent, AstType type); + QList arguments; + QList defaultValues; + Identifier* vararg; + Identifier* kwarg; +}; - qint64 start; - qint64 end; - qint64 startCol; - qint64 startLine; - qint64 endCol; - qint64 endLine; - - KDevelop::DUContext* context; +class KDEVPYTHONPARSER_EXPORT KeywordAst : public Ast { + KeywordAst(Ast* parent, AstType type); + Identifier* argumentName; + ExpressionAst* value; }; } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 03c4840..e7d2aa9 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -23,607 +23,70 @@ namespace Python { -// TODO: Check which visitXX need a visitNode( node->someIdentifierAst ); - -AstDefaultVisitor::AstDefaultVisitor() - : AstVisitor() -{ -} - -AstDefaultVisitor::~AstDefaultVisitor() -{ -} - -void AstDefaultVisitor::visitCode( CodeAst* code ) -{ - foreach( StatementAst* stmt, code->statements ) - { - visitNode( stmt ); - } -} - -void AstDefaultVisitor::visitFunctionDefinition( FunctionDefinitionAst* node ) -{ - foreach( DecoratorAst* ast, node->decorators ) - { - visitNode( ast ); - } - - visitNode( node->functionName ); - - foreach( ParameterAst* ast, node->parameters ) - { - visitNode( ast ); - } - - foreach( StatementAst* ast, node->functionBody ) - { - visitNode( ast ); - } -} - -void AstDefaultVisitor::visitDecorator( DecoratorAst* node ) -{ - foreach( IdentifierAst* a, node->dottedName ) - { - visitNode( a ); - } - foreach( ArgumentAst* a, node->arguments ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitArgument( ArgumentAst* node ) -{ - visitNode( node->keywordName ); - visitNode( node->argumentExpression ); -} - -void AstDefaultVisitor::visitDefaultParameter( DefaultParameterAst* node ) -{ - visitNode( node->name ); - visitNode( node->value ); -} - -void AstDefaultVisitor::visitIdentifierParameterPart( IdentifierParameterPartAst* node ) -{ - visitNode( node->name ); -} - -void AstDefaultVisitor::visitListParameterPart( ListParameterPartAst* node ) -{ - foreach( ParameterPartAst* a, node->parameternames ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitDictionaryParameter( DictionaryParameterAst* node ) -{ - visitNode( node->name ); -} - -void AstDefaultVisitor::visitListParameter( ListParameterAst* node ) -{ - visitNode( node->name ); -} - -void AstDefaultVisitor::visitIf( IfAst* node ) -{ - visitNode( node->ifCondition ); - foreach( StatementAst* a, node->ifBody ) - { - visitNode( a ); - } - QList > >::const_iterator it = - node->elseIfBodies.begin(); - QList > >::const_iterator end = - node->elseIfBodies.end(); - for( ; it != end; ++it ) - { - QPair > p = *it; - visitNode( p.first ); - foreach( StatementAst* a, p.second ) - { - visitNode( a ); - } - } - foreach( StatementAst* a, node->elseBody ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitWhile( WhileAst* node ) -{ - visitNode( node->condition ); - - foreach( StatementAst* a, node->whileBody ) - { - visitNode( a ); - } - - foreach( StatementAst* a, node->elseBody ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitFor( ForAst* node ) -{ - - foreach( TargetAst* a, node->assignedTargets ) - { - visitNode( a ); - } - - foreach( ExpressionAst* a, node->iterable ) - { - visitNode( a ); - } - - foreach( StatementAst* a, node->forBody ) - { - visitNode( a ); - } - - - foreach( StatementAst* a, node->elseBody ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitClassDefinition( ClassDefinitionAst* node ) -{ - visitNode( node->className ); - foreach( ExpressionAst* a, node->inheritance ) - { - visitNode( a ); - } - foreach( StatementAst* a, node->classBody ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitTry( TryAst* node ) -{ - - foreach( StatementAst* a, node->tryBody ) - { - visitNode( a ); - } - foreach( ExceptAst* a, node->exceptions ) - { - visitNode( a ); - } - - foreach( StatementAst* a, node->elseBody ) - { - visitNode( a ); - } - foreach( StatementAst* a, node->finallyBody ) - { - visitNode( a ); - } -} +AstDefaultVisitor::AstDefaultVisitor() : AstVisitor() { } +AstDefaultVisitor::~AstDefaultVisitor() { } -void AstDefaultVisitor::visitExcept( ExceptAst* node ) -{ - visitNode( node->exceptionDeclaration ); - visitNode( node->exceptionValue ); - foreach( StatementAst* a, node->exceptionBody ) - { - visitNode( a ); - } -} - -void AstDefaultVisitor::visitWith( WithAst* node ) -{ - visitNode( node->context ); - visitNode( node->name ); - foreach( StatementAst* a, node->body ) - { - visitNode( a ); - } -} +// The Ast "ends" here, those dont have child nodes +// note that Identifier is not a node in this Ast +void AstDefaultVisitor::visitName(NameAst* node) { } +void AstDefaultVisitor::visitPass(StatementAst* node) { } -void AstDefaultVisitor::visitExec( ExecAst* node ) -{ - visitNode( node->executable ); - visitNode( node->globalsAndLocals ); - visitNode( node->localsOnly ); -} -void AstDefaultVisitor::visitGlobal( GlobalAst* node ) +void AstDefaultVisitor::visitCode(CodeAst* node) { - foreach( IdentifierAst* a, node->identifiers ) - { - visitNode( a ); + foreach (StatementAst* statement, node->body) { + visitNode(statement); } } -void AstDefaultVisitor::visitPlainImport( PlainImportAst* node ) +void AstDefaultVisitor::visitAssignment(AssignmentAst* node) { - for( int i = 0; i < node->modulesAsName.count(); i++ ) - { - QPair< QList, Python::IdentifierAst*> pair = - node->modulesAsName.at(i); - for( int j = 0; j < pair.first.count(); j++ ) - { - visitNode( pair.first.at(j) ); - } - visitNode( pair.second ); - } + foreach (ExpressionAst* expression, node->targets) { + visitNode(expression); + }; + visitNode(node->value); } -void AstDefaultVisitor::visitStarImport( StarImportAst* node ) +void AstDefaultVisitor::visitPrint(PrintAst* node) { - foreach( IdentifierAst* a, node->modulePath ) - { - visitNode( a ); + visitNode(node->destination); + foreach (ExpressionAst* expression, node->values) { + visitNode(expression); } } -void AstDefaultVisitor::visitFromImport( FromImportAst* node ) +void AstDefaultVisitor::visitCall(CallAst* node) { - foreach( IdentifierAst* a, node->modulePath ) - { - visitNode( a ); - } - for( int i = 0; i < node->identifierAsName.count(); i++ ) - { - visitNode( node->identifierAsName.at(i).first ); - visitNode( node->identifierAsName.at(i).second ); + visitNode(node->function); + visitNode(node->keywordArguments); + visitNode(node->starArguments); + foreach (ExpressionAst* argument, node->arguments) { + visitNode(node->arguments); } + visitNode(node->arguments); } -void AstDefaultVisitor::visitRaise( RaiseAst* node ) +void AstDefaultVisitor::visitFunctionDefinition(FunctionDefinitionAst* node) { - visitNode( node->exceptionType ); - visitNode( node->exceptionValue ); - visitNode( node->traceback ); + visitNode(node->arguments); } -void AstDefaultVisitor::visitPrint( PrintAst* node ) +void AstDefaultVisitor::visitAttribute(AttributeAst* node) { - visitNode( node->outfile ); - foreach( ExpressionAst* a, node->printables ) - { - visitNode( a ); - } + visitNode(node->value); } -void AstDefaultVisitor::visitReturn( ReturnAst* node ) +void AstDefaultVisitor::visitKeyword(KeywordAst* node) { - foreach( ExpressionAst* e, node->returnValues ) - { - visitNode( e ); - } + visitNode(node->value); } -void AstDefaultVisitor::visitYield( YieldAst* node ) +void AstDefaultVisitor::visitArguments(ArgumentsAst* node) { - foreach( ExpressionAst* e, node->yieldValue ) - { - visitNode( e ); + foreach (ExpressionAst* expression, node->arguments) { + visitNode(expression); } } -void AstDefaultVisitor::visitDel( DelAst* node ) -{ - foreach( TargetAst* t, node->deleteObjects ) - { - visitNode( t ); - } -} - -void AstDefaultVisitor::visitAssert( AssertAst* node ) -{ - visitNode( node->assertTest ); - visitNode( node->exceptionValue ); -} - -void AstDefaultVisitor::visitExpressionStatement( ExpressionStatementAst* node ) -{ - foreach( ExpressionAst* e, node->expressions ) - { - visitNode( e ); - } -} - -void AstDefaultVisitor::visitAssignment( AssignmentAst* node ) -{ - QList, AssignmentAst::OpType > >::const_iterator it; - QList, AssignmentAst::OpType > >::const_iterator end; - it = node->targets.begin(); - end = node->targets.end(); - for( ; it != end; ++it ) - { - QList tl = (*it).first; - foreach( TargetAst* t, tl ) - { - visitNode( t ); - } - } - - foreach( ExpressionAst* e, node->value ) - { - visitNode( e ); - } - visitNode( node->yieldValue ); -} - -void AstDefaultVisitor::visitAtom( AtomAst* node ) -{ - visitNode( node->identifier ); - visitNode( node->enclosure ); - visitNode( node->literal ); -} - -void AstDefaultVisitor::visitEnclosure( EnclosureAst* node ) -{ - switch( node->encType ) - { - case EnclosureAst::Dictionary: - visitNode( node->dict ); - break; - case EnclosureAst::Generator: - visitNode( node->generator ); - break; - case EnclosureAst::List: - visitNode( node->list ); - break; - case EnclosureAst::Yield: - visitNode( node->yield ); - break; - case EnclosureAst::ParenthesizedForm: - foreach( ExpressionAst* a, node->parenthesizedform ) - { - visitNode( a ); - } - break; - case EnclosureAst::StringConversion: - foreach( ExpressionAst* a, node->stringConversion ) - { - visitNode( a ); - } - break; - } -} - -void AstDefaultVisitor::visitList( ListAst* node ) -{ - foreach( ExpressionAst* a, node->plainList ) - { - visitNode( a ); - } - visitNode( node->listGenerator ); -} - -void AstDefaultVisitor::visitListFor( ListForAst* node ) -{ - foreach( TargetAst* t, node->assignedTargets ) - { - visitNode( t ); - } - foreach( ExpressionAst* e, node->iterableObject ) - { - visitNode( e ); - } - visitNode( node->nextGenerator ); - visitNode( node->nextCondition ); -} - -void AstDefaultVisitor::visitListIf( ListIfAst* node ) -{ - visitNode( node->condition ); - visitNode( node->nextGenerator ); - visitNode( node->nextCondition ); -} - -void AstDefaultVisitor::visitGenerator( GeneratorAst* node ) -{ - visitNode( node->generatedValue ); - visitNode( node->generator ); -} - -void AstDefaultVisitor::visitGeneratorFor( GeneratorForAst* node ) -{ - foreach( TargetAst* t, node->assignedTargets ) - { - visitNode( t ); - } - visitNode( node->iterableObject ); - visitNode( node->nextGenerator ); - visitNode( node->nextCondition ); -} - -void AstDefaultVisitor::visitGeneratorIf( GeneratorIfAst* node ) -{ - visitNode( node->condition ); - visitNode( node->nextGenerator ); - visitNode( node->nextCondition ); -} - -void AstDefaultVisitor::visitDictionary( DictionaryAst* node ) -{ - foreach( ExpressionAst* key, node->dictionary.keys() ) - { - visitNode( key ); - visitNode( node->dictionary[key] ); - } -} - -void AstDefaultVisitor::visitAttributeReference( AttributeReferenceAst* node ) -{ - visitNode( node->primary ); - visitNode( node->identifier ); -} - -void AstDefaultVisitor::visitSubscript( SubscriptAst* node ) -{ - visitNode( node->primary ); - foreach( ExpressionAst* e, node->subscription ) - { - visitNode( e ); - } -} - -void AstDefaultVisitor::visitExtendedSlice( ExtendedSliceAst* node ) -{ - visitNode( node->primary ); - foreach( SliceItemAst* s, node->extendedSliceList ) - { - visitNode( s ); - } -} - -void AstDefaultVisitor::visitSimpleSlice( SimpleSliceAst* node ) -{ - visitNode( node->primary ); - visitNode( node->simpleSliceBounds.first ); - visitNode( node->simpleSliceBounds.second ); -} - -void AstDefaultVisitor::visitProperSliceItem( ProperSliceItemAst* node ) -{ - visitNode( node->bounds.first ); - visitNode( node->bounds.second ); - visitNode( node->stride ); -} - -void AstDefaultVisitor::visitExpressionSliceItem( ExpressionSliceItemAst* node ) -{ - visitNode( node->sliceExpression ); -} - -void AstDefaultVisitor::visitEllipsisSliceItem( EllipsisSliceItemAst* ) -{ -} - -void AstDefaultVisitor::visitCall( CallAst* node ) -{ - visitNode( node->callable ); - foreach( ArgumentAst* a, node->arguments ) - { - visitNode( a ); - } - visitNode( node->generator ); -} - -void AstDefaultVisitor::visitUnaryExpression( UnaryExpressionAst* node ) -{ - visitNode( node->operand ); -} - -void AstDefaultVisitor::visitBinaryExpression( BinaryExpressionAst* node ) -{ - visitNode( node->lhs ); - visitNode( node->rhs ); -} - -void AstDefaultVisitor::visitComparison( ComparisonAst* node ) -{ - visitNode( node->firstComparator ); - QList< QPair< ComparisonAst::ComparisonOperator, ExpressionAst*> >::iterator it; - QList< QPair< ComparisonAst::ComparisonOperator, ExpressionAst*> >::iterator end = node->comparatorList.end(); - for( it = node->comparatorList.begin(); it != end; ++it ) - { - visitNode( (*it).second ); - } -} - -void AstDefaultVisitor::visitBooleanNotOperation( BooleanNotOperationAst* node ) -{ - visitNode( node->op ); -} - -void AstDefaultVisitor::visitBooleanOrOperation( BooleanOrOperationAst* node ) -{ - visitNode( node->lhs ); - visitNode( node->rhs ); -} - -void AstDefaultVisitor::visitBooleanAndOperation( BooleanAndOperationAst* node ) -{ - visitNode( node->lhs ); - visitNode( node->rhs ); -} - -void AstDefaultVisitor::visitConditionalExpression( ConditionalExpressionAst* node ) -{ - visitNode( node->mainExpression ); - visitNode( node->condition ); - visitNode( node->elseExpression ); -} - -void AstDefaultVisitor::visitLambda( LambdaAst* node ) -{ - foreach( ParameterAst* p, node->parameters ) - { - visitNode( p ); - } - visitNode( node->expression ); -} - -void AstDefaultVisitor::visitPass( StatementAst* ) -{ -} - -void AstDefaultVisitor::visitContinue( StatementAst* ) -{ -} - -void AstDefaultVisitor::visitBreak( StatementAst* ) -{ -} - -void AstDefaultVisitor::visitIdentifier( IdentifierAst * ) -{ -} - -void AstDefaultVisitor::visitLiteral( LiteralAst * ) -{ -} - -void AstDefaultVisitor::visitIdentifierTarget( IdentifierTargetAst * ast ) -{ - visitNode( ast->identifier ); -} - -void AstDefaultVisitor::visitListTarget( ListTargetAst * ast ) -{ - foreach( Python::TargetAst* t, ast->items ) - { - visitNode( t ); - } -} - -void AstDefaultVisitor::visitTupleTarget( TupleTargetAst * ast ) -{ - foreach( Python::TargetAst* t, ast->items ) - { - visitNode( t ); - } -} - -void AstDefaultVisitor::visitAttributeReferenceTarget( AttributeReferenceTargetAst * ast ) -{ - visitNode( ast->attribute ); -} - -void AstDefaultVisitor::visitSubscriptTarget( SubscriptTargetAst * ast ) -{ - visitNode( ast->subscript ); -} - -void AstDefaultVisitor::visitSliceTarget( SliceTargetAst * ast ) -{ - visitNode( ast->slice ); -} - } diff --git a/parser/astdefaultvisitor.h b/parser/astdefaultvisitor.h index 451d47a..d31e4cb 100644 --- a/parser/astdefaultvisitor.h +++ b/parser/astdefaultvisitor.h @@ -33,72 +33,16 @@ class KDEVPYTHONPARSER_EXPORT AstDefaultVisitor : public AstVisitor AstDefaultVisitor(); virtual ~AstDefaultVisitor(); - virtual void visitCode( CodeAst* ); - virtual void visitFunctionDefinition( FunctionDefinitionAst* ); - virtual void visitDecorator( DecoratorAst* ); - virtual void visitArgument( ArgumentAst* ); - virtual void visitDefaultParameter( DefaultParameterAst* ); - virtual void visitIdentifierParameterPart( IdentifierParameterPartAst* ); - virtual void visitListParameterPart( ListParameterPartAst* ); - virtual void visitDictionaryParameter( DictionaryParameterAst* ); - virtual void visitListParameter( ListParameterAst* ); - virtual void visitIf( IfAst* ); - virtual void visitWhile( WhileAst* ); - virtual void visitFor( ForAst* ); - virtual void visitClassDefinition( ClassDefinitionAst* ); - virtual void visitTry( TryAst* ); - virtual void visitExcept( ExceptAst* ); - virtual void visitWith( WithAst* ); - virtual void visitExec( ExecAst* ); - virtual void visitGlobal( GlobalAst* ); - virtual void visitPlainImport( PlainImportAst* ); - virtual void visitStarImport( StarImportAst* ); - virtual void visitFromImport( FromImportAst* ); - virtual void visitRaise( RaiseAst* ); - virtual void visitPrint( PrintAst* ); - virtual void visitReturn( ReturnAst* ); - virtual void visitYield( YieldAst* ); - virtual void visitDel( DelAst* ); - virtual void visitAssert( AssertAst* ); - virtual void visitExpressionStatement( ExpressionStatementAst* ); - virtual void visitAssignment( AssignmentAst* ); - virtual void visitAtom( AtomAst* ); - virtual void visitEnclosure( EnclosureAst* ); - virtual void visitList( ListAst* ); - virtual void visitListFor( ListForAst* ); - virtual void visitListIf( ListIfAst* ); - virtual void visitLiteral( LiteralAst* ); - virtual void visitGenerator( GeneratorAst* ); - virtual void visitGeneratorFor( GeneratorForAst* ); - virtual void visitGeneratorIf( GeneratorIfAst* ); - virtual void visitDictionary( DictionaryAst* ); - virtual void visitAttributeReference( AttributeReferenceAst* ); - virtual void visitSubscript( SubscriptAst* ); - virtual void visitExtendedSlice( ExtendedSliceAst* ); - virtual void visitSimpleSlice( SimpleSliceAst* ); - virtual void visitProperSliceItem( ProperSliceItemAst* ); - virtual void visitExpressionSliceItem( ExpressionSliceItemAst* ); - virtual void visitEllipsisSliceItem( EllipsisSliceItemAst* ); - virtual void visitCall( CallAst* ); - virtual void visitUnaryExpression( UnaryExpressionAst* ); - virtual void visitBinaryExpression( BinaryExpressionAst* ); - virtual void visitComparison( ComparisonAst* ); - virtual void visitBooleanNotOperation( BooleanNotOperationAst* ); - virtual void visitBooleanAndOperation( BooleanAndOperationAst* ); - virtual void visitBooleanOrOperation( BooleanOrOperationAst* ); - virtual void visitConditionalExpression( ConditionalExpressionAst* ); - virtual void visitLambda( LambdaAst* ); - virtual void visitBreak( StatementAst* ); - virtual void visitContinue( StatementAst* ); - virtual void visitPass( StatementAst* ); - virtual void visitIdentifier( IdentifierAst* ); - virtual void visitIdentifierTarget( IdentifierTargetAst* ); - virtual void visitListTarget( ListTargetAst* ); - virtual void visitTupleTarget( TupleTargetAst* ); - virtual void visitAttributeReferenceTarget( AttributeReferenceTargetAst* ); - virtual void visitSubscriptTarget( SubscriptTargetAst* ); - virtual void visitSliceTarget( SliceTargetAst* ); - + virtual void visitCode(CodeAst* node); + virtual void visitFunctionDefinition(FunctionDefinitionAst* node); + virtual void visitPrint(PrintAst* node); + virtual void visitAssignment(AssignmentAst* node); + virtual void visitCall(CallAst* node); + virtual void visitPass(StatementAst* node); + virtual void visitName(NameAst* node); + virtual void visitAttribute(AttributeAst* node); + virtual void visitKeyword(KeywordAst* node); + virtual void visitArguments(ArgumentsAst* node); }; } diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index f02bd87..44c21a2 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -23,81 +23,20 @@ namespace Python { -AstVisitor::visitFunc _S_parser_table[] = { - - reinterpret_cast(&AstVisitor::visitArgument), - reinterpret_cast(&AstVisitor::visitAssert), - reinterpret_cast(&AstVisitor::visitAssignment), - reinterpret_cast(&AstVisitor::visitAtom), - reinterpret_cast(&AstVisitor::visitAttributeReference), - reinterpret_cast(&AstVisitor::visitAttributeReferenceTarget), - reinterpret_cast(&AstVisitor::visitBinaryExpression), - reinterpret_cast(&AstVisitor::visitBooleanNotOperation), - reinterpret_cast(&AstVisitor::visitBooleanAndOperation), - reinterpret_cast(&AstVisitor::visitBooleanOrOperation), - reinterpret_cast(&AstVisitor::visitBreak), - reinterpret_cast(&AstVisitor::visitCall), - reinterpret_cast(&AstVisitor::visitClassDefinition), - reinterpret_cast(&AstVisitor::visitCode), - reinterpret_cast(&AstVisitor::visitComparison), - reinterpret_cast(&AstVisitor::visitConditionalExpression), - reinterpret_cast(&AstVisitor::visitContinue), - reinterpret_cast(&AstVisitor::visitDecorator), - reinterpret_cast(&AstVisitor::visitDefaultParameter), - reinterpret_cast(&AstVisitor::visitDel), - reinterpret_cast(&AstVisitor::visitDictionary), - reinterpret_cast(&AstVisitor::visitDictionaryParameter), - reinterpret_cast(&AstVisitor::visitEllipsisSliceItem), - reinterpret_cast(&AstVisitor::visitEnclosure), - reinterpret_cast(&AstVisitor::visitExcept), - reinterpret_cast(&AstVisitor::visitExec), - reinterpret_cast(&AstVisitor::visitExpressionSliceItem), - reinterpret_cast(&AstVisitor::visitExpressionStatement), - reinterpret_cast(&AstVisitor::visitExtendedSlice), - reinterpret_cast(&AstVisitor::visitFor), - reinterpret_cast(&AstVisitor::visitFromImport), - reinterpret_cast(&AstVisitor::visitFunctionDefinition), - reinterpret_cast(&AstVisitor::visitGenerator), - reinterpret_cast(&AstVisitor::visitGeneratorFor), - reinterpret_cast(&AstVisitor::visitGeneratorIf), - reinterpret_cast(&AstVisitor::visitGlobal), - reinterpret_cast(&AstVisitor::visitIdentifier), - reinterpret_cast(&AstVisitor::visitIdentifierParameterPart), - reinterpret_cast(&AstVisitor::visitIdentifierTarget), - reinterpret_cast(&AstVisitor::visitIf), - reinterpret_cast(&AstVisitor::visitLambda), - reinterpret_cast(&AstVisitor::visitList), - reinterpret_cast(&AstVisitor::visitListFor), - reinterpret_cast(&AstVisitor::visitListIf), - reinterpret_cast(&AstVisitor::visitListParameter), - reinterpret_cast(&AstVisitor::visitListParameterPart), - reinterpret_cast(&AstVisitor::visitListTarget), - reinterpret_cast(&AstVisitor::visitLiteral), - reinterpret_cast(&AstVisitor::visitPass), - reinterpret_cast(&AstVisitor::visitPlainImport), - reinterpret_cast(&AstVisitor::visitPrint), - reinterpret_cast(&AstVisitor::visitProperSliceItem), - reinterpret_cast(&AstVisitor::visitRaise), - reinterpret_cast(&AstVisitor::visitReturn), - reinterpret_cast(&AstVisitor::visitSimpleSlice), - reinterpret_cast(&AstVisitor::visitSliceTarget), - reinterpret_cast(&AstVisitor::visitStarImport), - reinterpret_cast(&AstVisitor::visitSubscript), - reinterpret_cast(&AstVisitor::visitSubscriptTarget), - reinterpret_cast(&AstVisitor::visitTupleTarget), - reinterpret_cast(&AstVisitor::visitTry), - reinterpret_cast(&AstVisitor::visitUnaryExpression), - reinterpret_cast(&AstVisitor::visitWhile), - reinterpret_cast(&AstVisitor::visitWith), - reinterpret_cast(&AstVisitor::visitYield), - - -}; - -void AstVisitor::visitNode( Ast* node ) +void AstVisitor::visitNode(Ast* node) { - if (node) - (this->*_S_parser_table[node->astType])(node); + if ( ! node ) return; + switch ( node->astType ) { + case Ast::ArgumentsAstType: AstVisitor::visitArguments(node); break; + case Ast::AssignmentAstType: AstVisitor::visitAssignment(node); break; + case Ast::AttributeAstType: AstVisitor::visitAttribute(node); break; + case Ast::CallAstType: AstVisitor::visitCall(node); break; + case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(node); break; + case Ast::KeywordAstType: AstVisitor::visitKeyword(node); break; + case Ast::NameAstType: AstVisitor::visitName(node); break; + case Ast::PassAstType: AstVisitor::visitPass(node); break; + case Ast::PrintAstType: AstVisitor::visitPrint(node); break; + } } } diff --git a/parser/astvisitor.h b/parser/astvisitor.h index 04b27ec..b6e1845 100644 --- a/parser/astvisitor.h +++ b/parser/astvisitor.h @@ -33,74 +33,19 @@ class KDEVPYTHONPARSER_EXPORT AstVisitor virtual ~AstVisitor() {} typedef void (AstVisitor::*visitFunc)(Ast *); - - virtual void visitNode( Ast* ); - - virtual void visitCode( CodeAst* ) = 0; - virtual void visitFunctionDefinition( FunctionDefinitionAst* ) = 0; - virtual void visitDecorator( DecoratorAst* ) = 0; - virtual void visitArgument( ArgumentAst* ) = 0; - virtual void visitDefaultParameter( DefaultParameterAst* ) = 0; - virtual void visitIdentifierParameterPart( IdentifierParameterPartAst* ) = 0; - virtual void visitListParameterPart( ListParameterPartAst* ) = 0; - virtual void visitDictionaryParameter( DictionaryParameterAst* ) = 0; - virtual void visitListParameter( ListParameterAst* ) = 0; - virtual void visitIf( IfAst* ) = 0; - virtual void visitWhile( WhileAst* ) = 0; - virtual void visitFor( ForAst* ) = 0; - virtual void visitClassDefinition( ClassDefinitionAst* ) = 0; - virtual void visitTry( TryAst* ) = 0; - virtual void visitExcept( ExceptAst* ) = 0; - virtual void visitWith( WithAst* ) = 0; - virtual void visitExec( ExecAst* ) = 0; - virtual void visitGlobal( GlobalAst* ) = 0; - virtual void visitPlainImport( PlainImportAst* ) = 0; - virtual void visitStarImport( StarImportAst* ) = 0; - virtual void visitFromImport( FromImportAst* ) = 0; - virtual void visitRaise( RaiseAst* ) = 0; - virtual void visitPrint( PrintAst* ) = 0; - virtual void visitReturn( ReturnAst* ) = 0; - virtual void visitYield( YieldAst* ) = 0; - virtual void visitDel( DelAst* ) = 0; - virtual void visitAssert( AssertAst* ) = 0; - virtual void visitExpressionStatement( ExpressionStatementAst* ) = 0; - virtual void visitAssignment( AssignmentAst* ) = 0; - virtual void visitAtom( AtomAst* ) = 0; - virtual void visitEnclosure( EnclosureAst* ) = 0; - virtual void visitList( ListAst* ) = 0; - virtual void visitListFor( ListForAst* ) = 0; - virtual void visitListIf( ListIfAst* ) = 0; - virtual void visitLiteral( LiteralAst* ) = 0; - virtual void visitGenerator( GeneratorAst* ) = 0; - virtual void visitGeneratorFor( GeneratorForAst* ) = 0; - virtual void visitGeneratorIf( GeneratorIfAst* ) = 0; - virtual void visitDictionary( DictionaryAst* ) = 0; - virtual void visitAttributeReference( AttributeReferenceAst* ) = 0; - virtual void visitSubscript( SubscriptAst* ) = 0; - virtual void visitExtendedSlice( ExtendedSliceAst* ) = 0; - virtual void visitSimpleSlice( SimpleSliceAst* ) = 0; - virtual void visitProperSliceItem( ProperSliceItemAst* ) = 0; - virtual void visitExpressionSliceItem( ExpressionSliceItemAst* ) = 0; - virtual void visitEllipsisSliceItem( EllipsisSliceItemAst* ) = 0; - virtual void visitCall( CallAst* ) = 0; - virtual void visitUnaryExpression( UnaryExpressionAst* ) = 0; - virtual void visitBinaryExpression( BinaryExpressionAst* ) = 0; - virtual void visitComparison( ComparisonAst* ) = 0; - virtual void visitBooleanNotOperation( BooleanNotOperationAst* ) = 0; - virtual void visitBooleanAndOperation( BooleanAndOperationAst* ) = 0; - virtual void visitBooleanOrOperation( BooleanOrOperationAst* ) = 0; - virtual void visitConditionalExpression( ConditionalExpressionAst* ) = 0; - virtual void visitLambda( LambdaAst* ) = 0; - virtual void visitBreak( StatementAst* ) = 0; - virtual void visitContinue( StatementAst* ) = 0; - virtual void visitPass( StatementAst* ) = 0; - virtual void visitIdentifier( IdentifierAst* ) = 0; - virtual void visitIdentifierTarget( IdentifierTargetAst* ) = 0; - virtual void visitListTarget( ListTargetAst* ) = 0; - virtual void visitTupleTarget( TupleTargetAst* ) = 0; - virtual void visitAttributeReferenceTarget( AttributeReferenceTargetAst* ) = 0; - virtual void visitSubscriptTarget( SubscriptTargetAst* ) = 0; - virtual void visitSliceTarget( SliceTargetAst* ) = 0; + + void visitNode(Ast* node); + + virtual void visitCode(CodeAst* node); + virtual void visitFunctionDefinition(FunctionDefinitionAst* node); + virtual void visitPrint(PrintAst* node); + virtual void visitAssignment(AssignmentAst* node); + virtual void visitCall(CallAst* node); + virtual void visitPass(StatementAst* node); + virtual void visitName(NameAst* node); + virtual void visitAttribute(AttributeAst* node); + virtual void visitKeyword(KeywordAst* node); + virtual void visitArguments(ArgumentsAst* node); }; } From 3a38f88eff735a792556086cdf41e159f1835df9 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 11:36:40 +0200 Subject: [PATCH 018/118] Fixed a lot of build errors, added Enums --- parser/ast.h | 91 +++++++++++++++++++++++++++++++++++- parser/astbuilder.cpp | 28 +++++++---- parser/astbuilder.h | 4 +- parser/astdefaultvisitor.cpp | 6 +-- parser/astvisitor.cpp | 23 +++++---- parser/astvisitor.h | 23 ++++----- 6 files changed, 141 insertions(+), 34 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index 00d1b44..a804bcb 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -79,7 +79,95 @@ class KDEVPYTHONPARSER_EXPORT Ast AttributeAstType, ArgumentsAstType, KeywordAstType, + ClassDefinitionAstType, + ReturnAstType, + DeleteAstType, + AugAssignAstType, + ForAstType, + WhileAstType, + IfAstType, + WithAstType, + RaiseAstType, + TryExceptAstType, + TryFinallyAstType, + AssertAstType, + ImportAstType, + ImportFromAstType, + ExecAstType, + GlobalAstType, + ExprAstType, + BreakAstType, + ContinueAstType, + AttributesAstType, + + BooleanOperationAstType, + BinaryOperationAstType, + UnaryOperationAstType, + LambdaAstType, + IfExpAstType, + DictAstType, + SetAstType, + ListComprehensionAstType, + SetComprehensionAstType, + DictComprehensionAstType, + GeneratorExpressionAstType, + YieldAstType, + CompareAstType, + ReprAstType, + NumberAstType, + StringAstType, + SubscriptAstType, + ListAstType, + TupleAstType, + + SliceAstType, + EllipsisAstType, + IndexAstType, + + ComprehensionAstType, + ExceptionHandlerAstType, + AliasAstType // for imports }; + + enum BooleanOperationTypes { + BooleanAnd, + BooleanOr + }; + + enum OperatorTypes { + OperatorAdd, + OperatorSub, + OperatorMult, + OperatorDiv, + OperatorMod, + OperatorPow, + OperatorLeftShift, + OperatorRightShift, + OperatorBitwiseOr, + OperatorBitwiseXor, + OperatorBitwiseAnd, + OperatorFloorDivision + }; + + enum UnaryOperatorTypes { + UnaryOperatorInvert, + UnaryOperatorNot, + UnaryOperatorAdd, + UnaryOperatorSub + }; + + enum ComparisionOperatorTypes { + ComparisonOperatorEquals, + ComparisonOperatorNotEquals, + ComparisonOperatorLessThan, + ComparisonOperatorLessThanEqual, + ComparisonOperatorGreaterThan, + ComparisonOperatorGreaterThanEqual, + ComparisonOperatorIs, + ComparisonOperatorIsNot, + ComparisonOperatorIn, + ComparisonOperatorNotIn + } Ast(Ast* parent, AstType type); virtual ~Ast(); @@ -127,7 +215,7 @@ class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { public: PrintAst(Ast* parent, AstType type); ExpressionAst* destination; - QList values; + QList values; bool newline; }; @@ -187,6 +275,7 @@ class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { }; class KDEVPYTHONPARSER_EXPORT KeywordAst : public Ast { +public: KeywordAst(Ast* parent, AstType type); Identifier* argumentName; ExpressionAst* value; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index f7edac5..7c3147a 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -42,7 +42,7 @@ CodeAst* AstBuilder::parse(KUrl filename) QString AstBuilder::getXmlForFile(KUrl filename) { - QProcess *parser = new QProcess(); + QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST parser->start("/home/sven/projects/kde4/python/pythonpythonparser.py", QStringList(filename.path())); // TODO fix this parser->waitForFinished(); @@ -62,14 +62,15 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) { QXmlStreamReader* xmlast = new QXmlStreamReader(); xmlast->addData(xml); - m_nodeMap = new QMap; + + m_nodeMap.clear(); parseXmlAstNode(xmlast, QXmlStreamReader::Invalid); Q_ASSERT(false); } -void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token) { +void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) { while ( ! xmlast->atEnd() && ! xmlast->hasError() ) { // Advance to the next (first) token QXmlStreamReader::TokenType token = xmlast->readNext(); @@ -103,13 +104,24 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok void AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes) { Ast* ast; - switch ( name ) { - case "AssignAst": ast = createAssignmentAst(name, text, attributes); break; - case "NameAst": ast = createIdentifierAst(name, text, attributes); break; - case "StoreAst": break; - default: kError() << "Unknown AST type" << name; + + QMap attributeDict; + for ( int i=0; i& attributes) +{ + +} + } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index a60371b..366bc11 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -63,8 +63,8 @@ class AstBuilder QMap m_nodeMap; - AssignmentAst* createAssignmentAst(const QList& attributes); - IdentifierAst* createIdentifierAst(const QList& attributes); + AssignmentAst* createAssignmentAst(const QMap& attributes); + Identifier* createIdentifier(const QMap& attributes); }; } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index e7d2aa9..4905b36 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -19,11 +19,12 @@ ***************************************************************************/ #include "astdefaultvisitor.h" +#include "ast.h" namespace Python { -AstDefaultVisitor::AstDefaultVisitor() : AstVisitor() { } +AstDefaultVisitor::AstDefaultVisitor() { } AstDefaultVisitor::~AstDefaultVisitor() { } // The Ast "ends" here, those dont have child nodes @@ -61,9 +62,8 @@ void AstDefaultVisitor::visitCall(CallAst* node) visitNode(node->keywordArguments); visitNode(node->starArguments); foreach (ExpressionAst* argument, node->arguments) { - visitNode(node->arguments); + visitNode(argument); } - visitNode(node->arguments); } void AstDefaultVisitor::visitFunctionDefinition(FunctionDefinitionAst* node) diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index 44c21a2..4d07c6c 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -22,20 +22,25 @@ namespace Python { + +AstVisitor::AstVisitor() { } +AstVisitor::~AstVisitor() { } + void AstVisitor::visitNode(Ast* node) { if ( ! node ) return; switch ( node->astType ) { - case Ast::ArgumentsAstType: AstVisitor::visitArguments(node); break; - case Ast::AssignmentAstType: AstVisitor::visitAssignment(node); break; - case Ast::AttributeAstType: AstVisitor::visitAttribute(node); break; - case Ast::CallAstType: AstVisitor::visitCall(node); break; - case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(node); break; - case Ast::KeywordAstType: AstVisitor::visitKeyword(node); break; - case Ast::NameAstType: AstVisitor::visitName(node); break; - case Ast::PassAstType: AstVisitor::visitPass(node); break; - case Ast::PrintAstType: AstVisitor::visitPrint(node); break; + case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; + case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; + case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; + case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; + case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; + case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; + case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; + case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; + case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; + case Ast::ExpressionAstType: break; } } diff --git a/parser/astvisitor.h b/parser/astvisitor.h index b6e1845..38ddce3 100644 --- a/parser/astvisitor.h +++ b/parser/astvisitor.h @@ -30,22 +30,23 @@ namespace Python class KDEVPYTHONPARSER_EXPORT AstVisitor { public: - virtual ~AstVisitor() {} + AstVisitor(); + virtual ~AstVisitor(); typedef void (AstVisitor::*visitFunc)(Ast *); void visitNode(Ast* node); - virtual void visitCode(CodeAst* node); - virtual void visitFunctionDefinition(FunctionDefinitionAst* node); - virtual void visitPrint(PrintAst* node); - virtual void visitAssignment(AssignmentAst* node); - virtual void visitCall(CallAst* node); - virtual void visitPass(StatementAst* node); - virtual void visitName(NameAst* node); - virtual void visitAttribute(AttributeAst* node); - virtual void visitKeyword(KeywordAst* node); - virtual void visitArguments(ArgumentsAst* node); + virtual void visitCode(CodeAst* node) { Q_UNUSED(node); }; + virtual void visitFunctionDefinition(FunctionDefinitionAst* node) { Q_UNUSED(node); }; + virtual void visitPrint(PrintAst* node) { Q_UNUSED(node); }; + virtual void visitAssignment(AssignmentAst* node) { Q_UNUSED(node); }; + virtual void visitCall(CallAst* node) { Q_UNUSED(node); }; + virtual void visitPass(StatementAst* node) { Q_UNUSED(node); }; + virtual void visitName(NameAst* node) { Q_UNUSED(node); }; + virtual void visitAttribute(AttributeAst* node) { Q_UNUSED(node); }; + virtual void visitKeyword(KeywordAst* node) { Q_UNUSED(node); }; + virtual void visitArguments(ArgumentsAst* node) { Q_UNUSED(node); }; }; } From 7a177c194727953f10b604ed5abd2c17d1a6f605 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 12:25:54 +0200 Subject: [PATCH 019/118] Modelled the whole AST after the official grammar file --- parser/ast.h | 319 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 3 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index a804bcb..91ecdb1 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -104,7 +104,7 @@ class KDEVPYTHONPARSER_EXPORT Ast BinaryOperationAstType, UnaryOperationAstType, LambdaAstType, - IfExpAstType, + IfExpressionAstType, // the short one, if a then b else c DictAstType, SetAstType, ListComprehensionAstType, @@ -156,7 +156,7 @@ class KDEVPYTHONPARSER_EXPORT Ast UnaryOperatorSub }; - enum ComparisionOperatorTypes { + enum ComparisonOperatorTypes { ComparisonOperatorEquals, ComparisonOperatorNotEquals, ComparisonOperatorLessThan, @@ -204,6 +204,27 @@ class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { ArgumentsAst* arguments; }; +class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { +public: + ClassDefinitionAst(Ast* parent, AstType type); + Identifier* name; + QList baseClasses; + QList body; + QList decorators; +}; + +class KDEVPYTHONPARSER_EXPORT ReturnAst : public StatementAst { +public: + ReturnAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT DeleteAst : public StatementAst { +public: + DeleteAst(Ast* parent, AstType type); + QList targets; +}; + class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst { public: AssignmentAst(Ast* parent, Ast::AstType type); @@ -211,6 +232,115 @@ class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst { ExpressionAst* value; }; +class KDEVPYTHONPARSER_EXPORT AugmentedAssignmentAst : public StatementAst { +public: + AugmentedAssignmentAst(Ast* parent, AstType type); + ExpressionAst* target; + Ast::OperatorTypes op; + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { +public: + ForAst(Ast* parent, AstType type); + ExpressionAst* target; + ExpressionAst* iterator; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst { +public: + WhileAst(Ast* parent, AstType type); + ExpressionAst* condition; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst { +public: + IfAst(Ast* parent, AstType type); + ExpressionAst* condition; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { +public: + WithAst(Ast* parent, AstType type); + ExpressionAst* contextExpression; + ExpressionAst* optionalVars; + QList body; +}; + +class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst { +public: + RaiseAst(Ast* parent, AstType type); + ExpressionAst* type; + // TODO check what the other things in the grammar actually are and add them +}; + +class KDEVPYTHONPARSER_EXPORT TryExceptAst : public StatementAst { +public: + TryExceptAst(Ast* parent, AstType type); + QList body; + QList handlers; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT TryFinallyAst : public StatementAst { +public: + TryFinallyAst(Ast* parent, AstType type); + QList body; + QList finalbody; +}; + +class KDEVPYTHONPARSER_EXPORT AssertionAst : public StatementAst { +public: + AssertionAst(Ast* parent, AstType type); + ExpressionAst* condition; + ExpressionAst* message; +}; + +class KDEVPYTHONPARSER_EXPORT ImportAst : public StatementAst { +public: + ImportAst(Ast* parent, AstType type); + QList names; +}; + +class KDEVPYTHONPARSER_EXPORT ImportFromAst : public StatementAst { +public: + ImportFromAst(Ast* parent, AstType type); + Identifier* module; + QList names; + int level; +}; + +class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst { +public: + ExecAst(Ast* parent, AstType type); + ExpressionAst* body; + ExpressionAst* globals; + ExpressionAst* locals; +}; + +class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst { +public: + QList name; +}; + +// TODO what's stmt::Expr(expr value) in the grammar and what do we need it for? + +class KDEVPYTHONPARSER_EXPORT BreakAst : public StatementAst { +public: + BreakAst(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT ContinueAst : public StatementAst { +public: + ContinueAst(Ast* parent, AstType type); +}; + class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { public: PrintAst(Ast* parent, AstType type); @@ -234,10 +364,120 @@ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { Store, // the object is written Delete, // the object is deleted Parameter, // the object is passed as a parameter - AugLoad, AugStore // Apparently not used by python currently, I also dont know what they mean + AugLoad, AugStore // Augmented assignments, like a += 1 }; }; +class KDEVPYTHONPARSER_EXPORT BooleanOperationAst : public ExpressionAst { +public: + BooleanOperationAst(Ast* parent, AstType type); + Ast::BooleanOperationTypes type; + QList values; +}; + +class KDEVPYTHONPARSER_EXPORT BinaryOperationAst : public ExpressionAst { +public: + BinaryOperationAst(Ast* parent, AstType type); + Ast::OperatorTypes type; + ExpressionAst* lhs; + ExpressionAst* rhs; +}; + +class KDEVPYTHONPARSER_EXPORT UnaryOperationAst : public ExpressionAst { +public: + UnaryOperationAst(Ast* parent, AstType type); + Ast::UnaryOperatorTypes type; + ExpressionAst* operand; +}; + +class KDEVPYTHONPARSER_EXPORT LambdaAst : public ExpressionAst { +public: + LambdaAst(Ast* parent, AstType type); + ArgumentsAst* arguments; + ExpressionAst* body; +}; + +class KDEVPYTHONPARSER_EXPORT IfExpressionAst : public ExpressionAst { +public: + IfExpressionAst(Ast* parent, AstType type); + ExpressionAst* condition; + ExpressionAst* body; + ExpressionAst* orelse; +}; + +class KDEVPYTHONPARSER_EXPORT DictAst : public ExpressionAst { +public: + QList keys; + QList values; +}; + +class KDEVPYTHONPARSER_EXPORT SetAst : public ExpressionAst { +public: + SetAst(Ast* parent, AstType type); + QList elements; +}; + +class KDEVPYTHONPARSER_EXPORT ListComprehensionAst : public ExpressionAst { +public: + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT SetComprehensionAst : public ExpressionAst { +public: + SetComprehensionAst(Ast* parent, AstType type); + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT DictionaryComprehensionAst : public ExpressionAst { +public: + DictionaryComprehensionAst(Ast* parent, AstType type); + ExpressionAst* key; + ExpressionAst* value; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT GeneratorExpressionAst : public ExpressionAst { +public: + GeneratorExpressionAst(Ast* parent, AstType type); + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT CompareAst : public ExpressionAst { +public: + CompareAst(Ast* parent, AstType type); + ExpressionAst* leftmostElement; + QList operators; + QList comparands; +}; + +// TODO whats this exactly? +class KDEVPYTHONPARSER_EXPORT ReprAst : public ExpressionAst { +public: + ReprAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT NumberAst : public ExpressionAst { +public: + NumberAst(Ast* parent, AstType type); + QString value; // everything else would be even more strange +}; + +class KDEVPYTHONPARSER_EXPORT StringAst : public ExpressionAst { +public: + StringAst(Ast* parent, AstType type); + QString value; +}; + +class KDEVPYTHONPARSER_EXPORT YieldAst : public ExpressionAst { +public: + YieldAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + class KDEVPYTHONPARSER_EXPORT NameAst : public ExpressionAst { public: NameAst(Ast* parent, AstType type); @@ -263,6 +503,56 @@ class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { ExpressionAst::Context context; }; +class KDEVPYTHONPARSER_EXPORT SubscriptAst : public ExpressionAst { +public: + SubscriptAst(Ast* parent, AstType type); + ExpressionAst* value; + SliceAst* slice; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT ListAst : public ExpressionAst { +public: + ListAst(Ast* parent, AstType type); + QList elements; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT TupleAst : public ExpressionAst { +public: + TupleAst(Ast* parent, AstType type); + QList elements; + ExpressionAst::Context context; +}; + +/** Slice classes **/ +class KDEVPYTHONPARSER_EXPORT SliceAstBase : public Ast { +public: + SliceAstBase(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT EllipsisAstType : public SliceAstBase { +public: + EllipsisAstType(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { +public: + ExpressionAst* lower; + ExpressionAst* upper; + ExpressionAst* step; +}; + +class KDEVPYTHONPARSER_EXPORT ExtendedSliceAst : public SliceAstBase { +public: + ExtendedSliceAst(Ast* parent, AstType type); + QList dims; +}; + +class KDEVPYTHONPARSER_EXPORT IndexAst : public SliceAstBase { +public: + ExpressionAst* value; +}; /** Independent classes **/ class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { @@ -281,6 +571,29 @@ class KDEVPYTHONPARSER_EXPORT KeywordAst : public Ast { ExpressionAst* value; }; +class KDEVPYTHONPARSER_EXPORT ComprehensionAst : public Ast { +public: + ComprehensionAst(Ast* parent, AstType type); + ExpressionAst* target; + ExpressionAst* iterator; + QList conditions; +}; + +class KDEVPYTHONPARSER_EXPORT ExceptionHandlerAst : public Ast { +public: + ExceptionHandlerAst(Ast* parent, AstType type); + ExpressionAst* type; + ExpressionAst* name; + QList body; +}; + +class KDEVPYTHONPARSER_EXPORT AliasAst : public Ast { +public: + AliasAst(Ast* parent, AstType type); + Identifier* name; + Identifier* asName; +}; + } #endif From bfc218662df9ea5453ecf07bcdce7c30600efd9a Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 12:28:14 +0200 Subject: [PATCH 020/118] Added some necessary forward-Declarations --- parser/ast.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/parser/ast.h b/parser/ast.h index 91ecdb1..2786192 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -52,6 +52,11 @@ namespace Python { class ExpressionAst; class StatementAst; class Ast; + class ExceptionHandlerAst; + class AliasAst; + class ComprehensionAst; + class SliceAstBase; + class SliceAst; } namespace Python @@ -167,7 +172,7 @@ class KDEVPYTHONPARSER_EXPORT Ast ComparisonOperatorIsNot, ComparisonOperatorIn, ComparisonOperatorNotIn - } + }; Ast(Ast* parent, AstType type); virtual ~Ast(); From c6c40aa3bfa0a6c8bb9c1d2e801d6fa1428e8cb1 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 14:31:21 +0200 Subject: [PATCH 021/118] astdefaultvisitor.cpp, part I --- parser/ast.h | 7 +- parser/astdefaultvisitor.cpp | 194 ++++++++++++++++++++++++++++++++++- parser/astdefaultvisitor.h | 59 ++++++++++- parser/astvisitor.h | 61 ++++++++++- 4 files changed, 309 insertions(+), 12 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index 2786192..e0b0611 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -331,7 +331,8 @@ class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst { public: - QList name; + GlobalAst(Ast* parent, AstType type); + QList names; }; // TODO what's stmt::Expr(expr value) in the grammar and what do we need it for? @@ -536,9 +537,9 @@ class KDEVPYTHONPARSER_EXPORT SliceAstBase : public Ast { SliceAstBase(Ast* parent, AstType type); }; -class KDEVPYTHONPARSER_EXPORT EllipsisAstType : public SliceAstBase { +class KDEVPYTHONPARSER_EXPORT EllipsisAst : public SliceAstBase { public: - EllipsisAstType(Ast* parent, AstType type); + EllipsisAst(Ast* parent, AstType type); }; class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 4905b36..c0690da 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -31,7 +31,12 @@ AstDefaultVisitor::~AstDefaultVisitor() { } // note that Identifier is not a node in this Ast void AstDefaultVisitor::visitName(NameAst* node) { } void AstDefaultVisitor::visitPass(StatementAst* node) { } - +void AstDefaultVisitor::visitAlias(AliasAst* node) { } +void AstDefaultVisitor::visitBreak(BreakAst* node) { } +void AstDefaultVisitor::visitContinue(ContinueAst* node) { } +void AstDefaultVisitor::visitEllipsis(EllipsisAst* node) { } +void AstDefaultVisitor::visitGlobal(GlobalAst* node) { } +void AstDefaultVisitor::visitNumber(NumberAst* node) { } void AstDefaultVisitor::visitCode(CodeAst* node) { @@ -40,6 +45,193 @@ void AstDefaultVisitor::visitCode(CodeAst* node) } } +void AstDefaultVisitor::visitAssertion(AssertionAst* node) +{ + visitNode(node->condition); + visitNode(node->message); +} + +void AstDefaultVisitor::visitDelete(DeleteAst* node) +{ + foreach (ExpressionAst* expression, node->targets) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitExec(ExecAst* node) +{ + visitNode(node->body); + visitNode(node->globals); + visitNode(node->locals); +} + +void AstDefaultVisitor::visitExtendedSlice(ExtendedSliceAst* node) +{ + foreach (SliceAst* slice, node->dims) { + visitNode(slice); + } +} + +void AstDefaultVisitor::visitFor(ForAst* node) +{ + visitNode(node->target); + visitNode(node->iterator); + foreach (ExpressionAst* expression, node->body) { + visitNode(expression); + } + foreach (StatementAst* statement, node->orelse) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitGeneratorExpression(GeneratorExpressionAst* node) +{ + visitNode(node->element); + foreach (ComprehensionAst* comp, node->generators) { + visitNode(comp); + } +} + +void AstDefaultVisitor::visitIf(IfAst* node) +{ + visitNode(node->condition); + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } + foreach (StatementAst* statement, node->orelse) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitIfExpression(IfExpressionAst* node) +{ + visitNode(node->condition); + visitNode(node->body); + visitNode(node->orelse); +} + +void AstDefaultVisitor::visitImport(ImportAst* node) +{ + foreach (AliasAst* alias, node->names) { + visitNode(alias); + } +} + +void AstDefaultVisitor::visitImportFrom(ImportFromAst* node) +{ + foreach (AliasAst* alias, node->names) { + visitNode(alias); + } +} + +void AstDefaultVisitor::visitIndex(IndexAst* node) +{ + visitNode(node->value); +} + +void AstDefaultVisitor::visitLambda(LambdaAst* node) +{ + visitNode(node->arguments); + visitNode(node->body); +} + +void AstDefaultVisitor::visitRaise(RaiseAst* node) +{ + Python::AstVisitor::visitRaise(node); +} + +void AstDefaultVisitor::visitList(ListAst* node) +{ + foreach (ExpressionAst* expression, node->elements) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitListComprehension(ListComprehensionAst* node) +{ + visitNode(node->element); + foreach (ComprehensionAst* comp, node->generators) { + visitNode(comp); + } +} + +void AstDefaultVisitor::visitExceptionHandler(ExceptionHandlerAst* node) +{ + visitNode(node->type); + visitNode(node->name); + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitDict(DictAst* node) +{ + foreach (ExpressionAst* expression, node->keys) { + visitNode(expression); + } + foreach (ExpressionAst* expression, node->values) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitDictionaryComprehension(DictionaryComprehensionAst* node) +{ + visitNode(node->key); + visitNode(node->value); + foreach (ComprehensionAst* comp, node->generators) { + visitNode(comp); + } +} + +void AstDefaultVisitor::visitAugmentedAssignment(AugmentedAssignmentAst* node) +{ + visitNode(node->target); + visitNode(node->value); +} + +void AstDefaultVisitor::visitBinaryOperation(BinaryOperationAst* node) +{ + visitNode(node->lhs); + visitNode(node->rhs); +} + +void AstDefaultVisitor::visitBooleanOperation(BooleanOperationAst* node) +{ + foreach (ExpressionAst* expression, node->values) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitClassDefinition(ClassDefinitionAst* node) +{ + foreach (ExpressionAst* expression, node->baseClasses) { + visitNode(expression); + } + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } + foreach (ExpressionAst* expression, node->decorators) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitCompare(CompareAst* node) +{ + visitNode(node->leftmostElement); + foreach (ExpressionAst* expression, node->comparands) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitComprehension(ComprehensionAst* node) +{ + visitNode(node->target); + visitNode(node->iterator); + foreach (ExpressionAst* expression, node->conditions) { + visitNode(expression); + } +} + void AstDefaultVisitor::visitAssignment(AssignmentAst* node) { foreach (ExpressionAst* expression, node->targets) { diff --git a/parser/astdefaultvisitor.h b/parser/astdefaultvisitor.h index d31e4cb..cf75fbb 100644 --- a/parser/astdefaultvisitor.h +++ b/parser/astdefaultvisitor.h @@ -24,6 +24,11 @@ #include "astvisitor.h" #include "parserexport.h" +/** + * Note: This has been generated using utilities/generate.py + * but you can modifiy it, it's not regenerated automatically + */ + namespace Python { @@ -34,15 +39,61 @@ class KDEVPYTHONPARSER_EXPORT AstDefaultVisitor : public AstVisitor virtual ~AstDefaultVisitor(); virtual void visitCode(CodeAst* node); + virtual void visitStatement(StatementAst* node); virtual void visitFunctionDefinition(FunctionDefinitionAst* node); - virtual void visitPrint(PrintAst* node); + virtual void visitClassDefinition(ClassDefinitionAst* node); + virtual void visitReturn(ReturnAst* node); + virtual void visitDelete(DeleteAst* node); virtual void visitAssignment(AssignmentAst* node); - virtual void visitCall(CallAst* node); - virtual void visitPass(StatementAst* node); + virtual void visitAugmentedAssignment(AugmentedAssignmentAst* node); + virtual void visitFor(ForAst* node); + virtual void visitWhile(WhileAst* node); + virtual void visitIf(IfAst* node); + virtual void visitWith(WithAst* node); + virtual void visitRaise(RaiseAst* node); + virtual void visitTryExcept(TryExceptAst* node); + virtual void visitTryFinally(TryFinallyAst* node); + virtual void visitAssertion(AssertionAst* node); + virtual void visitImport(ImportAst* node); + virtual void visitImportFrom(ImportFromAst* node); + virtual void visitExec(ExecAst* node); + virtual void visitGlobal(GlobalAst* node); + virtual void visitBreak(BreakAst* node); + virtual void visitContinue(ContinueAst* node); + virtual void visitPrint(PrintAst* node); + virtual void visitPass(PassAst* node); + virtual void visitBooleanOperation(BooleanOperationAst* node); + virtual void visitBinaryOperation(BinaryOperationAst* node); + virtual void visitUnaryOperation(UnaryOperationAst* node); + virtual void visitLambda(LambdaAst* node); + virtual void visitIfExpression(IfExpressionAst* node); + virtual void visitDict(DictAst* node); + virtual void visitSet(SetAst* node); + virtual void visitListComprehension(ListComprehensionAst* node); + virtual void visitSetComprehension(SetComprehensionAst* node); + virtual void visitDictionaryComprehension(DictionaryComprehensionAst* node); + virtual void visitGeneratorExpression(GeneratorExpressionAst* node); + virtual void visitCompare(CompareAst* node); + virtual void visitRepr(ReprAst* node); + virtual void visitNumber(NumberAst* node); + virtual void visitString(StringAst* node); + virtual void visitYield(YieldAst* node); virtual void visitName(NameAst* node); + virtual void visitCall(CallAst* node); virtual void visitAttribute(AttributeAst* node); - virtual void visitKeyword(KeywordAst* node); + virtual void visitSubscript(SubscriptAst* node); + virtual void visitList(ListAst* node); + virtual void visitTuple(TupleAst* node); + virtual void visitSlice(SliceAst* node); + virtual void visitEllipsis(EllipsisAst* node); + virtual void visitSlice(SliceAst* node); + virtual void visitExtendedSlice(ExtendedSliceAst* node); + virtual void visitIndex(IndexAst* node); virtual void visitArguments(ArgumentsAst* node); + virtual void visitKeyword(KeywordAst* node); + virtual void visitComprehension(ComprehensionAst* node); + virtual void visitExceptionHandler(ExceptionHandlerAst* node); + virtual void visitAlias(AliasAst* node); }; } diff --git a/parser/astvisitor.h b/parser/astvisitor.h index 38ddce3..1ba35ca 100644 --- a/parser/astvisitor.h +++ b/parser/astvisitor.h @@ -24,6 +24,11 @@ #include "ast.h" #include "parserexport.h" +/** + * Note: This has been generated using utilities/generate.py + * but you can modifiy it, it's not regenerated automatically + */ + namespace Python { @@ -38,15 +43,63 @@ class KDEVPYTHONPARSER_EXPORT AstVisitor void visitNode(Ast* node); virtual void visitCode(CodeAst* node) { Q_UNUSED(node); }; + virtual void visitStatement(StatementAst* node) { Q_UNUSED(node); }; virtual void visitFunctionDefinition(FunctionDefinitionAst* node) { Q_UNUSED(node); }; - virtual void visitPrint(PrintAst* node) { Q_UNUSED(node); }; + virtual void visitClassDefinition(ClassDefinitionAst* node) { Q_UNUSED(node); }; + virtual void visitReturn(ReturnAst* node) { Q_UNUSED(node); }; + virtual void visitDelete(DeleteAst* node) { Q_UNUSED(node); }; virtual void visitAssignment(AssignmentAst* node) { Q_UNUSED(node); }; - virtual void visitCall(CallAst* node) { Q_UNUSED(node); }; - virtual void visitPass(StatementAst* node) { Q_UNUSED(node); }; + virtual void visitAugmentedAssignment(AugmentedAssignmentAst* node) { Q_UNUSED(node); }; + virtual void visitFor(ForAst* node) { Q_UNUSED(node); }; + virtual void visitWhile(WhileAst* node) { Q_UNUSED(node); }; + virtual void visitIf(IfAst* node) { Q_UNUSED(node); }; + virtual void visitWith(WithAst* node) { Q_UNUSED(node); }; + virtual void visitRaise(RaiseAst* node) { Q_UNUSED(node); }; + virtual void visitTryExcept(TryExceptAst* node) { Q_UNUSED(node); }; + virtual void visitTryFinally(TryFinallyAst* node) { Q_UNUSED(node); }; + virtual void visitAssertion(AssertionAst* node) { Q_UNUSED(node); }; + virtual void visitImport(ImportAst* node) { Q_UNUSED(node); }; + virtual void visitImportFrom(ImportFromAst* node) { Q_UNUSED(node); }; + virtual void visitExec(ExecAst* node) { Q_UNUSED(node); }; + virtual void visitGlobal(GlobalAst* node) { Q_UNUSED(node); }; + virtual void visitBreak(BreakAst* node) { Q_UNUSED(node); }; + virtual void visitContinue(ContinueAst* node) { Q_UNUSED(node); }; + virtual void visitPrint(PrintAst* node) { Q_UNUSED(node); }; + virtual void visitPass(PassAst* node) { Q_UNUSED(node); }; + virtual void visitExpression(ExpressionAst* node) { Q_UNUSED(node); }; + virtual void visitBooleanOperation(BooleanOperationAst* node) { Q_UNUSED(node); }; + virtual void visitBinaryOperation(BinaryOperationAst* node) { Q_UNUSED(node); }; + virtual void visitUnaryOperation(UnaryOperationAst* node) { Q_UNUSED(node); }; + virtual void visitLambda(LambdaAst* node) { Q_UNUSED(node); }; + virtual void visitIfExpression(IfExpressionAst* node) { Q_UNUSED(node); }; + virtual void visitDict(DictAst* node) { Q_UNUSED(node); }; + virtual void visitSet(SetAst* node) { Q_UNUSED(node); }; + virtual void visitListComprehension(ListComprehensionAst* node) { Q_UNUSED(node); }; + virtual void visitSetComprehension(SetComprehensionAst* node) { Q_UNUSED(node); }; + virtual void visitDictionaryComprehension(DictionaryComprehensionAst* node) { Q_UNUSED(node); }; + virtual void visitGeneratorExpression(GeneratorExpressionAst* node) { Q_UNUSED(node); }; + virtual void visitCompare(CompareAst* node) { Q_UNUSED(node); }; + virtual void visitRepr(ReprAst* node) { Q_UNUSED(node); }; + virtual void visitNumber(NumberAst* node) { Q_UNUSED(node); }; + virtual void visitString(StringAst* node) { Q_UNUSED(node); }; + virtual void visitYield(YieldAst* node) { Q_UNUSED(node); }; virtual void visitName(NameAst* node) { Q_UNUSED(node); }; + virtual void visitCall(CallAst* node) { Q_UNUSED(node); }; virtual void visitAttribute(AttributeAst* node) { Q_UNUSED(node); }; - virtual void visitKeyword(KeywordAst* node) { Q_UNUSED(node); }; + virtual void visitSubscript(SubscriptAst* node) { Q_UNUSED(node); }; + virtual void visitList(ListAst* node) { Q_UNUSED(node); }; + virtual void visitTuple(TupleAst* node) { Q_UNUSED(node); }; + virtual void visitSlice(SliceAst* node) { Q_UNUSED(node); }; + virtual void visitEllipsis(EllipsisAst* node) { Q_UNUSED(node); }; + virtual void visitSlice(SliceAst* node) { Q_UNUSED(node); }; + virtual void visitExtendedSlice(ExtendedSliceAst* node) { Q_UNUSED(node); }; + virtual void visitIndex(IndexAst* node) { Q_UNUSED(node); }; virtual void visitArguments(ArgumentsAst* node) { Q_UNUSED(node); }; + virtual void visitKeyword(KeywordAst* node) { Q_UNUSED(node); }; + virtual void visitComprehension(ComprehensionAst* node) { Q_UNUSED(node); }; + virtual void visitExceptionHandler(ExceptionHandlerAst* node) { Q_UNUSED(node); }; + virtual void visitAlias(AliasAst* node) { Q_UNUSED(node); }; + }; } From 6c0ee45417ef488cdffcc76d30bd4d0b065cbaa7 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 14:38:37 +0200 Subject: [PATCH 022/118] Implemented astdefaultvisitor.cpp (untested!) --- parser/astdefaultvisitor.cpp | 101 ++++++++++++++++++++++++++++++++++- parser/astdefaultvisitor.h | 1 - 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index c0690da..2fdd64a 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -37,6 +37,7 @@ void AstDefaultVisitor::visitContinue(ContinueAst* node) { } void AstDefaultVisitor::visitEllipsis(EllipsisAst* node) { } void AstDefaultVisitor::visitGlobal(GlobalAst* node) { } void AstDefaultVisitor::visitNumber(NumberAst* node) { } +void AstDefaultVisitor::visitString(StringAst* node) { } void AstDefaultVisitor::visitCode(CodeAst* node) { @@ -137,7 +138,105 @@ void AstDefaultVisitor::visitLambda(LambdaAst* node) void AstDefaultVisitor::visitRaise(RaiseAst* node) { - Python::AstVisitor::visitRaise(node); + visitNode(node->type); +} + +void AstDefaultVisitor::visitRepr(ReprAst* node) +{ + visitNode(node->value); +} + +void AstDefaultVisitor::visitReturn(ReturnAst* node) +{ + visitNode(node->value); +} + +void AstDefaultVisitor::visitSet(SetAst* node) +{ + foreach (ExpressionAst* expression, node->elements) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitSetComprehension(SetComprehensionAst* node) +{ + visitNode(node->element); + foreach (ComprehensionAst* comp, node->generators) { + visitNode(comp); + } +} + +void AstDefaultVisitor::visitSlice(SliceAst* node) +{ + visitNode(node->lower); + visitNode(node->upper); + visitNode(node->step); +} + +void AstDefaultVisitor::visitSubscript(SubscriptAst* node) +{ + visitNode(node->value); + visitNode(node->slice); +} + +void AstDefaultVisitor::visitTryExcept(TryExceptAst* node) +{ + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } + foreach (ExceptionHandlerAst* handler, node->handlers) { + visitNode(handler); + } + foreach (StatementAst* statement, node->orelse) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitTryFinally(TryFinallyAst* node) +{ + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } + foreach (StatementAst* statement, node->finalbody) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitTuple(TupleAst* node) +{ + foreach (ExpressionAst* expression, node->elements) { + visitNode(expression); + } +} + +void AstDefaultVisitor::visitUnaryOperation(UnaryOperationAst* node) +{ + visitNode(node->operand); +} + +void AstDefaultVisitor::visitWhile(WhileAst* node) +{ + visitNode(node->condition); + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } + foreach (StatementAst* statement, node->orelse) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitWith(WithAst* node) +{ + visitNode(node->contextExpression); + visitNode(node->optionalVars); + foreach (StatementAst* statement, node->body) { + visitNode(statement); + } +} + +void AstDefaultVisitor::visitYield(YieldAst* node) +{ + visitNode(node->value); } void AstDefaultVisitor::visitList(ListAst* node) diff --git a/parser/astdefaultvisitor.h b/parser/astdefaultvisitor.h index cf75fbb..e60c5f3 100644 --- a/parser/astdefaultvisitor.h +++ b/parser/astdefaultvisitor.h @@ -39,7 +39,6 @@ class KDEVPYTHONPARSER_EXPORT AstDefaultVisitor : public AstVisitor virtual ~AstDefaultVisitor(); virtual void visitCode(CodeAst* node); - virtual void visitStatement(StatementAst* node); virtual void visitFunctionDefinition(FunctionDefinitionAst* node); virtual void visitClassDefinition(ClassDefinitionAst* node); virtual void visitReturn(ReturnAst* node); From 3e0d01448255a5ed3586f230cb3e2922c7348da3 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 14:51:23 +0200 Subject: [PATCH 023/118] astvisitor.cpp, utility generator script, missing enums --- parser/ast.h | 5 + parser/astvisitor.cpp | 71 ++++- utilities/classes | 604 ++++++++++++++++++++++++++++++++++++++++++ utilities/generate.py | 15 ++ 4 files changed, 685 insertions(+), 10 deletions(-) create mode 100644 utilities/classes create mode 100644 utilities/generate.py diff --git a/parser/ast.h b/parser/ast.h index e0b0611..3e97026 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -104,6 +104,11 @@ class KDEVPYTHONPARSER_EXPORT Ast BreakAstType, ContinueAstType, AttributesAstType, + AssertionAstType, + AugmentedAssignmentAstType, + DictionaryComprehensionAstType, + ExtendedSliceAstType, + CodeAstType, BooleanOperationAstType, BinaryOperationAstType, diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index 4d07c6c..b929e1c 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -20,6 +20,11 @@ #include "astvisitor.h" +/** + * Note: This has been generated using utilities/generate.py + * but you can modifiy it, it's not regenerated automatically + */ + namespace Python { @@ -31,16 +36,62 @@ void AstVisitor::visitNode(Ast* node) { if ( ! node ) return; switch ( node->astType ) { - case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; - case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; - case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; - case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; - case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; - case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; - case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; - case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; - case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; - case Ast::ExpressionAstType: break; + case Ast::CodeAstType: AstVisitor::visitCode(dynamic_cast(node)); break; + case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; + case Ast::ClassDefinitionAstType: AstVisitor::visitClassDefinition(dynamic_cast(node)); break; + case Ast::ReturnAstType: AstVisitor::visitReturn(dynamic_cast(node)); break; + case Ast::DeleteAstType: AstVisitor::visitDelete(dynamic_cast(node)); break; + case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; + case Ast::AugmentedAssignmentAstType: AstVisitor::visitAugmentedAssignment(dynamic_cast(node)); break; + case Ast::ForAstType: AstVisitor::visitFor(dynamic_cast(node)); break; + case Ast::WhileAstType: AstVisitor::visitWhile(dynamic_cast(node)); break; + case Ast::IfAstType: AstVisitor::visitIf(dynamic_cast(node)); break; + case Ast::WithAstType: AstVisitor::visitWith(dynamic_cast(node)); break; + case Ast::RaiseAstType: AstVisitor::visitRaise(dynamic_cast(node)); break; + case Ast::TryExceptAstType: AstVisitor::visitTryExcept(dynamic_cast(node)); break; + case Ast::TryFinallyAstType: AstVisitor::visitTryFinally(dynamic_cast(node)); break; + case Ast::AssertionAstType: AstVisitor::visitAssertion(dynamic_cast(node)); break; + case Ast::ImportAstType: AstVisitor::visitImport(dynamic_cast(node)); break; + case Ast::ImportFromAstType: AstVisitor::visitImportFrom(dynamic_cast(node)); break; + case Ast::ExecAstType: AstVisitor::visitExec(dynamic_cast(node)); break; + case Ast::GlobalAstType: AstVisitor::visitGlobal(dynamic_cast(node)); break; + case Ast::BreakAstType: AstVisitor::visitBreak(dynamic_cast(node)); break; + case Ast::ContinueAstType: AstVisitor::visitContinue(dynamic_cast(node)); break; + case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; + case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; + case Ast::BooleanOperationAstType: AstVisitor::visitBooleanOperation(dynamic_cast(node)); break; + case Ast::BinaryOperationAstType: AstVisitor::visitBinaryOperation(dynamic_cast(node)); break; + case Ast::UnaryOperationAstType: AstVisitor::visitUnaryOperation(dynamic_cast(node)); break; + case Ast::LambdaAstType: AstVisitor::visitLambda(dynamic_cast(node)); break; + case Ast::IfExpressionAstType: AstVisitor::visitIfExpression(dynamic_cast(node)); break; + case Ast::DictAstType: AstVisitor::visitDict(dynamic_cast(node)); break; + case Ast::SetAstType: AstVisitor::visitSet(dynamic_cast(node)); break; + case Ast::ListComprehensionAstType: AstVisitor::visitListComprehension(dynamic_cast(node)); break; + case Ast::SetComprehensionAstType: AstVisitor::visitSetComprehension(dynamic_cast(node)); break; + case Ast::DictionaryComprehensionAstType: AstVisitor::visitDictionaryComprehension(dynamic_cast(node)); break; + case Ast::GeneratorExpressionAstType: AstVisitor::visitGeneratorExpression(dynamic_cast(node)); break; + case Ast::CompareAstType: AstVisitor::visitCompare(dynamic_cast(node)); break; + case Ast::ReprAstType: AstVisitor::visitRepr(dynamic_cast(node)); break; + case Ast::NumberAstType: AstVisitor::visitNumber(dynamic_cast(node)); break; + case Ast::StringAstType: AstVisitor::visitString(dynamic_cast(node)); break; + case Ast::YieldAstType: AstVisitor::visitYield(dynamic_cast(node)); break; + case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; + case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; + case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; + case Ast::SubscriptAstType: AstVisitor::visitSubscript(dynamic_cast(node)); break; + case Ast::ListAstType: AstVisitor::visitList(dynamic_cast(node)); break; + case Ast::TupleAstType: AstVisitor::visitTuple(dynamic_cast(node)); break; + case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; + case Ast::EllipsisAstType: AstVisitor::visitEllipsis(dynamic_cast(node)); break; + case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; + case Ast::ExtendedSliceAstType: AstVisitor::visitExtendedSlice(dynamic_cast(node)); break; + case Ast::IndexAstType: AstVisitor::visitIndex(dynamic_cast(node)); break; + case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; + case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; + case Ast::ComprehensionAstType: AstVisitor::visitComprehension(dynamic_cast(node)); break; + case Ast::ExceptionHandlerAstType: AstVisitor::visitExceptionHandler(dynamic_cast(node)); break; + case Ast::AliasAstType: AstVisitor::visitAlias(dynamic_cast(node)); break; + case Ast::ExpressionAstType: break; } } diff --git a/utilities/classes b/utilities/classes new file mode 100644 index 0000000..2786192 --- /dev/null +++ b/utilities/classes @@ -0,0 +1,604 @@ +/*************************************************************************** + * This file is part of KDevelop * + * Copyright 2007 Andreas Pakulat * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +// The Python 2.6 Language Reference was used as basis for this AST + +#ifndef PYTHON_AST_H +#define PYTHON_AST_H + +#include +#include +#include +#include +#include + +#include "parserexport.h" + +namespace KDevelop +{ + class DUContext; +} + +namespace Python { + class StatementAst; + class FunctionDefinitionAst; + class AssignmentAst; + class PrintAst; + class PassAst; + class ExpressionAst; + class NameAst; + class CallAst; + class AttributeAst; + class ArgumentsAst; + class KeywordAst; + + class ExpressionAst; + class StatementAst; + class Ast; + class ExceptionHandlerAst; + class AliasAst; + class ComprehensionAst; + class SliceAstBase; + class SliceAst; +} + +namespace Python +{ + +class KDEVPYTHONPARSER_EXPORT Identifier { +public: + Identifier(QString value); + QString value; +}; + +// Base class for all other Abstract Syntax Tree classes +class KDEVPYTHONPARSER_EXPORT Ast +{ +public: + enum AstType + { + FunctionDefinitionAstType, + AssignmentAstType, + PrintAstType, + PassAstType, + ExpressionAstType, + NameAstType, + CallAstType, + AttributeAstType, + ArgumentsAstType, + KeywordAstType, + ClassDefinitionAstType, + ReturnAstType, + DeleteAstType, + AugAssignAstType, + ForAstType, + WhileAstType, + IfAstType, + WithAstType, + RaiseAstType, + TryExceptAstType, + TryFinallyAstType, + AssertAstType, + ImportAstType, + ImportFromAstType, + ExecAstType, + GlobalAstType, + ExprAstType, + BreakAstType, + ContinueAstType, + AttributesAstType, + + BooleanOperationAstType, + BinaryOperationAstType, + UnaryOperationAstType, + LambdaAstType, + IfExpressionAstType, // the short one, if a then b else c + DictAstType, + SetAstType, + ListComprehensionAstType, + SetComprehensionAstType, + DictComprehensionAstType, + GeneratorExpressionAstType, + YieldAstType, + CompareAstType, + ReprAstType, + NumberAstType, + StringAstType, + SubscriptAstType, + ListAstType, + TupleAstType, + + SliceAstType, + EllipsisAstType, + IndexAstType, + + ComprehensionAstType, + ExceptionHandlerAstType, + AliasAstType // for imports + }; + + enum BooleanOperationTypes { + BooleanAnd, + BooleanOr + }; + + enum OperatorTypes { + OperatorAdd, + OperatorSub, + OperatorMult, + OperatorDiv, + OperatorMod, + OperatorPow, + OperatorLeftShift, + OperatorRightShift, + OperatorBitwiseOr, + OperatorBitwiseXor, + OperatorBitwiseAnd, + OperatorFloorDivision + }; + + enum UnaryOperatorTypes { + UnaryOperatorInvert, + UnaryOperatorNot, + UnaryOperatorAdd, + UnaryOperatorSub + }; + + enum ComparisonOperatorTypes { + ComparisonOperatorEquals, + ComparisonOperatorNotEquals, + ComparisonOperatorLessThan, + ComparisonOperatorLessThanEqual, + ComparisonOperatorGreaterThan, + ComparisonOperatorGreaterThanEqual, + ComparisonOperatorIs, + ComparisonOperatorIsNot, + ComparisonOperatorIn, + ComparisonOperatorNotIn + }; + + Ast(Ast* parent, AstType type); + virtual ~Ast(); + Ast* parent; + AstType astType; + + qint64 start; + qint64 end; + qint64 startCol; + qint64 startLine; + qint64 endCol; + qint64 endLine; + + KDevelop::DUContext* context; +}; + +// this replaces ModuleAst +class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast { +public: + CodeAst(Ast* parent, AstType type); + QList body; +}; + +/** Statement classes **/ +class KDEVPYTHONPARSER_EXPORT StatementAst : public Ast { +public: + StatementAst(Ast* parent, Ast::AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { +public: + FunctionDefinitionAst(Ast* parent, Ast::AstType type); + Identifier* name; + ArgumentsAst* arguments; +}; + +class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { +public: + ClassDefinitionAst(Ast* parent, AstType type); + Identifier* name; + QList baseClasses; + QList body; + QList decorators; +}; + +class KDEVPYTHONPARSER_EXPORT ReturnAst : public StatementAst { +public: + ReturnAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT DeleteAst : public StatementAst { +public: + DeleteAst(Ast* parent, AstType type); + QList targets; +}; + +class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst { +public: + AssignmentAst(Ast* parent, Ast::AstType type); + QList targets; + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT AugmentedAssignmentAst : public StatementAst { +public: + AugmentedAssignmentAst(Ast* parent, AstType type); + ExpressionAst* target; + Ast::OperatorTypes op; + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { +public: + ForAst(Ast* parent, AstType type); + ExpressionAst* target; + ExpressionAst* iterator; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst { +public: + WhileAst(Ast* parent, AstType type); + ExpressionAst* condition; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst { +public: + IfAst(Ast* parent, AstType type); + ExpressionAst* condition; + QList body; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { +public: + WithAst(Ast* parent, AstType type); + ExpressionAst* contextExpression; + ExpressionAst* optionalVars; + QList body; +}; + +class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst { +public: + RaiseAst(Ast* parent, AstType type); + ExpressionAst* type; + // TODO check what the other things in the grammar actually are and add them +}; + +class KDEVPYTHONPARSER_EXPORT TryExceptAst : public StatementAst { +public: + TryExceptAst(Ast* parent, AstType type); + QList body; + QList handlers; + QList orelse; +}; + +class KDEVPYTHONPARSER_EXPORT TryFinallyAst : public StatementAst { +public: + TryFinallyAst(Ast* parent, AstType type); + QList body; + QList finalbody; +}; + +class KDEVPYTHONPARSER_EXPORT AssertionAst : public StatementAst { +public: + AssertionAst(Ast* parent, AstType type); + ExpressionAst* condition; + ExpressionAst* message; +}; + +class KDEVPYTHONPARSER_EXPORT ImportAst : public StatementAst { +public: + ImportAst(Ast* parent, AstType type); + QList names; +}; + +class KDEVPYTHONPARSER_EXPORT ImportFromAst : public StatementAst { +public: + ImportFromAst(Ast* parent, AstType type); + Identifier* module; + QList names; + int level; +}; + +class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst { +public: + ExecAst(Ast* parent, AstType type); + ExpressionAst* body; + ExpressionAst* globals; + ExpressionAst* locals; +}; + +class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst { +public: + QList name; +}; + +// TODO what's stmt::Expr(expr value) in the grammar and what do we need it for? + +class KDEVPYTHONPARSER_EXPORT BreakAst : public StatementAst { +public: + BreakAst(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT ContinueAst : public StatementAst { +public: + ContinueAst(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { +public: + PrintAst(Ast* parent, AstType type); + ExpressionAst* destination; + QList values; + bool newline; +}; + +class KDEVPYTHONPARSER_EXPORT PassAst : public StatementAst { +public: + PassAst(Ast* parent, AstType type); +}; + + +/** Expression classes **/ +class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { +public: + ExpressionAst(Ast* parent, AstType type); + enum Context { + Load, // the object is read + Store, // the object is written + Delete, // the object is deleted + Parameter, // the object is passed as a parameter + AugLoad, AugStore // Augmented assignments, like a += 1 + }; +}; + +class KDEVPYTHONPARSER_EXPORT BooleanOperationAst : public ExpressionAst { +public: + BooleanOperationAst(Ast* parent, AstType type); + Ast::BooleanOperationTypes type; + QList values; +}; + +class KDEVPYTHONPARSER_EXPORT BinaryOperationAst : public ExpressionAst { +public: + BinaryOperationAst(Ast* parent, AstType type); + Ast::OperatorTypes type; + ExpressionAst* lhs; + ExpressionAst* rhs; +}; + +class KDEVPYTHONPARSER_EXPORT UnaryOperationAst : public ExpressionAst { +public: + UnaryOperationAst(Ast* parent, AstType type); + Ast::UnaryOperatorTypes type; + ExpressionAst* operand; +}; + +class KDEVPYTHONPARSER_EXPORT LambdaAst : public ExpressionAst { +public: + LambdaAst(Ast* parent, AstType type); + ArgumentsAst* arguments; + ExpressionAst* body; +}; + +class KDEVPYTHONPARSER_EXPORT IfExpressionAst : public ExpressionAst { +public: + IfExpressionAst(Ast* parent, AstType type); + ExpressionAst* condition; + ExpressionAst* body; + ExpressionAst* orelse; +}; + +class KDEVPYTHONPARSER_EXPORT DictAst : public ExpressionAst { +public: + QList keys; + QList values; +}; + +class KDEVPYTHONPARSER_EXPORT SetAst : public ExpressionAst { +public: + SetAst(Ast* parent, AstType type); + QList elements; +}; + +class KDEVPYTHONPARSER_EXPORT ListComprehensionAst : public ExpressionAst { +public: + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT SetComprehensionAst : public ExpressionAst { +public: + SetComprehensionAst(Ast* parent, AstType type); + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT DictionaryComprehensionAst : public ExpressionAst { +public: + DictionaryComprehensionAst(Ast* parent, AstType type); + ExpressionAst* key; + ExpressionAst* value; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT GeneratorExpressionAst : public ExpressionAst { +public: + GeneratorExpressionAst(Ast* parent, AstType type); + ExpressionAst* element; + QList generators; +}; + +class KDEVPYTHONPARSER_EXPORT CompareAst : public ExpressionAst { +public: + CompareAst(Ast* parent, AstType type); + ExpressionAst* leftmostElement; + QList operators; + QList comparands; +}; + +// TODO whats this exactly? +class KDEVPYTHONPARSER_EXPORT ReprAst : public ExpressionAst { +public: + ReprAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT NumberAst : public ExpressionAst { +public: + NumberAst(Ast* parent, AstType type); + QString value; // everything else would be even more strange +}; + +class KDEVPYTHONPARSER_EXPORT StringAst : public ExpressionAst { +public: + StringAst(Ast* parent, AstType type); + QString value; +}; + +class KDEVPYTHONPARSER_EXPORT YieldAst : public ExpressionAst { +public: + YieldAst(Ast* parent, AstType type); + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT NameAst : public ExpressionAst { +public: + NameAst(Ast* parent, AstType type); + Identifier* identifier; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT CallAst : public ExpressionAst { +public: + CallAst(Ast* parent, AstType type); + ExpressionAst* function; + QList arguments; + QList keywords; + ExpressionAst* starArguments; + ExpressionAst* keywordArguments; +}; + +class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { +public: + AttributeAst(Ast* parent, AstType type); + ExpressionAst* value; + Identifier* attribute; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT SubscriptAst : public ExpressionAst { +public: + SubscriptAst(Ast* parent, AstType type); + ExpressionAst* value; + SliceAst* slice; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT ListAst : public ExpressionAst { +public: + ListAst(Ast* parent, AstType type); + QList elements; + ExpressionAst::Context context; +}; + +class KDEVPYTHONPARSER_EXPORT TupleAst : public ExpressionAst { +public: + TupleAst(Ast* parent, AstType type); + QList elements; + ExpressionAst::Context context; +}; + +/** Slice classes **/ +class KDEVPYTHONPARSER_EXPORT SliceAstBase : public Ast { +public: + SliceAstBase(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT EllipsisAstType : public SliceAstBase { +public: + EllipsisAstType(Ast* parent, AstType type); +}; + +class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { +public: + ExpressionAst* lower; + ExpressionAst* upper; + ExpressionAst* step; +}; + +class KDEVPYTHONPARSER_EXPORT ExtendedSliceAst : public SliceAstBase { +public: + ExtendedSliceAst(Ast* parent, AstType type); + QList dims; +}; + +class KDEVPYTHONPARSER_EXPORT IndexAst : public SliceAstBase { +public: + ExpressionAst* value; +}; + +/** Independent classes **/ +class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { +public: + ArgumentsAst(Ast* parent, AstType type); + QList arguments; + QList defaultValues; + Identifier* vararg; + Identifier* kwarg; +}; + +class KDEVPYTHONPARSER_EXPORT KeywordAst : public Ast { +public: + KeywordAst(Ast* parent, AstType type); + Identifier* argumentName; + ExpressionAst* value; +}; + +class KDEVPYTHONPARSER_EXPORT ComprehensionAst : public Ast { +public: + ComprehensionAst(Ast* parent, AstType type); + ExpressionAst* target; + ExpressionAst* iterator; + QList conditions; +}; + +class KDEVPYTHONPARSER_EXPORT ExceptionHandlerAst : public Ast { +public: + ExceptionHandlerAst(Ast* parent, AstType type); + ExpressionAst* type; + ExpressionAst* name; + QList body; +}; + +class KDEVPYTHONPARSER_EXPORT AliasAst : public Ast { +public: + AliasAst(Ast* parent, AstType type); + Identifier* name; + Identifier* asName; +}; + +} + +#endif diff --git a/utilities/generate.py b/utilities/generate.py new file mode 100644 index 0000000..cdef647 --- /dev/null +++ b/utilities/generate.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python2.6 + +import re + +f = open('classes') +contents = f.read() +f.close() + +r = re.findall(r'class KDEVPYTHONPARSER_EXPORT (?P\w+)Ast', contents) +for item in r: + funcname = 'visit' + item + astname = item + 'Ast' + #print 'virtual void ' + funcname + '(' + astname + '* node);' + #print 'virtual void ' + funcname + '(' + astname + '* node) { Q_UNUSED(node); };' + print 'case Ast::' + astname + 'Type:\t\t\t' + 'AstVisitor::' + funcname + '(dynamic_cast<' + astname + '>(node)); break;' \ No newline at end of file From 17dc9abe86d5459645c88603b00603b1b8b9b88e Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 15:04:35 +0200 Subject: [PATCH 024/118] Fixed various small errors --- parser/astdefaultvisitor.cpp | 18 +++--- parser/astdefaultvisitor.h | 1 - parser/astvisitor.cpp | 109 +++++++++++++++++------------------ parser/astvisitor.h | 1 - 4 files changed, 63 insertions(+), 66 deletions(-) diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 2fdd64a..b97c6aa 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -29,15 +29,15 @@ AstDefaultVisitor::~AstDefaultVisitor() { } // The Ast "ends" here, those dont have child nodes // note that Identifier is not a node in this Ast -void AstDefaultVisitor::visitName(NameAst* node) { } -void AstDefaultVisitor::visitPass(StatementAst* node) { } -void AstDefaultVisitor::visitAlias(AliasAst* node) { } -void AstDefaultVisitor::visitBreak(BreakAst* node) { } -void AstDefaultVisitor::visitContinue(ContinueAst* node) { } -void AstDefaultVisitor::visitEllipsis(EllipsisAst* node) { } -void AstDefaultVisitor::visitGlobal(GlobalAst* node) { } -void AstDefaultVisitor::visitNumber(NumberAst* node) { } -void AstDefaultVisitor::visitString(StringAst* node) { } +void AstDefaultVisitor::visitName(NameAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitPass(PassAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitAlias(AliasAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitBreak(BreakAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitContinue(ContinueAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitEllipsis(EllipsisAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitGlobal(GlobalAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitNumber(NumberAst* node) { Q_UNUSED(node); } +void AstDefaultVisitor::visitString(StringAst* node) { Q_UNUSED(node); } void AstDefaultVisitor::visitCode(CodeAst* node) { diff --git a/parser/astdefaultvisitor.h b/parser/astdefaultvisitor.h index e60c5f3..af9c851 100644 --- a/parser/astdefaultvisitor.h +++ b/parser/astdefaultvisitor.h @@ -83,7 +83,6 @@ class KDEVPYTHONPARSER_EXPORT AstDefaultVisitor : public AstVisitor virtual void visitSubscript(SubscriptAst* node); virtual void visitList(ListAst* node); virtual void visitTuple(TupleAst* node); - virtual void visitSlice(SliceAst* node); virtual void visitEllipsis(EllipsisAst* node); virtual void visitSlice(SliceAst* node); virtual void visitExtendedSlice(ExtendedSliceAst* node); diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index b929e1c..1ed1cb9 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -36,61 +36,60 @@ void AstVisitor::visitNode(Ast* node) { if ( ! node ) return; switch ( node->astType ) { - case Ast::CodeAstType: AstVisitor::visitCode(dynamic_cast(node)); break; - case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; - case Ast::ClassDefinitionAstType: AstVisitor::visitClassDefinition(dynamic_cast(node)); break; - case Ast::ReturnAstType: AstVisitor::visitReturn(dynamic_cast(node)); break; - case Ast::DeleteAstType: AstVisitor::visitDelete(dynamic_cast(node)); break; - case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; - case Ast::AugmentedAssignmentAstType: AstVisitor::visitAugmentedAssignment(dynamic_cast(node)); break; - case Ast::ForAstType: AstVisitor::visitFor(dynamic_cast(node)); break; - case Ast::WhileAstType: AstVisitor::visitWhile(dynamic_cast(node)); break; - case Ast::IfAstType: AstVisitor::visitIf(dynamic_cast(node)); break; - case Ast::WithAstType: AstVisitor::visitWith(dynamic_cast(node)); break; - case Ast::RaiseAstType: AstVisitor::visitRaise(dynamic_cast(node)); break; - case Ast::TryExceptAstType: AstVisitor::visitTryExcept(dynamic_cast(node)); break; - case Ast::TryFinallyAstType: AstVisitor::visitTryFinally(dynamic_cast(node)); break; - case Ast::AssertionAstType: AstVisitor::visitAssertion(dynamic_cast(node)); break; - case Ast::ImportAstType: AstVisitor::visitImport(dynamic_cast(node)); break; - case Ast::ImportFromAstType: AstVisitor::visitImportFrom(dynamic_cast(node)); break; - case Ast::ExecAstType: AstVisitor::visitExec(dynamic_cast(node)); break; - case Ast::GlobalAstType: AstVisitor::visitGlobal(dynamic_cast(node)); break; - case Ast::BreakAstType: AstVisitor::visitBreak(dynamic_cast(node)); break; - case Ast::ContinueAstType: AstVisitor::visitContinue(dynamic_cast(node)); break; - case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; - case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; - case Ast::BooleanOperationAstType: AstVisitor::visitBooleanOperation(dynamic_cast(node)); break; - case Ast::BinaryOperationAstType: AstVisitor::visitBinaryOperation(dynamic_cast(node)); break; - case Ast::UnaryOperationAstType: AstVisitor::visitUnaryOperation(dynamic_cast(node)); break; - case Ast::LambdaAstType: AstVisitor::visitLambda(dynamic_cast(node)); break; - case Ast::IfExpressionAstType: AstVisitor::visitIfExpression(dynamic_cast(node)); break; - case Ast::DictAstType: AstVisitor::visitDict(dynamic_cast(node)); break; - case Ast::SetAstType: AstVisitor::visitSet(dynamic_cast(node)); break; - case Ast::ListComprehensionAstType: AstVisitor::visitListComprehension(dynamic_cast(node)); break; - case Ast::SetComprehensionAstType: AstVisitor::visitSetComprehension(dynamic_cast(node)); break; - case Ast::DictionaryComprehensionAstType: AstVisitor::visitDictionaryComprehension(dynamic_cast(node)); break; - case Ast::GeneratorExpressionAstType: AstVisitor::visitGeneratorExpression(dynamic_cast(node)); break; - case Ast::CompareAstType: AstVisitor::visitCompare(dynamic_cast(node)); break; - case Ast::ReprAstType: AstVisitor::visitRepr(dynamic_cast(node)); break; - case Ast::NumberAstType: AstVisitor::visitNumber(dynamic_cast(node)); break; - case Ast::StringAstType: AstVisitor::visitString(dynamic_cast(node)); break; - case Ast::YieldAstType: AstVisitor::visitYield(dynamic_cast(node)); break; - case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; - case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; - case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; - case Ast::SubscriptAstType: AstVisitor::visitSubscript(dynamic_cast(node)); break; - case Ast::ListAstType: AstVisitor::visitList(dynamic_cast(node)); break; - case Ast::TupleAstType: AstVisitor::visitTuple(dynamic_cast(node)); break; - case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; - case Ast::EllipsisAstType: AstVisitor::visitEllipsis(dynamic_cast(node)); break; - case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; - case Ast::ExtendedSliceAstType: AstVisitor::visitExtendedSlice(dynamic_cast(node)); break; - case Ast::IndexAstType: AstVisitor::visitIndex(dynamic_cast(node)); break; - case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; - case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; - case Ast::ComprehensionAstType: AstVisitor::visitComprehension(dynamic_cast(node)); break; - case Ast::ExceptionHandlerAstType: AstVisitor::visitExceptionHandler(dynamic_cast(node)); break; - case Ast::AliasAstType: AstVisitor::visitAlias(dynamic_cast(node)); break; + case Ast::CodeAstType: AstVisitor::visitCode(dynamic_cast(node)); break; + case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; + case Ast::ClassDefinitionAstType: AstVisitor::visitClassDefinition(dynamic_cast(node)); break; + case Ast::ReturnAstType: AstVisitor::visitReturn(dynamic_cast(node)); break; + case Ast::DeleteAstType: AstVisitor::visitDelete(dynamic_cast(node)); break; + case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; + case Ast::AugmentedAssignmentAstType: AstVisitor::visitAugmentedAssignment(dynamic_cast(node)); break; + case Ast::ForAstType: AstVisitor::visitFor(dynamic_cast(node)); break; + case Ast::WhileAstType: AstVisitor::visitWhile(dynamic_cast(node)); break; + case Ast::IfAstType: AstVisitor::visitIf(dynamic_cast(node)); break; + case Ast::WithAstType: AstVisitor::visitWith(dynamic_cast(node)); break; + case Ast::RaiseAstType: AstVisitor::visitRaise(dynamic_cast(node)); break; + case Ast::TryExceptAstType: AstVisitor::visitTryExcept(dynamic_cast(node)); break; + case Ast::TryFinallyAstType: AstVisitor::visitTryFinally(dynamic_cast(node)); break; + case Ast::AssertionAstType: AstVisitor::visitAssertion(dynamic_cast(node)); break; + case Ast::ImportAstType: AstVisitor::visitImport(dynamic_cast(node)); break; + case Ast::ImportFromAstType: AstVisitor::visitImportFrom(dynamic_cast(node)); break; + case Ast::ExecAstType: AstVisitor::visitExec(dynamic_cast(node)); break; + case Ast::GlobalAstType: AstVisitor::visitGlobal(dynamic_cast(node)); break; + case Ast::BreakAstType: AstVisitor::visitBreak(dynamic_cast(node)); break; + case Ast::ContinueAstType: AstVisitor::visitContinue(dynamic_cast(node)); break; + case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; + case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; + case Ast::BooleanOperationAstType: AstVisitor::visitBooleanOperation(dynamic_cast(node)); break; + case Ast::BinaryOperationAstType: AstVisitor::visitBinaryOperation(dynamic_cast(node)); break; + case Ast::UnaryOperationAstType: AstVisitor::visitUnaryOperation(dynamic_cast(node)); break; + case Ast::LambdaAstType: AstVisitor::visitLambda(dynamic_cast(node)); break; + case Ast::IfExpressionAstType: AstVisitor::visitIfExpression(dynamic_cast(node)); break; + case Ast::DictAstType: AstVisitor::visitDict(dynamic_cast(node)); break; + case Ast::SetAstType: AstVisitor::visitSet(dynamic_cast(node)); break; + case Ast::ListComprehensionAstType: AstVisitor::visitListComprehension(dynamic_cast(node)); break; + case Ast::SetComprehensionAstType: AstVisitor::visitSetComprehension(dynamic_cast(node)); break; + case Ast::DictionaryComprehensionAstType: AstVisitor::visitDictionaryComprehension(dynamic_cast(node)); break; + case Ast::GeneratorExpressionAstType: AstVisitor::visitGeneratorExpression(dynamic_cast(node)); break; + case Ast::CompareAstType: AstVisitor::visitCompare(dynamic_cast(node)); break; + case Ast::ReprAstType: AstVisitor::visitRepr(dynamic_cast(node)); break; + case Ast::NumberAstType: AstVisitor::visitNumber(dynamic_cast(node)); break; + case Ast::StringAstType: AstVisitor::visitString(dynamic_cast(node)); break; + case Ast::YieldAstType: AstVisitor::visitYield(dynamic_cast(node)); break; + case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; + case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; + case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; + case Ast::SubscriptAstType: AstVisitor::visitSubscript(dynamic_cast(node)); break; + case Ast::ListAstType: AstVisitor::visitList(dynamic_cast(node)); break; + case Ast::TupleAstType: AstVisitor::visitTuple(dynamic_cast(node)); break; + case Ast::EllipsisAstType: AstVisitor::visitEllipsis(dynamic_cast(node)); break; + case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; + case Ast::ExtendedSliceAstType: AstVisitor::visitExtendedSlice(dynamic_cast(node)); break; + case Ast::IndexAstType: AstVisitor::visitIndex(dynamic_cast(node)); break; + case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; + case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; + case Ast::ComprehensionAstType: AstVisitor::visitComprehension(dynamic_cast(node)); break; + case Ast::ExceptionHandlerAstType: AstVisitor::visitExceptionHandler(dynamic_cast(node)); break; + case Ast::AliasAstType: AstVisitor::visitAlias(dynamic_cast(node)); break; case Ast::ExpressionAstType: break; } } diff --git a/parser/astvisitor.h b/parser/astvisitor.h index 1ba35ca..cf18daa 100644 --- a/parser/astvisitor.h +++ b/parser/astvisitor.h @@ -89,7 +89,6 @@ class KDEVPYTHONPARSER_EXPORT AstVisitor virtual void visitSubscript(SubscriptAst* node) { Q_UNUSED(node); }; virtual void visitList(ListAst* node) { Q_UNUSED(node); }; virtual void visitTuple(TupleAst* node) { Q_UNUSED(node); }; - virtual void visitSlice(SliceAst* node) { Q_UNUSED(node); }; virtual void visitEllipsis(EllipsisAst* node) { Q_UNUSED(node); }; virtual void visitSlice(SliceAst* node) { Q_UNUSED(node); }; virtual void visitExtendedSlice(ExtendedSliceAst* node) { Q_UNUSED(node); }; From 3ce484894c0eec4aa1d208441bc91c8faad69513 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 15:17:55 +0200 Subject: [PATCH 025/118] Added the type attribute --- parser/ast.cpp | 283 ++++++++++++++++++++++++++++++++++++++++++++++--- parser/ast.h | 5 +- 2 files changed, 272 insertions(+), 16 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 016261a..0fedb11 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -29,18 +29,277 @@ namespace Python Ast::Ast( Ast* parent, Ast::AstType type ) : parent(parent), astType( type ) { } Ast::~Ast() { } -Identifier::Identifier(QString value) : value(value) { } -FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } -AssignmentAst::AssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } -PrintAst::PrintAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } -AttributeAst::AttributeAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } -CallAst::CallAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } -NameAst::NameAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, type) { } -PassAst::PassAst(Ast* parent, Ast::AstType type): StatementAst(parent, type) { } -ArgumentsAst::ArgumentsAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } -ExpressionAst::ExpressionAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } -KeywordAst::KeywordAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } -StatementAst::StatementAst(Ast* parent, Ast::AstType type): Ast(parent, type) { } + +ArgumentsAst::ArgumentsAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ArgumentsAstType) +{ + +} + +AssertionAst::AssertionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssertionAstType) +{ + +} + +AssignmentAst::AssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssignmentAstType) +{ + +} + +AttributeAst::AttributeAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::AttributeAstType) +{ + +} + +AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AugmentedAssignmentAstType) +{ + +} + +BinaryOperationAst::BinaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BinaryOperationAstType) +{ + +} + +BooleanOperationAst::BooleanOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BooleanOperationAstType) +{ + +} + +BreakAst::BreakAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::BreakAstType) +{ + +} + +CallAst::CallAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CallAstType) +{ + +} + +ClassDefinitionAst::ClassDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ClassDefinitionAstType) +{ + +} + +CodeAst::CodeAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::CodeAstType) +{ + +} + +CompareAst::CompareAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CompareAstType) +{ + +} + +ComprehensionAst::ComprehensionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ComprehensionAstType) +{ + +} + +ContinueAst::ContinueAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ContinueAstType) +{ + +} + +DeleteAst::DeleteAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::DeleteAstType) +{ + +} + +DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::DictionaryComprehensionAstType) +{ + +} + +EllipsisAst::EllipsisAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::EllipsisAstType) +{ + +} + +ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExceptionHandlerAstType) +{ + +} + +ExecAst::ExecAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ExecAstType) +{ + +} + +ExpressionAst::ExpressionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExpressionAstType) +{ + +} + +ExtendedSliceAst::ExtendedSliceAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::ExtendedSliceAstType) +{ + +} + +ForAst::ForAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ForAstType) +{ + +} + +FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::FunctionDefinitionAstType) +{ + +} + +GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::GeneratorExpressionAstType) +{ + +} + +GlobalAst::GlobalAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::GlobalAstType) +{ + +} + +Identifier::Identifier(QString value) : value(value) +{ + +} + +IfAst::IfAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::IfAstType) +{ + +} + +IfExpressionAst::IfExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::IfExpressionAstType) +{ + +} + +ImportAst::ImportAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportAstType) +{ + +} + +ImportFromAst::ImportFromAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportFromAstType) +{ + +} + +KeywordAst::KeywordAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::KeywordAstType) +{ + +} + +LambdaAst::LambdaAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::LambdaAstType) +{ + +} + +ListAst::ListAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ListAstType) +{ + +} + +NameAst::NameAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NameAstType) +{ + +} + +NumberAst::NumberAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NumberAstType) +{ + +} + +PassAst::PassAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PassAstType) +{ + +} + +PrintAst::PrintAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PrintAstType) +{ + +} + +RaiseAst::RaiseAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::RaiseAstType) +{ + +} + +ReprAst::ReprAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ReprAstType) +{ + +} + +ReturnAst::ReturnAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ReturnAstType) +{ + +} + +SetAst::SetAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetAstType) +{ + +} + +SetComprehensionAst::SetComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetComprehensionAstType) +{ + +} + +SliceAstBase::SliceAstBase(Ast* parent, Ast::AstType type): Ast(parent, Ast::SliceAstType) +{ + +} + +StatementAst::StatementAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::StatementAstType) +{ + +} + +StringAst::StringAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::StringAstType) +{ + +} + +SubscriptAst::SubscriptAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SubscriptAstType) +{ + +} + +TryExceptAst::TryExceptAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryExceptAstType) +{ + +} + +TryFinallyAst::TryFinallyAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryFinallyAstType) +{ + +} + +TupleAst::TupleAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::TupleAstType) +{ + +} + +UnaryOperationAst::UnaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::UnaryOperationAstType) +{ + +} + +WhileAst::WhileAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WhileAstType) +{ + +} + +WithAst::WithAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WithAstType) +{ + +} + +YieldAst::YieldAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::YieldAstType) +{ + +} + +AliasAst::AliasAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::AliasAstType) +{ + +} + } diff --git a/parser/ast.h b/parser/ast.h index 3e97026..68531bd 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -87,7 +87,6 @@ class KDEVPYTHONPARSER_EXPORT Ast ClassDefinitionAstType, ReturnAstType, DeleteAstType, - AugAssignAstType, ForAstType, WhileAstType, IfAstType, @@ -95,7 +94,6 @@ class KDEVPYTHONPARSER_EXPORT Ast RaiseAstType, TryExceptAstType, TryFinallyAstType, - AssertAstType, ImportAstType, ImportFromAstType, ExecAstType, @@ -103,12 +101,12 @@ class KDEVPYTHONPARSER_EXPORT Ast ExprAstType, BreakAstType, ContinueAstType, - AttributesAstType, AssertionAstType, AugmentedAssignmentAstType, DictionaryComprehensionAstType, ExtendedSliceAstType, CodeAstType, + StatementAstType, BooleanOperationAstType, BinaryOperationAstType, @@ -119,7 +117,6 @@ class KDEVPYTHONPARSER_EXPORT Ast SetAstType, ListComprehensionAstType, SetComprehensionAstType, - DictComprehensionAstType, GeneratorExpressionAstType, YieldAstType, CompareAstType, From 03b52bc960d2e2654e22d671ef5c9fef14f2292d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 15:28:27 +0200 Subject: [PATCH 026/118] Hopefully the hand-crafted AST is now complete --- parser/ast.cpp | 108 ++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 0fedb11..6deb4be 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -32,272 +32,272 @@ Ast::~Ast() { } ArgumentsAst::ArgumentsAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ArgumentsAstType) { - + Q_UNUSED(type); } AssertionAst::AssertionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssertionAstType) { - + Q_UNUSED(type); } AssignmentAst::AssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssignmentAstType) { - + Q_UNUSED(type); } AttributeAst::AttributeAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::AttributeAstType) { - + Q_UNUSED(type); } AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AugmentedAssignmentAstType) { - + Q_UNUSED(type); } BinaryOperationAst::BinaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BinaryOperationAstType) { - + Q_UNUSED(type); } BooleanOperationAst::BooleanOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BooleanOperationAstType) { - + Q_UNUSED(type); } BreakAst::BreakAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::BreakAstType) { - + Q_UNUSED(type); } CallAst::CallAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CallAstType) { - + Q_UNUSED(type); } ClassDefinitionAst::ClassDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ClassDefinitionAstType) { - + Q_UNUSED(type); } CodeAst::CodeAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::CodeAstType) { - + Q_UNUSED(type); } CompareAst::CompareAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CompareAstType) { - + Q_UNUSED(type); } ComprehensionAst::ComprehensionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ComprehensionAstType) { - + Q_UNUSED(type); } ContinueAst::ContinueAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ContinueAstType) { - + Q_UNUSED(type); } DeleteAst::DeleteAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::DeleteAstType) { - + Q_UNUSED(type); } DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::DictionaryComprehensionAstType) { - + Q_UNUSED(type); } EllipsisAst::EllipsisAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::EllipsisAstType) { - + Q_UNUSED(type); } ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExceptionHandlerAstType) { - + Q_UNUSED(type); } ExecAst::ExecAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ExecAstType) { - + Q_UNUSED(type); } ExpressionAst::ExpressionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExpressionAstType) { - + Q_UNUSED(type); } ExtendedSliceAst::ExtendedSliceAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::ExtendedSliceAstType) { - + Q_UNUSED(type); } ForAst::ForAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ForAstType) { - + Q_UNUSED(type); } FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::FunctionDefinitionAstType) { - + Q_UNUSED(type); } GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::GeneratorExpressionAstType) { - + Q_UNUSED(type); } GlobalAst::GlobalAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::GlobalAstType) { - + Q_UNUSED(type); } Identifier::Identifier(QString value) : value(value) { - + } IfAst::IfAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::IfAstType) { - + Q_UNUSED(type); } IfExpressionAst::IfExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::IfExpressionAstType) { - + Q_UNUSED(type); } ImportAst::ImportAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportAstType) { - + Q_UNUSED(type); } ImportFromAst::ImportFromAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportFromAstType) { - + Q_UNUSED(type); } KeywordAst::KeywordAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::KeywordAstType) { - + Q_UNUSED(type); } LambdaAst::LambdaAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::LambdaAstType) { - + Q_UNUSED(type); } ListAst::ListAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ListAstType) { - + Q_UNUSED(type); } NameAst::NameAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NameAstType) { - + Q_UNUSED(type); } NumberAst::NumberAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NumberAstType) { - + Q_UNUSED(type); } PassAst::PassAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PassAstType) { - + Q_UNUSED(type); } PrintAst::PrintAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PrintAstType) { - + Q_UNUSED(type); } RaiseAst::RaiseAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::RaiseAstType) { - + Q_UNUSED(type); } ReprAst::ReprAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ReprAstType) { - + Q_UNUSED(type); } ReturnAst::ReturnAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ReturnAstType) { - + Q_UNUSED(type); } SetAst::SetAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetAstType) { - + Q_UNUSED(type); } SetComprehensionAst::SetComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetComprehensionAstType) { - + Q_UNUSED(type); } SliceAstBase::SliceAstBase(Ast* parent, Ast::AstType type): Ast(parent, Ast::SliceAstType) { - + Q_UNUSED(type); } StatementAst::StatementAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::StatementAstType) { - + Q_UNUSED(type); } StringAst::StringAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::StringAstType) { - + Q_UNUSED(type); } SubscriptAst::SubscriptAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SubscriptAstType) { - + Q_UNUSED(type); } TryExceptAst::TryExceptAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryExceptAstType) { - + Q_UNUSED(type); } TryFinallyAst::TryFinallyAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryFinallyAstType) { - + Q_UNUSED(type); } TupleAst::TupleAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::TupleAstType) { - + Q_UNUSED(type); } UnaryOperationAst::UnaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::UnaryOperationAstType) { - + Q_UNUSED(type); } WhileAst::WhileAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WhileAstType) { - + Q_UNUSED(type); } WithAst::WithAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WithAstType) { - + Q_UNUSED(type); } YieldAst::YieldAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::YieldAstType) { - + Q_UNUSED(type); } AliasAst::AliasAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::AliasAstType) { - + Q_UNUSED(type); } From 47a891ad7047afe0967f82a40b5d66922be7fa52 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 17:11:06 +0200 Subject: [PATCH 027/118] (broken) mapping XML <> AST --- parser/ast.h | 3 +- parser/astbuilder.cpp | 70 ++++++++++++++++++++++++++++++++++++++----- parser/astbuilder.h | 4 +-- parser/astvisitor.cpp | 1 + utilities/generate.py | 4 ++- 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index 68531bd..4d690a1 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -98,7 +98,6 @@ class KDEVPYTHONPARSER_EXPORT Ast ImportFromAstType, ExecAstType, GlobalAstType, - ExprAstType, BreakAstType, ContinueAstType, AssertionAstType, @@ -546,6 +545,7 @@ class KDEVPYTHONPARSER_EXPORT EllipsisAst : public SliceAstBase { class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { public: + SliceAst(Ast* parent, AstType type); ExpressionAst* lower; ExpressionAst* upper; ExpressionAst* step; @@ -559,6 +559,7 @@ class KDEVPYTHONPARSER_EXPORT ExtendedSliceAst : public SliceAstBase { class KDEVPYTHONPARSER_EXPORT IndexAst : public SliceAstBase { public: + IndexAst(Ast* parent, AstType type); ExpressionAst* value; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 7c3147a..231c804 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -106,22 +106,78 @@ void AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea Ast* ast; QMap attributeDict; + for ( int i=0; i& attributes) +void AstBuilder::populateAst() { - } - } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 366bc11..d013543 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -62,9 +62,9 @@ class AstBuilder } QMap m_nodeMap; + QStack m_astStack; - AssignmentAst* createAssignmentAst(const QMap& attributes); - Identifier* createIdentifier(const QMap& attributes); + void populateAst(); }; } diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index 1ed1cb9..e1776ba 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -91,6 +91,7 @@ void AstVisitor::visitNode(Ast* node) case Ast::ExceptionHandlerAstType: AstVisitor::visitExceptionHandler(dynamic_cast(node)); break; case Ast::AliasAstType: AstVisitor::visitAlias(dynamic_cast(node)); break; case Ast::ExpressionAstType: break; + case Ast::StatementAstType: break; } } diff --git a/utilities/generate.py b/utilities/generate.py index cdef647..3255ee5 100644 --- a/utilities/generate.py +++ b/utilities/generate.py @@ -7,9 +7,11 @@ f.close() r = re.findall(r'class KDEVPYTHONPARSER_EXPORT (?P\w+)Ast', contents) +r.sort() for item in r: funcname = 'visit' + item astname = item + 'Ast' #print 'virtual void ' + funcname + '(' + astname + '* node);' #print 'virtual void ' + funcname + '(' + astname + '* node) { Q_UNUSED(node); };' - print 'case Ast::' + astname + 'Type:\t\t\t' + 'AstVisitor::' + funcname + '(dynamic_cast<' + astname + '>(node)); break;' \ No newline at end of file + #print 'case Ast::' + astname + 'Type:\t\t\t' + 'AstVisitor::' + funcname + '(dynamic_cast<' + astname + '>(node)); break;' + print 'else if ( name == "' + astname.lower() +'" ) ast = new ' + astname + '();' \ No newline at end of file From 6487af30a3b8f4d74137a354bec926d467df33d4 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 17 Oct 2010 17:45:41 +0200 Subject: [PATCH 028/118] Fixed a large amount of small bugs --- parser/ast.cpp | 233 +++++++++++++++++++++++------------------- parser/ast.h | 114 +++++++++++---------- parser/astbuilder.cpp | 131 ++++++++++++------------ 3 files changed, 254 insertions(+), 224 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 6deb4be..2ed31f6 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -28,131 +28,152 @@ namespace Python // there's nothing happening here, don't bother reading the code Ast::Ast( Ast* parent, Ast::AstType type ) : parent(parent), astType( type ) { } +Ast::Ast() { } Ast::~Ast() { } -ArgumentsAst::ArgumentsAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ArgumentsAstType) +ArgumentsAst::ArgumentsAst(Ast* parent): Ast(parent, Ast::ArgumentsAstType) { - Q_UNUSED(type); + } -AssertionAst::AssertionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssertionAstType) +AssertionAst::AssertionAst(Ast* parent): StatementAst(parent, Ast::AssertionAstType) { - Q_UNUSED(type); + } -AssignmentAst::AssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AssignmentAstType) +AssignmentAst::AssignmentAst(Ast* parent): StatementAst(parent, Ast::AssignmentAstType) { - Q_UNUSED(type); + } -AttributeAst::AttributeAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::AttributeAstType) +AttributeAst::AttributeAst(Ast* parent): ExpressionAst(parent, Ast::AttributeAstType) { - Q_UNUSED(type); + } -AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::AugmentedAssignmentAstType) +AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent): StatementAst(parent, Ast::AugmentedAssignmentAstType) { - Q_UNUSED(type); + } -BinaryOperationAst::BinaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BinaryOperationAstType) +BinaryOperationAst::BinaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::BinaryOperationAstType) { - Q_UNUSED(type); + } -BooleanOperationAst::BooleanOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::BooleanOperationAstType) +BooleanOperationAst::BooleanOperationAst(Ast* parent): ExpressionAst(parent, Ast::BooleanOperationAstType) { - Q_UNUSED(type); + } -BreakAst::BreakAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::BreakAstType) +BreakAst::BreakAst(Ast* parent): StatementAst(parent, Ast::BreakAstType) { - Q_UNUSED(type); + } -CallAst::CallAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CallAstType) +CallAst::CallAst(Ast* parent): ExpressionAst(parent, Ast::CallAstType) { - Q_UNUSED(type); + } -ClassDefinitionAst::ClassDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ClassDefinitionAstType) +ClassDefinitionAst::ClassDefinitionAst(Ast* parent): StatementAst(parent, Ast::ClassDefinitionAstType) { - Q_UNUSED(type); + } -CodeAst::CodeAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::CodeAstType) +CodeAst::CodeAst() { - Q_UNUSED(type); + } -CompareAst::CompareAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::CompareAstType) +CompareAst::CompareAst(Ast* parent): ExpressionAst(parent, Ast::CompareAstType) { - Q_UNUSED(type); + } -ComprehensionAst::ComprehensionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ComprehensionAstType) +ComprehensionAst::ComprehensionAst(Ast* parent): Ast(parent, Ast::ComprehensionAstType) { - Q_UNUSED(type); + } -ContinueAst::ContinueAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ContinueAstType) +ContinueAst::ContinueAst(Ast* parent): StatementAst(parent, Ast::ContinueAstType) { - Q_UNUSED(type); + } -DeleteAst::DeleteAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::DeleteAstType) +DeleteAst::DeleteAst(Ast* parent): StatementAst(parent, Ast::DeleteAstType) { - Q_UNUSED(type); + } -DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::DictionaryComprehensionAstType) +DictAst::DictAst(Ast* parent): ExpressionAst(parent, Ast::DictAstType) { - Q_UNUSED(type); + } -EllipsisAst::EllipsisAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::EllipsisAstType) +IndexAst::IndexAst(Ast* parent): SliceAstBase(parent, Ast::IndexAstType) { - Q_UNUSED(type); + } -ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExceptionHandlerAstType) +SliceAst::SliceAst(Ast* parent): SliceAstBase(parent, Ast::SliceAstType) { - Q_UNUSED(type); + } -ExecAst::ExecAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ExecAstType) +DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::DictionaryComprehensionAstType) { - Q_UNUSED(type); + } -ExpressionAst::ExpressionAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::ExpressionAstType) +EllipsisAst::EllipsisAst(Ast* parent): SliceAstBase(parent, Ast::EllipsisAstType) { - Q_UNUSED(type); + } -ExtendedSliceAst::ExtendedSliceAst(Ast* parent, Ast::AstType type): SliceAstBase(parent, Ast::ExtendedSliceAstType) +ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::ExceptionHandlerAstType) { - Q_UNUSED(type); + } -ForAst::ForAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ForAstType) +ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType) { - Q_UNUSED(type); + } -FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::FunctionDefinitionAstType) +ListComprehensionAst::ListComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::ListComprehensionAstType) { - Q_UNUSED(type); + } -GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::GeneratorExpressionAstType) +ExpressionAst::ExpressionAst(Ast* parent, AstType type): Ast(parent, type) { - Q_UNUSED(type); + } -GlobalAst::GlobalAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::GlobalAstType) +ExtendedSliceAst::ExtendedSliceAst(Ast* parent): SliceAstBase(parent, Ast::ExtendedSliceAstType) { - Q_UNUSED(type); + +} + +ForAst::ForAst(Ast* parent): StatementAst(parent, Ast::ForAstType) +{ + +} + +FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent): StatementAst(parent, Ast::FunctionDefinitionAstType) +{ + +} + +GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent): ExpressionAst(parent, Ast::GeneratorExpressionAstType) +{ + +} + +GlobalAst::GlobalAst(Ast* parent): StatementAst(parent, Ast::GlobalAstType) +{ + } Identifier::Identifier(QString value) : value(value) @@ -160,144 +181,144 @@ Identifier::Identifier(QString value) : value(value) } -IfAst::IfAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::IfAstType) +IfAst::IfAst(Ast* parent): StatementAst(parent, Ast::IfAstType) { - Q_UNUSED(type); + } -IfExpressionAst::IfExpressionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::IfExpressionAstType) +IfExpressionAst::IfExpressionAst(Ast* parent): ExpressionAst(parent, Ast::IfExpressionAstType) { - Q_UNUSED(type); + } -ImportAst::ImportAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportAstType) +ImportAst::ImportAst(Ast* parent): StatementAst(parent, Ast::ImportAstType) { - Q_UNUSED(type); + } -ImportFromAst::ImportFromAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ImportFromAstType) +ImportFromAst::ImportFromAst(Ast* parent): StatementAst(parent, Ast::ImportFromAstType) { - Q_UNUSED(type); + } -KeywordAst::KeywordAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::KeywordAstType) +KeywordAst::KeywordAst(Ast* parent): Ast(parent, Ast::KeywordAstType) { - Q_UNUSED(type); + } -LambdaAst::LambdaAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::LambdaAstType) +LambdaAst::LambdaAst(Ast* parent): ExpressionAst(parent, Ast::LambdaAstType) { - Q_UNUSED(type); + } -ListAst::ListAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ListAstType) +ListAst::ListAst(Ast* parent): ExpressionAst(parent, Ast::ListAstType) { - Q_UNUSED(type); + } -NameAst::NameAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NameAstType) +NameAst::NameAst(Ast* parent): ExpressionAst(parent, Ast::NameAstType) { - Q_UNUSED(type); + } -NumberAst::NumberAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::NumberAstType) +NumberAst::NumberAst(Ast* parent): ExpressionAst(parent, Ast::NumberAstType) { - Q_UNUSED(type); + } -PassAst::PassAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PassAstType) +PassAst::PassAst(Ast* parent): StatementAst(parent, Ast::PassAstType) { - Q_UNUSED(type); + } -PrintAst::PrintAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::PrintAstType) +PrintAst::PrintAst(Ast* parent): StatementAst(parent, Ast::PrintAstType) { - Q_UNUSED(type); + } -RaiseAst::RaiseAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::RaiseAstType) +RaiseAst::RaiseAst(Ast* parent): StatementAst(parent, Ast::RaiseAstType) { - Q_UNUSED(type); + } -ReprAst::ReprAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::ReprAstType) +ReprAst::ReprAst(Ast* parent): ExpressionAst(parent, Ast::ReprAstType) { - Q_UNUSED(type); + } -ReturnAst::ReturnAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::ReturnAstType) +ReturnAst::ReturnAst(Ast* parent): StatementAst(parent, Ast::ReturnAstType) { - Q_UNUSED(type); + } -SetAst::SetAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetAstType) +SetAst::SetAst(Ast* parent): ExpressionAst(parent, Ast::SetAstType) { - Q_UNUSED(type); + } -SetComprehensionAst::SetComprehensionAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SetComprehensionAstType) +SetComprehensionAst::SetComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::SetComprehensionAstType) { - Q_UNUSED(type); + } -SliceAstBase::SliceAstBase(Ast* parent, Ast::AstType type): Ast(parent, Ast::SliceAstType) +SliceAstBase::SliceAstBase(Ast* parent, AstType type): Ast(parent, type) { - Q_UNUSED(type); + } -StatementAst::StatementAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::StatementAstType) +StatementAst::StatementAst(Ast* parent, AstType type): Ast(parent, type) { - Q_UNUSED(type); + } -StringAst::StringAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::StringAstType) +StringAst::StringAst(Ast* parent): ExpressionAst(parent, Ast::StringAstType) { - Q_UNUSED(type); + } -SubscriptAst::SubscriptAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::SubscriptAstType) +SubscriptAst::SubscriptAst(Ast* parent): ExpressionAst(parent, Ast::SubscriptAstType) { - Q_UNUSED(type); + } -TryExceptAst::TryExceptAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryExceptAstType) +TryExceptAst::TryExceptAst(Ast* parent): StatementAst(parent, Ast::TryExceptAstType) { - Q_UNUSED(type); + } -TryFinallyAst::TryFinallyAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::TryFinallyAstType) +TryFinallyAst::TryFinallyAst(Ast* parent): StatementAst(parent, Ast::TryFinallyAstType) { - Q_UNUSED(type); + } -TupleAst::TupleAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::TupleAstType) +TupleAst::TupleAst(Ast* parent): ExpressionAst(parent, Ast::TupleAstType) { - Q_UNUSED(type); + } -UnaryOperationAst::UnaryOperationAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::UnaryOperationAstType) +UnaryOperationAst::UnaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::UnaryOperationAstType) { - Q_UNUSED(type); + } -WhileAst::WhileAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WhileAstType) +WhileAst::WhileAst(Ast* parent): StatementAst(parent, Ast::WhileAstType) { - Q_UNUSED(type); + } -WithAst::WithAst(Ast* parent, Ast::AstType type): StatementAst(parent, Ast::WithAstType) +WithAst::WithAst(Ast* parent): StatementAst(parent, Ast::WithAstType) { - Q_UNUSED(type); + } -YieldAst::YieldAst(Ast* parent, Ast::AstType type): ExpressionAst(parent, Ast::YieldAstType) +YieldAst::YieldAst(Ast* parent): ExpressionAst(parent, Ast::YieldAstType) { - Q_UNUSED(type); + } -AliasAst::AliasAst(Ast* parent, Ast::AstType type): Ast(parent, Ast::AliasAstType) +AliasAst::AliasAst(Ast* parent): Ast(parent, Ast::AliasAstType) { - Q_UNUSED(type); + } diff --git a/parser/ast.h b/parser/ast.h index 4d690a1..c0acf23 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -78,7 +78,6 @@ class KDEVPYTHONPARSER_EXPORT Ast AssignmentAstType, PrintAstType, PassAstType, - ExpressionAstType, NameAstType, CallAstType, AttributeAstType, @@ -106,6 +105,7 @@ class KDEVPYTHONPARSER_EXPORT Ast ExtendedSliceAstType, CodeAstType, StatementAstType, + ExpressionAstType, BooleanOperationAstType, BinaryOperationAstType, @@ -176,6 +176,7 @@ class KDEVPYTHONPARSER_EXPORT Ast }; Ast(Ast* parent, AstType type); + Ast(); virtual ~Ast(); Ast* parent; AstType astType; @@ -193,26 +194,26 @@ class KDEVPYTHONPARSER_EXPORT Ast // this replaces ModuleAst class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast { public: - CodeAst(Ast* parent, AstType type); + CodeAst(); QList body; }; /** Statement classes **/ class KDEVPYTHONPARSER_EXPORT StatementAst : public Ast { public: - StatementAst(Ast* parent, Ast::AstType type); + StatementAst(Ast* parent, AstType type); }; class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { public: - FunctionDefinitionAst(Ast* parent, Ast::AstType type); + FunctionDefinitionAst(Ast* parent); Identifier* name; ArgumentsAst* arguments; }; class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { public: - ClassDefinitionAst(Ast* parent, AstType type); + ClassDefinitionAst(Ast* parent); Identifier* name; QList baseClasses; QList body; @@ -221,26 +222,26 @@ class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT ReturnAst : public StatementAst { public: - ReturnAst(Ast* parent, AstType type); + ReturnAst(Ast* parent); ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT DeleteAst : public StatementAst { public: - DeleteAst(Ast* parent, AstType type); + DeleteAst(Ast* parent); QList targets; }; class KDEVPYTHONPARSER_EXPORT AssignmentAst : public StatementAst { public: - AssignmentAst(Ast* parent, Ast::AstType type); + AssignmentAst(Ast* parent); QList targets; ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT AugmentedAssignmentAst : public StatementAst { public: - AugmentedAssignmentAst(Ast* parent, AstType type); + AugmentedAssignmentAst(Ast* parent); ExpressionAst* target; Ast::OperatorTypes op; ExpressionAst* value; @@ -248,7 +249,7 @@ class KDEVPYTHONPARSER_EXPORT AugmentedAssignmentAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { public: - ForAst(Ast* parent, AstType type); + ForAst(Ast* parent); ExpressionAst* target; ExpressionAst* iterator; QList body; @@ -257,7 +258,7 @@ class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst { public: - WhileAst(Ast* parent, AstType type); + WhileAst(Ast* parent); ExpressionAst* condition; QList body; QList orelse; @@ -265,7 +266,7 @@ class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst { public: - IfAst(Ast* parent, AstType type); + IfAst(Ast* parent); ExpressionAst* condition; QList body; QList orelse; @@ -273,7 +274,7 @@ class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { public: - WithAst(Ast* parent, AstType type); + WithAst(Ast* parent); ExpressionAst* contextExpression; ExpressionAst* optionalVars; QList body; @@ -281,14 +282,14 @@ class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst { public: - RaiseAst(Ast* parent, AstType type); + RaiseAst(Ast* parent); ExpressionAst* type; // TODO check what the other things in the grammar actually are and add them }; class KDEVPYTHONPARSER_EXPORT TryExceptAst : public StatementAst { public: - TryExceptAst(Ast* parent, AstType type); + TryExceptAst(Ast* parent); QList body; QList handlers; QList orelse; @@ -296,27 +297,27 @@ class KDEVPYTHONPARSER_EXPORT TryExceptAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT TryFinallyAst : public StatementAst { public: - TryFinallyAst(Ast* parent, AstType type); + TryFinallyAst(Ast* parent); QList body; QList finalbody; }; class KDEVPYTHONPARSER_EXPORT AssertionAst : public StatementAst { public: - AssertionAst(Ast* parent, AstType type); + AssertionAst(Ast* parent); ExpressionAst* condition; ExpressionAst* message; }; class KDEVPYTHONPARSER_EXPORT ImportAst : public StatementAst { public: - ImportAst(Ast* parent, AstType type); + ImportAst(Ast* parent); QList names; }; class KDEVPYTHONPARSER_EXPORT ImportFromAst : public StatementAst { public: - ImportFromAst(Ast* parent, AstType type); + ImportFromAst(Ast* parent); Identifier* module; QList names; int level; @@ -324,7 +325,7 @@ class KDEVPYTHONPARSER_EXPORT ImportFromAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst { public: - ExecAst(Ast* parent, AstType type); + ExecAst(Ast* parent); ExpressionAst* body; ExpressionAst* globals; ExpressionAst* locals; @@ -332,7 +333,7 @@ class KDEVPYTHONPARSER_EXPORT ExecAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst { public: - GlobalAst(Ast* parent, AstType type); + GlobalAst(Ast* parent); QList names; }; @@ -340,17 +341,17 @@ class KDEVPYTHONPARSER_EXPORT GlobalAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT BreakAst : public StatementAst { public: - BreakAst(Ast* parent, AstType type); + BreakAst(Ast* parent); }; class KDEVPYTHONPARSER_EXPORT ContinueAst : public StatementAst { public: - ContinueAst(Ast* parent, AstType type); + ContinueAst(Ast* parent); }; class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { public: - PrintAst(Ast* parent, AstType type); + PrintAst(Ast* parent); ExpressionAst* destination; QList values; bool newline; @@ -358,14 +359,14 @@ class KDEVPYTHONPARSER_EXPORT PrintAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT PassAst : public StatementAst { public: - PassAst(Ast* parent, AstType type); + PassAst(Ast* parent); }; /** Expression classes **/ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { public: - ExpressionAst(Ast* parent, AstType type); + ExpressionAst(Ast* parent, AstType type = Ast::ExpressionAstType); enum Context { Load, // the object is read Store, // the object is written @@ -373,18 +374,19 @@ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { Parameter, // the object is passed as a parameter AugLoad, AugStore // Augmented assignments, like a += 1 }; + ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT BooleanOperationAst : public ExpressionAst { public: - BooleanOperationAst(Ast* parent, AstType type); + BooleanOperationAst(Ast* parent); Ast::BooleanOperationTypes type; QList values; }; class KDEVPYTHONPARSER_EXPORT BinaryOperationAst : public ExpressionAst { public: - BinaryOperationAst(Ast* parent, AstType type); + BinaryOperationAst(Ast* parent); Ast::OperatorTypes type; ExpressionAst* lhs; ExpressionAst* rhs; @@ -392,21 +394,21 @@ class KDEVPYTHONPARSER_EXPORT BinaryOperationAst : public ExpressionAst { class KDEVPYTHONPARSER_EXPORT UnaryOperationAst : public ExpressionAst { public: - UnaryOperationAst(Ast* parent, AstType type); + UnaryOperationAst(Ast* parent); Ast::UnaryOperatorTypes type; ExpressionAst* operand; }; class KDEVPYTHONPARSER_EXPORT LambdaAst : public ExpressionAst { public: - LambdaAst(Ast* parent, AstType type); + LambdaAst(Ast* parent); ArgumentsAst* arguments; ExpressionAst* body; }; class KDEVPYTHONPARSER_EXPORT IfExpressionAst : public ExpressionAst { public: - IfExpressionAst(Ast* parent, AstType type); + IfExpressionAst(Ast* parent); ExpressionAst* condition; ExpressionAst* body; ExpressionAst* orelse; @@ -414,32 +416,34 @@ class KDEVPYTHONPARSER_EXPORT IfExpressionAst : public ExpressionAst { class KDEVPYTHONPARSER_EXPORT DictAst : public ExpressionAst { public: + DictAst(Ast* parent); QList keys; QList values; }; class KDEVPYTHONPARSER_EXPORT SetAst : public ExpressionAst { public: - SetAst(Ast* parent, AstType type); + SetAst(Ast* parent); QList elements; }; class KDEVPYTHONPARSER_EXPORT ListComprehensionAst : public ExpressionAst { public: + ListComprehensionAst(Ast* parent); ExpressionAst* element; QList generators; }; class KDEVPYTHONPARSER_EXPORT SetComprehensionAst : public ExpressionAst { public: - SetComprehensionAst(Ast* parent, AstType type); + SetComprehensionAst(Ast* parent); ExpressionAst* element; QList generators; }; class KDEVPYTHONPARSER_EXPORT DictionaryComprehensionAst : public ExpressionAst { public: - DictionaryComprehensionAst(Ast* parent, AstType type); + DictionaryComprehensionAst(Ast* parent); ExpressionAst* key; ExpressionAst* value; QList generators; @@ -447,14 +451,14 @@ class KDEVPYTHONPARSER_EXPORT DictionaryComprehensionAst : public ExpressionAst class KDEVPYTHONPARSER_EXPORT GeneratorExpressionAst : public ExpressionAst { public: - GeneratorExpressionAst(Ast* parent, AstType type); + GeneratorExpressionAst(Ast* parent); ExpressionAst* element; QList generators; }; class KDEVPYTHONPARSER_EXPORT CompareAst : public ExpressionAst { public: - CompareAst(Ast* parent, AstType type); + CompareAst(Ast* parent); ExpressionAst* leftmostElement; QList operators; QList comparands; @@ -463,38 +467,38 @@ class KDEVPYTHONPARSER_EXPORT CompareAst : public ExpressionAst { // TODO whats this exactly? class KDEVPYTHONPARSER_EXPORT ReprAst : public ExpressionAst { public: - ReprAst(Ast* parent, AstType type); + ReprAst(Ast* parent); ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT NumberAst : public ExpressionAst { public: - NumberAst(Ast* parent, AstType type); + NumberAst(Ast* parent); QString value; // everything else would be even more strange }; class KDEVPYTHONPARSER_EXPORT StringAst : public ExpressionAst { public: - StringAst(Ast* parent, AstType type); + StringAst(Ast* parent); QString value; }; class KDEVPYTHONPARSER_EXPORT YieldAst : public ExpressionAst { public: - YieldAst(Ast* parent, AstType type); + YieldAst(Ast* parent); ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT NameAst : public ExpressionAst { public: - NameAst(Ast* parent, AstType type); + NameAst(Ast* parent); Identifier* identifier; ExpressionAst::Context context; }; class KDEVPYTHONPARSER_EXPORT CallAst : public ExpressionAst { public: - CallAst(Ast* parent, AstType type); + CallAst(Ast* parent); ExpressionAst* function; QList arguments; QList keywords; @@ -504,7 +508,7 @@ class KDEVPYTHONPARSER_EXPORT CallAst : public ExpressionAst { class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { public: - AttributeAst(Ast* parent, AstType type); + AttributeAst(Ast* parent); ExpressionAst* value; Identifier* attribute; ExpressionAst::Context context; @@ -512,7 +516,7 @@ class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { class KDEVPYTHONPARSER_EXPORT SubscriptAst : public ExpressionAst { public: - SubscriptAst(Ast* parent, AstType type); + SubscriptAst(Ast* parent); ExpressionAst* value; SliceAst* slice; ExpressionAst::Context context; @@ -520,14 +524,14 @@ class KDEVPYTHONPARSER_EXPORT SubscriptAst : public ExpressionAst { class KDEVPYTHONPARSER_EXPORT ListAst : public ExpressionAst { public: - ListAst(Ast* parent, AstType type); + ListAst(Ast* parent); QList elements; ExpressionAst::Context context; }; class KDEVPYTHONPARSER_EXPORT TupleAst : public ExpressionAst { public: - TupleAst(Ast* parent, AstType type); + TupleAst(Ast* parent); QList elements; ExpressionAst::Context context; }; @@ -540,12 +544,12 @@ class KDEVPYTHONPARSER_EXPORT SliceAstBase : public Ast { class KDEVPYTHONPARSER_EXPORT EllipsisAst : public SliceAstBase { public: - EllipsisAst(Ast* parent, AstType type); + EllipsisAst(Ast* parent); }; class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { public: - SliceAst(Ast* parent, AstType type); + SliceAst(Ast* parent); ExpressionAst* lower; ExpressionAst* upper; ExpressionAst* step; @@ -553,20 +557,20 @@ class KDEVPYTHONPARSER_EXPORT SliceAst : public SliceAstBase { class KDEVPYTHONPARSER_EXPORT ExtendedSliceAst : public SliceAstBase { public: - ExtendedSliceAst(Ast* parent, AstType type); + ExtendedSliceAst(Ast* parent); QList dims; }; class KDEVPYTHONPARSER_EXPORT IndexAst : public SliceAstBase { public: - IndexAst(Ast* parent, AstType type); + IndexAst(Ast* parent); ExpressionAst* value; }; /** Independent classes **/ class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { public: - ArgumentsAst(Ast* parent, AstType type); + ArgumentsAst(Ast* parent); QList arguments; QList defaultValues; Identifier* vararg; @@ -575,14 +579,14 @@ class KDEVPYTHONPARSER_EXPORT ArgumentsAst : public Ast { class KDEVPYTHONPARSER_EXPORT KeywordAst : public Ast { public: - KeywordAst(Ast* parent, AstType type); + KeywordAst(Ast* parent); Identifier* argumentName; ExpressionAst* value; }; class KDEVPYTHONPARSER_EXPORT ComprehensionAst : public Ast { public: - ComprehensionAst(Ast* parent, AstType type); + ComprehensionAst(Ast* parent); ExpressionAst* target; ExpressionAst* iterator; QList conditions; @@ -590,7 +594,7 @@ class KDEVPYTHONPARSER_EXPORT ComprehensionAst : public Ast { class KDEVPYTHONPARSER_EXPORT ExceptionHandlerAst : public Ast { public: - ExceptionHandlerAst(Ast* parent, AstType type); + ExceptionHandlerAst(Ast* parent); ExpressionAst* type; ExpressionAst* name; QList body; @@ -598,7 +602,7 @@ class KDEVPYTHONPARSER_EXPORT ExceptionHandlerAst : public Ast { class KDEVPYTHONPARSER_EXPORT AliasAst : public Ast { public: - AliasAst(Ast* parent, AstType type); + AliasAst(Ast* parent); Identifier* name; Identifier* asName; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 231c804..547a530 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -86,18 +86,22 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok } // We recursively continue parsing if we find another element else if ( token == QXmlStreamReader::StartElement ) { + // Here we can now assemble an actual node with the attributes extracted above + kDebug() << "Token: " << token << "; " << "Name: " << currentElementName << "; Text: " << currentElementText; + for ( int i=0; i Date: Sun, 17 Oct 2010 22:25:34 +0200 Subject: [PATCH 029/118] Fixed various bugs. Can now start to implement population functions --- duchain/contextbuilder.cpp | 67 +++++++------- duchain/contextbuilder.h | 5 +- duchain/declarationbuilder.cpp | 155 ++++++++++++++------------------- duchain/declarationbuilder.h | 6 +- duchain/typebuilder.h | 2 +- duchain/usebuilder.cpp | 20 ++--- duchain/usebuilder.h | 5 +- parser/ast.h | 17 ++-- parser/astbuilder.cpp | 132 ++++++++++++++++++++++++++-- parser/astbuilder.h | 16 ++-- parser/astdefaultvisitor.cpp | 4 +- pythonparsejob.cpp | 2 +- utilities/classes | 2 +- 13 files changed, 267 insertions(+), 166 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 3255d06..449a665 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include "pythoneditorintegrator.h" #include "dumpchain.h" #include @@ -92,9 +91,9 @@ RangeInRevision ContextBuilder::editorFindRange( Ast* fromNode, Ast* toNode ) return editor()->findRange(fromNode, toNode); } -QualifiedIdentifier ContextBuilder::identifierForNode( IdentifierAst* node ) +QualifiedIdentifier ContextBuilder::identifierForNode( Python::Identifier* node ) { - return QualifiedIdentifier( node->identifier ); + return QualifiedIdentifier( node->value ); } void ContextBuilder::addImportedContexts() @@ -124,10 +123,10 @@ void ContextBuilder::openContextForStatementList( const QList& l void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "Visiting Class Declaration"; - openContext( node, DUContext::Class, identifierForNode( node->className ) ); + openContext( node, DUContext::Class, identifierForNode( node->name ) ); addImportedContexts(); - visitNodeList( node->inheritance ); - visitNodeList( node->classBody ); + visitNodeList( node->baseClasses ); + visitNodeList( node->body ); closeContext(); } @@ -160,31 +159,31 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) visitNodeList( node->decorators ); - if ( node->parameters.count() > 0 ) + if ( node->arguments ) { - DUContext* funcctx = openContext( node->parameters.first(), node->parameters.last(), DUContext::Function, identifierForNode( node->functionName ) ); + DUContext* funcctx = openContext( node->arguments, node->arguments, DUContext::Function, identifierForNode( node->name ) ); addImportedContexts(); - visitNodeList( node->parameters ); + visitNode( node->arguments ); closeContext(); m_importedParentContexts.append( funcctx ); } - openContextForStatementList( node->functionBody ); + openContextForStatementList( node->body ); m_importedParentContexts.clear(); } void ContextBuilder::visitFor( ForAst* node ) { kDebug() << "Found for, building context"; - DUContext* forctx = openContext( node->assignedTargets.first(), node->assignedTargets.last(), DUContext::Other ); - visitNodeList( node->assignedTargets ); + DUContext* forctx = openContext( node, KDevelop::DUContext::Other ); + visitNode(node->target); closeContext(); - visitNodeList( node->iterable ); + visitNode(node->iterator); m_importedParentContexts = QList() << forctx; - openContextForStatementList( node->forBody ); - openContextForStatementList( node->elseBody ); + openContextForStatementList( node->body ); + openContextForStatementList( node->orelse ); m_importedParentContexts.clear(); } @@ -192,45 +191,45 @@ void ContextBuilder::visitWhile( WhileAst* node ) { kDebug() << "Creating contexts for while"; visitNode( node->condition ); - openContextForStatementList( node->whileBody ); - openContextForStatementList( node->elseBody ); + openContextForStatementList( node->body ); + openContextForStatementList( node->orelse ); } void ContextBuilder::visitWith( WithAst * node ) { kDebug() << "creating contexts for With"; - m_importedParentContexts = QList() << openContext( node->name, DUContext::Other ); - visitNode( node->name ); + m_importedParentContexts = QList() << openContext( node->contextExpression, DUContext::Other ); + visitNode( node->contextExpression ); closeContext(); openContextForStatementList( node->body ); m_importedParentContexts.clear(); } -void ContextBuilder::visitTry( TryAst* node ) -{ - kDebug() << "creating contexts for try"; - openContextForStatementList( node->tryBody ); - visitNodeList( node->exceptions ); - openContextForStatementList( node->elseBody ); - openContextForStatementList( node->finallyBody ); -} +// void ContextBuilder::visitTry( TryAst* node ) +// { +// kDebug() << "creating contexts for try"; +// openContextForStatementList( node->tryBody ); +// visitNodeList( node->exceptions ); +// openContextForStatementList( node->elseBody ); +// openContextForStatementList( node->finallyBody ); +// } void ContextBuilder::visitIf( IfAst* node ) { kDebug() << "creating contexts for if"; - visitNode( node->ifCondition ); - openContextForStatementList( node->ifBody ); - QList< QPair< ExpressionAst*, QList > >::ConstIterator it, end = node->elseIfBodies.end(); + visitNode( node->condition ); + openContextForStatementList( node->body ); + + QList ::const_iterator it, end = node->body.constEnd(); - for ( it = node->elseIfBodies.begin(); it != end; ++it ) + for ( it = node->body.begin(); it != end; ++it ) { - visitNode( ( *it ).first ); - openContextForStatementList( ( *it ).second ); + visitNode(*it); } - openContextForStatementList( node->elseBody ); + openContextForStatementList( node->orelse ); } } diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 82f57b4..af4a4cc 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -40,7 +40,7 @@ namespace Python class PythonEditorIntegrator; class ParseSession; -typedef KDevelop::AbstractContextBuilder ContextBuilderBase; +typedef KDevelop::AbstractContextBuilder ContextBuilderBase; class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public Python::AstDefaultVisitor { @@ -55,7 +55,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void setContextOnNode( Ast* node, KDevelop::DUContext* context ); virtual KDevelop::DUContext* contextFromNode( Ast* node ); virtual KDevelop::RangeInRevision editorFindRange( Ast* fromNode, Ast* toNode ); - virtual KDevelop::QualifiedIdentifier identifierForNode( IdentifierAst* node ); + virtual KDevelop::QualifiedIdentifier identifierForNode( Identifier* node ); void addImportedContexts(); @@ -65,7 +65,6 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitWith( WithAst* node ); virtual void visitWhile( WhileAst* node ); virtual void visitIf( IfAst* node ); - virtual void visitTry( TryAst* node ); PythonEditorIntegrator *m_editor; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index baaecbd..95d7bb0 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -67,28 +67,6 @@ DeclarationBuilder:: ~DeclarationBuilder() { } -// This is not used anywhere and causes build errors, so... bye. -/* -template -DeclarationType* DeclarationBuilder::specialDeclaration( KTextEditor::SmartRange* smartRange, - const KDevelop::SimpleRange& range ) -{ - DeclarationType* ret = new DeclarationType( m_editor->currentUrl(), range, currentContext() ); - ret->setSmartRange( smartRange ); - return ret; -} - -template -DeclarationType* DeclarationBuilder::specialDeclaration( KTextEditor::SmartRange* smartRange, - const KDevelop::SimpleRange& range, - int scope ) -{ - DeclarationType* ret = new DeclarationType( m_editor->currentUrl(), range, currentContext() ); - ret->setSmartRange( smartRange ); - return ret; -} -*/ - void DeclarationBuilder::closeDeclaration() { if ( lastContext() ) @@ -102,39 +80,39 @@ void DeclarationBuilder::closeDeclaration() DeclarationBuilderBase::closeDeclaration(); } -void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) -{ - Python::AstDefaultVisitor::visitIdentifierTarget(node); - - QList existingLocalDeclarations; - - { - DUChainWriteLocker lock( DUChain::lock() ); - RangeInRevision range = editorFindRange(node, node); - CursorInRevision stopSearching = range.start; - QualifiedIdentifier id = identifierForNode(node->identifier); - existingLocalDeclarations = currentContext()->findLocalDeclarations(id.last(), stopSearching); - } - - if ( ! existingLocalDeclarations.length() ) { - Declaration *dec = openDeclaration( node->identifier, node); - closeDeclaration(); - { - DUChainWriteLocker lock(DUChain::lock()); - dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); - } - } - else { - kDebug() << "Declaration does already exist, not updating" << node->identifier->identifier.toAscii(); - } -} +// void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) +// { +// Python::AstDefaultVisitor::visitIdentifierTarget(node); +// +// QList existingLocalDeclarations; +// +// { +// DUChainWriteLocker lock( DUChain::lock() ); +// RangeInRevision range = editorFindRange(node, node); +// CursorInRevision stopSearching = range.start; +// QualifiedIdentifier id = identifierForNode(node->identifier); +// existingLocalDeclarations = currentContext()->findLocalDeclarations(id.last(), stopSearching); +// } +// +// if ( ! existingLocalDeclarations.length() ) { +// Declaration *dec = openDeclaration( node->identifier, node); +// closeDeclaration(); +// { +// DUChainWriteLocker lock(DUChain::lock()); +// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); +// } +// } +// else { +// kDebug() << "Declaration does already exist, not updating" << node->identifier->identifier.toAscii(); +// } +// } void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; ContextBuilder::visitClassDefinition( node ); - openDeclaration( node->className, node ); + openDeclaration( node->name, node ); eventuallyAssignInternalContext(); closeDeclaration(); } @@ -142,7 +120,7 @@ void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << "opening function definition"; - FunctionDeclaration* dec = openDeclaration( node->functionName, node ); + FunctionDeclaration* dec = openDeclaration( node->name, node ); FunctionType::Ptr type(new FunctionType); @@ -165,45 +143,46 @@ void DeclarationBuilder::visitLambda( LambdaAst* node ) // closeDeclaration(); } -void DeclarationBuilder::visitDefaultParameter( DefaultParameterAst* node ) +void DeclarationBuilder::visitArguments( ArgumentsAst* node ) { - ContextBuilder::visitDefaultParameter( node ); -// AbstractFunctionDeclaration* function = currentDeclaration(); - AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); - - if( function ) - { - if( node->value ) - { - //Not sure what to do here, C++ simply adds the source code as default parameter, but that doesn't sound sane... - } - //simple case, we have an identifier parameter - if( node->name->astType == Ast::IdentifierParameterPartAst ) - { - function->addDefaultParameter(IndexedString("foo")); - kDebug() << function->defaultParametersSize(); - - Q_ASSERT(hasCurrentType()); - FunctionType::Ptr type = currentType(); - Q_ASSERT(type); - - kDebug() << type->toString(); - - // create a variable definition - IdentifierParameterPartAst* identifierNode = dynamic_cast(node->name); - Declaration* dec = openDeclaration( identifierNode->name, node); - { - DUChainWriteLocker lock(DUChain::lock()); - dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); - type->addArgument(dec->abstractType()); - } - closeDeclaration(); - - } else if( node->name->astType == Ast::ListParameterPartAst ) - { - //complex case, a sublist, what to do?? - } - } + AstDefaultVisitor::visitArguments(node); +// ContextBuilder::visitDefaultParameter( node ); +// // AbstractFunctionDeclaration* function = currentDeclaration(); +// AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); +// +// if( function ) +// { +// if( node->value ) +// { +// //Not sure what to do here, C++ simply adds the source code as default parameter, but that doesn't sound sane... +// } +// //simple case, we have an identifier parameter +// if( node->name->astType == Ast::IdentifierParameterPartAst ) +// { +// function->addDefaultParameter(IndexedString("foo")); +// kDebug() << function->defaultParametersSize(); +// +// Q_ASSERT(hasCurrentType()); +// FunctionType::Ptr type = currentType(); +// Q_ASSERT(type); +// +// kDebug() << type->toString(); +// +// // create a variable definition +// IdentifierParameterPartAst* identifierNode = dynamic_cast(node->name); +// Declaration* dec = openDeclaration( identifierNode->name, node); +// { +// DUChainWriteLocker lock(DUChain::lock()); +// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); +// type->addArgument(dec->abstractType()); +// } +// closeDeclaration(); +// +// } else if( node->name->astType == Ast::ListParameterPartAst ) +// { +// //complex case, a sublist, what to do?? +// } +// } } } diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 093b5ba..240c493 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -33,7 +33,7 @@ namespace Python { -typedef KDevelop::AbstractDeclarationBuilder DeclarationBuilderBase; +typedef KDevelop::AbstractDeclarationBuilder DeclarationBuilderBase; class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase { @@ -47,10 +47,10 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitClassDefinition( ClassDefinitionAst* node ); virtual void visitFunctionDefinition( FunctionDefinitionAst* node ); - virtual void visitDefaultParameter( DefaultParameterAst* node ); + virtual void visitArguments( ArgumentsAst* node ); virtual void visitLambda( LambdaAst* node ); - virtual void visitIdentifierTarget( IdentifierTargetAst * node ); +// virtual void visitIdentifierTarget( IdentifierTargetAst * node ); private: /* diff --git a/duchain/typebuilder.h b/duchain/typebuilder.h index d9efd85..4f2e00e 100644 --- a/duchain/typebuilder.h +++ b/duchain/typebuilder.h @@ -30,7 +30,7 @@ namespace Python { -typedef KDevelop::AbstractTypeBuilder TypeBuilderBase; +typedef KDevelop::AbstractTypeBuilder TypeBuilderBase; class KDEVPYTHONDUCHAIN_EXPORT TypeBuilder: public TypeBuilderBase { diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 3d07a99..d7da97e 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -51,7 +51,7 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) // // top->setHasUses(true); // } -void UseBuilder::visitIdentifier(IdentifierAst* node) +void UseBuilder::visitIdentifier(Identifier* node) { DUChainWriteLocker lock( DUChain::lock() ); QualifiedIdentifier id = identifierForNode(node); @@ -59,35 +59,35 @@ void UseBuilder::visitIdentifier(IdentifierAst* node) CursorInRevision until = range.start; QList allDeclarations = currentContext()->findDeclarations(id, until); - kDebug() << " >> scanning " << node->identifier; + kDebug() << " >> scanning " << node->value; kDebug() << " > searching for declaration until" << until.line << ":" << until.column << "; " << allDeclarations.length() << "Declarations found"; Declaration *globalDeclaration = 0; foreach ( Declaration* dec, allDeclarations ) { if ( dec->context() == dec->topContext() ) { - kDebug() << "There's already a global declaration for" << node->identifier; + kDebug() << "There's already a global declaration for" << node->value; globalDeclaration = dec; } } // if there's a local declaration, use the last one of those if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { - kDebug() << " ++ Created a use of local declaration for node" << node->identifier; + kDebug() << " ++ Created a use of local declaration for node" << node->value; UseBuilderBase::newUse(node, allDeclarations.last()); } // otherwise, use the global one. // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 else if ( globalDeclaration ) { - kDebug() << " ++ Created a use of global declaration for node" << node->identifier; + kDebug() << " ++ Created a use of global declaration for node" << node->value; UseBuilderBase::newUse(node, globalDeclaration); } } -void UseBuilder::visitIdentifierTarget(IdentifierTargetAst* node) -{ - kDebug() << "Target variable identifier: " << node->identifier->identifier.toAscii(); - UseBuilderBase::visitIdentifierTarget(node); -} +// void UseBuilder::visitIdentifierTarget(IdentifierTargetAst* node) +// { +// kDebug() << "Target variable identifier: " << node->identifier->identifier.toAscii(); +// UseBuilderBase::visitIdentifierTarget(node); +// } void UseBuilder::openContext(DUContext * newContext) diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 5e6605a..0e38dc0 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -34,7 +34,7 @@ namespace Python { class ParseSession; -typedef KDevelop::AbstractUseBuilder UseBuilderBase; +typedef KDevelop::AbstractUseBuilder UseBuilderBase; class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase { @@ -47,8 +47,7 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase virtual void openContext(KDevelop::DUContext* newContext); virtual void closeContext(); - virtual void visitIdentifier(IdentifierAst* node); - virtual void visitIdentifierTarget(IdentifierTargetAst* node); + virtual void visitIdentifier(Identifier* node); private: ParseSession* m_session; // void newUse(std::size_t name, Ast *rangenode); diff --git a/parser/ast.h b/parser/ast.h index c0acf23..9654975 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -61,12 +61,7 @@ namespace Python { namespace Python { - -class KDEVPYTHONPARSER_EXPORT Identifier { -public: - Identifier(QString value); - QString value; -}; + // Base class for all other Abstract Syntax Tree classes class KDEVPYTHONPARSER_EXPORT Ast @@ -191,6 +186,12 @@ class KDEVPYTHONPARSER_EXPORT Ast KDevelop::DUContext* context; }; +class KDEVPYTHONPARSER_EXPORT Identifier : public Ast { +public: + Identifier(QString value); + QString value; +}; + // this replaces ModuleAst class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast { public: @@ -209,6 +210,8 @@ class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { FunctionDefinitionAst(Ast* parent); Identifier* name; ArgumentsAst* arguments; + QList decorators; + QList body; }; class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { @@ -252,7 +255,7 @@ class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { ForAst(Ast* parent); ExpressionAst* target; ExpressionAst* iterator; - QList body; + QList body; QList orelse; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 547a530..4a6d13f 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -47,8 +47,9 @@ QString AstBuilder::getXmlForFile(KUrl filename) parser->start("/home/sven/projects/kde4/python/pythonpythonparser.py", QStringList(filename.path())); // TODO fix this parser->waitForFinished(); - if ( parser->error() ) { - kError() << parser->errorString(); + // TODO this is not clean + if ( parser->exitStatus() != QProcess::NormalExit ) { + kError() << "Error parsing file: " << parser->errorString(); return ""; } @@ -67,10 +68,14 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) parseXmlAstNode(xmlast, QXmlStreamReader::Invalid); + populateAst(); + Q_ASSERT(false); } void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) { + bool nodeAdded = false; + while ( ! xmlast->atEnd() && ! xmlast->hasError() ) { // Advance to the next (first) token QXmlStreamReader::TokenType token = xmlast->readNext(); @@ -87,13 +92,21 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok // We recursively continue parsing if we find another element else if ( token == QXmlStreamReader::StartElement ) { // Here we can now assemble an actual node with the attributes extracted above + + // Skip the document root element + if ( currentElementName == "pythonast" ) { + parseXmlAstNode(xmlast, token); + continue; + } + kDebug() << "Token: " << token << "; " << "Name: " << currentElementName << "; Text: " << currentElementText; for ( int i=0; i& attributes) +bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes) { Ast* ast; QMap attributeDict; for ( int i=0; i T* AstBuilder::resolveNode(const QString& identifier) +{ + return dynamic_cast(m_nodeMap[identifier.toInt()]); +} + +template QList AstBuilder::resolveNodeList(const QString& commaSeperatedIdentifiers) +{ + QList items; + QStringList identifiers = commaSeperatedIdentifiers.split(","); + for ( int i=0; i(identifiers.at(i)); + } + return items; +} + +FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes) +{ + FunctionDefinitionAst* currentNode = dynamic_cast(ast); + currentNode->arguments = resolveNode(currentAttributes.value("NR_args")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); + currentNode->name = new Identifier(currentAttributes.value("name")); + kDebug() << "Found function definition, name: " << currentAttributes.value("name"); + return currentNode; } void AstBuilder::populateAst() { + Ast* currentAbstractNode; + Ast* currentNode; + stringDictionary currentAttributes; + QMapIterator i(m_nodeMap); + while ( i.hasNext() ) { + i.next(); + currentAbstractNode = i.value(); + currentAttributes = m_attributeStore.value(i.key()); + + kDebug() << "Processing AST node ID " << i.key(); + kDebug() << "Amount of attributes: " << currentAttributes.size(); + + stringDictionary::const_iterator i = currentAttributes.begin(); + while ( i != currentAttributes.end() ) { + kDebug() << i.key() << i.value(); + ++i; + } + + switch ( currentAbstractNode->astType ) { + case Ast::CodeAstType: break; + case Ast::FunctionDefinitionAstType: populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; + case Ast::ClassDefinitionAstType: break; + case Ast::ReturnAstType: break; + case Ast::DeleteAstType: break; + case Ast::AssignmentAstType: break; + case Ast::AugmentedAssignmentAstType: break; + case Ast::ForAstType: break; + case Ast::WhileAstType: break; + case Ast::IfAstType: break; + case Ast::WithAstType: break; + case Ast::RaiseAstType: break; + case Ast::TryExceptAstType: break; + case Ast::TryFinallyAstType: break; + case Ast::AssertionAstType: break; + case Ast::ImportAstType: break; + case Ast::ImportFromAstType: break; + case Ast::ExecAstType: break; + case Ast::GlobalAstType: break; + case Ast::BreakAstType: break; + case Ast::ContinueAstType: break; + case Ast::PrintAstType: break; + case Ast::PassAstType: break; + case Ast::BooleanOperationAstType: break; + case Ast::BinaryOperationAstType: break; + case Ast::UnaryOperationAstType: break; + case Ast::LambdaAstType: break; + case Ast::IfExpressionAstType: break; + case Ast::DictAstType: break; + case Ast::SetAstType: break; + case Ast::ListComprehensionAstType: break; + case Ast::SetComprehensionAstType: break; + case Ast::DictionaryComprehensionAstType: break; + case Ast::GeneratorExpressionAstType: break; + case Ast::CompareAstType: break; + case Ast::ReprAstType: break; + case Ast::NumberAstType: break; + case Ast::StringAstType: break; + case Ast::YieldAstType: break; + case Ast::NameAstType: break; + case Ast::CallAstType: break; + case Ast::AttributeAstType: break; + case Ast::SubscriptAstType: break; + case Ast::ListAstType: break; + case Ast::TupleAstType: break; + case Ast::EllipsisAstType: break; + case Ast::SliceAstType: break; + case Ast::ExtendedSliceAstType: break; + case Ast::IndexAstType: break; + case Ast::ArgumentsAstType: break; + case Ast::KeywordAstType: break; + case Ast::ComprehensionAstType: break; + case Ast::ExceptionHandlerAstType: break; + case Ast::AliasAstType: break; + case Ast::ExpressionAstType: break; + case Ast::StatementAstType: break; + } + } } } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index d013543..bc8f2a5 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -40,6 +40,7 @@ namespace Python class Ast; class CodeAst; +typedef QMap stringDictionary; class AstBuilder { @@ -50,21 +51,20 @@ class AstBuilder CodeAst* parseXmlAst(QString xml); QString getXmlForFile(KUrl filename); void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); - void parseAstNode(QString name, QString text, const QList& attributes); + bool parseAstNode(QString name, QString text, const QList& attributes); QList m_nodeStack; - template ASTType* createAst(QDomElement* startEnd = 0) { - ASTType* ast = new ASTType(); - if ( startEnd ) { - kDebug() << "would set start end now"; - } - } - QMap m_nodeMap; QStack m_astStack; + QMap m_attributeStore; void populateAst(); + + template QList resolveNodeList(const QString& commaSeperatedIdentifiers); + template T* resolveNode(const QString& identifier); + + FunctionDefinitionAst* populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes); }; } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index b97c6aa..688ab04 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -77,8 +77,8 @@ void AstDefaultVisitor::visitFor(ForAst* node) { visitNode(node->target); visitNode(node->iterator); - foreach (ExpressionAst* expression, node->body) { - visitNode(expression); + foreach (StatementAst* statement, node->body) { + visitNode(statement); } foreach (StatementAst* statement, node->orelse) { visitNode(statement); diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 03b67c9..be7317d 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -47,7 +47,7 @@ // #include "contextbuilder.h" #include "declarationbuilder.h" #include "usebuilder.h" -#include "astprinter.h" +// #include "astprinter.h" // #include "usebuilder.h" using namespace KDevelop; diff --git a/utilities/classes b/utilities/classes index 2786192..5df6415 100644 --- a/utilities/classes +++ b/utilities/classes @@ -248,7 +248,7 @@ public: class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { public: ForAst(Ast* parent, AstType type); - ExpressionAst* target; + ExpressionAst* target; // may be a tupleAst for something like for a, b in j ExpressionAst* iterator; QList body; QList orelse; From a976f57365c28c1fea1aba70dfe7d463d3fcd2c4 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 18 Oct 2010 00:37:02 +0200 Subject: [PATCH 030/118] Added all AST primitivies, fixed bugs. --- parser/ast.cpp | 2 +- parser/astbuilder.cpp | 54 ++++++++++++++++++++++++++++++++++++++--- parser/astbuilder.h | 8 ++++++ parser/parsesession.cpp | 3 ++- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 2ed31f6..929e3e9 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -83,7 +83,7 @@ ClassDefinitionAst::ClassDefinitionAst(Ast* parent): StatementAst(parent, Ast::C CodeAst::CodeAst() { - + astType = Ast::CodeAstType; } CompareAst::CompareAst(Ast* parent): ExpressionAst(parent, Ast::CompareAstType) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 4a6d13f..f6e5865 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -70,7 +70,10 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) populateAst(); - Q_ASSERT(false); + CodeAst* codeAst = dynamic_cast(m_currentNode); + if ( ! codeAst ) + Q_ASSERT(codeAst); + return codeAst; } void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) { @@ -111,6 +114,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok parseXmlAstNode(xmlast, token); // now we pop this parent off + m_currentNode = m_nodeStack.last(); m_nodeStack.removeLast(); } // Everything else (stuff between tags, comments...) is ignored @@ -129,6 +133,8 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea attributeDict.insert(attributes.at(i).name().toString(), attributes.at(i).value().toString()); } + int node_id = attributeDict["nodecnt"].toInt(); + // TODO think about a less explicit way to do this // things in the comments are definitely found like this in the XML file name = name.toLower(); @@ -188,12 +194,52 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea else if ( name == "withast" ) ast = new WithAst(m_nodeStack.last()); // withAst else if ( name == "yieldast" ) ast = new YieldAst(m_nodeStack.last()); // yieldAst else { - kWarning() << "Unknown AST type" << name; + // assemble AST primitives + // TODO revert the order, better performance + if ( name == "loadast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Load); + else if ( name == "storeast") m_contextNodeMap.insert(node_id, ExpressionAst::Store); + else if ( name == "deleteast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Delete); + else if ( name == "augassignast" ) m_contextNodeMap.insert(node_id, ExpressionAst::AugStore); + + else if ( name == "addast" ) m_opNodeMap.insert(node_id, Ast::OperatorAdd); + else if ( name == "subast" ) m_opNodeMap.insert(node_id, Ast::OperatorSub); + else if ( name == "multast" ) m_opNodeMap.insert(node_id, Ast::OperatorMult); + else if ( name == "divast" ) m_opNodeMap.insert(node_id, Ast::OperatorDiv); + else if ( name == "modast" ) m_opNodeMap.insert(node_id, Ast::OperatorMod); + else if ( name == "bitxorast" ) m_opNodeMap.insert(node_id, Ast::OperatorBitwiseXor); + else if ( name == "bitandast" ) m_opNodeMap.insert(node_id, Ast::OperatorBitwiseAnd); + else if ( name == "bitorast" ) m_opNodeMap.insert(node_id, Ast::OperatorBitwiseOr); + else if ( name == "powast" ) m_opNodeMap.insert(node_id, Ast::OperatorPow); + else if ( name == "rshiftast" ) m_opNodeMap.insert(node_id, Ast::OperatorRightShift); + else if ( name == "lshiftast" ) m_opNodeMap.insert(node_id, Ast::OperatorLeftShift); + + else if ( name == "notast" ) m_unaryOpNodeMap.insert(node_id, Ast::UnaryOperatorNot); + else if ( name == "uaddast" ) m_unaryOpNodeMap.insert(node_id, Ast::UnaryOperatorAdd); + else if ( name == "usubast" ) m_unaryOpNodeMap.insert(node_id, Ast::UnaryOperatorSub); + else if ( name == "invertast" ) m_unaryOpNodeMap.insert(node_id, Ast::UnaryOperatorInvert); + + else if ( name == "eqast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorEquals); + else if ( name == "noteqast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorNotEquals); + else if ( name == "ltast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorLessThan); + else if ( name == "lteast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorLessThanEqual); + else if ( name == "gtast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorGreaterThan); + else if ( name == "gteast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorGreaterThanEqual); + else if ( name == "isast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorIs); + else if ( name == "isnotast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorIsNot); + else if ( name == "inast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorIn); + else if ( name == "notinast" ) m_compOpNodeMap.insert(node_id, Ast::ComparisonOperatorNotIn); + + else if ( name == "andast" ) m_boolOpNodeMap.insert(node_id, Ast::BooleanAnd); + else if ( name == "orast" ) m_boolOpNodeMap.insert(node_id, Ast::BooleanOr); + else { + kWarning() << "Unknown AST type" << name; + } + // we did not push a node onto the stack, so we return false return false; } - m_nodeMap.insert(attributeDict["nodecnt"].toInt(), ast); - m_attributeStore.insert(attributeDict["nodecnt"].toInt(), attributeDict); + m_nodeMap.insert(node_id, ast); + m_attributeStore.insert(node_id, attributeDict); m_nodeStack.append(ast); return true; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index bc8f2a5..22800fb 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -55,9 +55,17 @@ class AstBuilder QList m_nodeStack; + // one map for regular ast nodes, and the others for primitive nodes of different types QMap m_nodeMap; + QMap m_contextNodeMap; + QMap m_boolOpNodeMap; + QMap m_compOpNodeMap; + QMap m_opNodeMap; + QMap m_unaryOpNodeMap; + QStack m_astStack; QMap m_attributeStore; + Ast* m_currentNode; void populateAst(); diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index 6419f8c..d11c0a0 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -65,7 +65,8 @@ bool ParseSession::parse( Python::CodeAst* ast ) { AstBuilder parser; ast = parser.parse(m_currentDocument); - Q_ASSERT(false); + if ( ! ast ) + Q_ASSERT(false); } } From f7c393d5206b1791f786d0a489b677fa56e206bf Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 18 Oct 2010 10:57:21 +0200 Subject: [PATCH 031/118] More populator functions --- parser/ast.h | 3 ++- parser/astbuilder.cpp | 59 ++++++++++++++++++++++++++++++++++++------- parser/astbuilder.h | 16 ++++++++++++ 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index 9654975..d179922 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -375,7 +375,8 @@ class KDEVPYTHONPARSER_EXPORT ExpressionAst : public Ast { Store, // the object is written Delete, // the object is deleted Parameter, // the object is passed as a parameter - AugLoad, AugStore // Augmented assignments, like a += 1 + AugLoad, AugStore, // Augmented assignments, like a += 1 + Invalid }; ExpressionAst* value; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index f6e5865..8a1e4a4 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -135,7 +135,7 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea int node_id = attributeDict["nodecnt"].toInt(); - // TODO think about a less explicit way to do this + // TODO implent this using QMap/QBinaryFind/enum/parser table // things in the comments are definitely found like this in the XML file name = name.toLower(); if ( name == "aliasast" ) ast = new AliasAst(m_nodeStack.last()); // aliasAst @@ -195,7 +195,6 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea else if ( name == "yieldast" ) ast = new YieldAst(m_nodeStack.last()); // yieldAst else { // assemble AST primitives - // TODO revert the order, better performance if ( name == "loadast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Load); else if ( name == "storeast") m_contextNodeMap.insert(node_id, ExpressionAst::Store); else if ( name == "deleteast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Delete); @@ -247,7 +246,9 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea template T* AstBuilder::resolveNode(const QString& identifier) { - return dynamic_cast(m_nodeMap[identifier.toInt()]); + int id = identifier.toInt(); + if ( ! id ) return 0; + return dynamic_cast(m_nodeMap.value(id)); } template QList AstBuilder::resolveNodeList(const QString& commaSeperatedIdentifiers) @@ -260,6 +261,32 @@ template QList AstBuilder::resolveNodeList(const QString& comma return items; } +ExpressionAst::Context AstBuilder::resolveContext(const QString& identifier) +{ + int id = identifier.toInt(); + if ( ! id ) return ExpressionAst::Invalid; + return m_contextNodeMap.value(id); +} + +NameAst* AstBuilder::populateNameAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + NameAst* currentNode = dynamic_cast(ast); + currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); + currentNode->identifier = new Identifier(currentAttributes.value("id")); + kDebug() << "Processing NameAst" << currentNode->identifier->value; + return currentNode; +} + +ClassDefinitionAst* AstBuilder::populateClassDefinitonAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ClassDefinitionAst* currentNode = dynamic_cast(ast); + currentNode->baseClasses = resolveNodeList(currentAttributes.value("NRLST_bases")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); + currentNode->name = new Identifier(currentAttributes.value("name")); + return currentNode; +} + FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes) { FunctionDefinitionAst* currentNode = dynamic_cast(ast); @@ -267,7 +294,21 @@ FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); currentNode->name = new Identifier(currentAttributes.value("name")); - kDebug() << "Found function definition, name: " << currentAttributes.value("name"); + return currentNode; +} + +AssignmentAst* AstBuilder::populateAssignmentAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + AssignmentAst* currentNode = dynamic_cast(ast); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + currentNode->targets = resolveNodeList(currentAttributes.value("NRLST_targets")); + return currentNode; +} + +CodeAst* AstBuilder::populateCodeAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + CodeAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); return currentNode; } @@ -292,12 +333,12 @@ void AstBuilder::populateAst() } switch ( currentAbstractNode->astType ) { - case Ast::CodeAstType: break; - case Ast::FunctionDefinitionAstType: populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; - case Ast::ClassDefinitionAstType: break; + case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; + case Ast::FunctionDefinitionAstType: currentAbstractNode = populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; + case Ast::ClassDefinitionAstType: currentAbstractNode = populateClassDefinitonAst(currentAbstractNode, currentAttributes); break; case Ast::ReturnAstType: break; case Ast::DeleteAstType: break; - case Ast::AssignmentAstType: break; + case Ast::AssignmentAstType: currentAbstractNode = populateAssignmentAst(currentAbstractNode, currentAttributes); break; case Ast::AugmentedAssignmentAstType: break; case Ast::ForAstType: break; case Ast::WhileAstType: break; @@ -331,7 +372,7 @@ void AstBuilder::populateAst() case Ast::NumberAstType: break; case Ast::StringAstType: break; case Ast::YieldAstType: break; - case Ast::NameAstType: break; + case Ast::NameAstType: currentAbstractNode = populateNameAst(currentAbstractNode, currentAttributes); break; case Ast::CallAstType: break; case Ast::AttributeAstType: break; case Ast::SubscriptAstType: break; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 22800fb..7425971 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -67,12 +67,28 @@ class AstBuilder QMap m_attributeStore; Ast* m_currentNode; + Ast::BooleanOperationTypes resolveBooleanOperator(const QString& identifier); + Ast::ComparisonOperatorTypes resolveComparisonOperator(const QString& identifier); + Ast::OperatorTypes resolveOperator(const QString& identifier); + Ast::UnaryOperatorTypes resolveUnaryOperator(const QString& identifier); + ExpressionAst::Context resolveContext(const QString& identifier); + + QList resolveBooleanOperatorList(const QString& identifiers); + QList resolveComparisonOperatorList(const QString& identifiers); + QList resolveOperatorList(const QString& identifiers); + QList resolveUnaryOperatorList(const QString& identifiers); + QList resolveContextList(const QString& identifiers); + void populateAst(); template QList resolveNodeList(const QString& commaSeperatedIdentifiers); template T* resolveNode(const QString& identifier); FunctionDefinitionAst* populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes); + AssignmentAst* populateAssignmentAst(Ast* ast, const stringDictionary& currentAttributes); + CodeAst* populateCodeAst(Ast* ast, const stringDictionary& currentAttributes); + ClassDefinitionAst* populateClassDefinitonAst(Ast* ast, const stringDictionary& currentAttributes); + NameAst* populateNameAst(Ast* ast, const stringDictionary& currentAttributes); }; } From 1b154bd131a7e6c54157f10ab99c879edf0bafbf Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 19 Oct 2010 00:08:19 +0200 Subject: [PATCH 032/118] Many small bugfixes and updates --- parser/ast.h | 2 -- parser/astbuilder.cpp | 9 +++++++-- parser/parsesession.cpp | 3 ++- parser/parsesession.h | 2 +- pythonlanguagesupport.cpp | 9 +++++++++ pythonlanguagesupport.h | 3 +++ pythonparsejob.cpp | 18 +++++++++++------- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/parser/ast.h b/parser/ast.h index d179922..9e1369b 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -176,8 +176,6 @@ class KDEVPYTHONPARSER_EXPORT Ast Ast* parent; AstType astType; - qint64 start; - qint64 end; qint64 startCol; qint64 startLine; qint64 endCol; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 8a1e4a4..efaff10 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -37,7 +37,8 @@ namespace Python CodeAst* AstBuilder::parse(KUrl filename) { - return parseXmlAst(getXmlForFile(filename)); + CodeAst* ast = parseXmlAst(getXmlForFile(filename)); + return ast; } QString AstBuilder::getXmlForFile(KUrl filename) @@ -315,7 +316,6 @@ CodeAst* AstBuilder::populateCodeAst(Ast* ast, const Python::stringDictionary& c void AstBuilder::populateAst() { Ast* currentAbstractNode; - Ast* currentNode; stringDictionary currentAttributes; QMapIterator i(m_nodeMap); while ( i.hasNext() ) { @@ -332,6 +332,11 @@ void AstBuilder::populateAst() ++i; } + int startLine = currentAttributes.value("lineno").toInt(); + if ( startLine ) currentAbstractNode->startLine = startLine; + int startCol = currentAttributes.value("col_offset").toInt(); + if ( startCol ) currentAbstractNode->startCol = startCol; + switch ( currentAbstractNode->astType ) { case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; case Ast::FunctionDefinitionAstType: currentAbstractNode = populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index d11c0a0..c852e18 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -61,12 +61,13 @@ void ParseSession::setContents( const QString& contents ) m_contents = contents; } -bool ParseSession::parse( Python::CodeAst* ast ) +QPair ParseSession::parse( Python::CodeAst* ast ) { AstBuilder parser; ast = parser.parse(m_currentDocument); if ( ! ast ) Q_ASSERT(false); + return QPair(ast, true); } } diff --git a/parser/parsesession.h b/parser/parsesession.h index 613bf54..87ae758 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -54,7 +54,7 @@ class KDEVPYTHONPARSER_EXPORT ParseSession void setCurrentDocument(KUrl& filename); IndexedString currentDocument(); - bool parse( Python::CodeAst* ); + QPair parse( Python::CodeAst* ast ); void mapAstUse(Ast* node, const SimpleUse& use) { diff --git a/pythonlanguagesupport.cpp b/pythonlanguagesupport.cpp index 51701f9..0b8353d 100644 --- a/pythonlanguagesupport.cpp +++ b/pythonlanguagesupport.cpp @@ -64,12 +64,16 @@ K_EXPORT_PLUGIN( KDevPythonSupportFactory( "kdevpythonsupport" ) ) namespace Python { + +LanguageSupport* LanguageSupport::m_self = 0; LanguageSupport::LanguageSupport( QObject* parent, const QVariantList& /*args*/ ) : KDevelop::IPlugin( KDevPythonSupportFactory::componentData(), parent ), KDevelop::ILanguageSupport() { KDEV_USE_EXTENSION_INTERFACE( KDevelop::ILanguageSupport ) + + m_self = this; m_highlighting = new Highlighting( this ); PythonCodeCompletionModel* codeCompletion = new PythonCodeCompletionModel(this); @@ -92,6 +96,11 @@ QString LanguageSupport::name() const return "Python"; } +LanguageSupport* LanguageSupport::self() +{ + return m_self; +} + KDevelop::ILanguage *LanguageSupport::language() { kDebug() << core()->languageController()->language( name() ); diff --git a/pythonlanguagesupport.h b/pythonlanguagesupport.h index 8434b21..54662c5 100644 --- a/pythonlanguagesupport.h +++ b/pythonlanguagesupport.h @@ -62,10 +62,13 @@ class LanguageSupport : public KDevelop::IPlugin, public KDevelop::ILanguageSupp /*the code highlighter*/ KDevelop::ICodeHighlighting* codeHighlighting() const; + static LanguageSupport* self(); + // virtual QWidget* specialLanguageObjectNavigationWidget(const KUrl& url, const KDevelop::SimpleCursor& position); private: Highlighting* m_highlighting; + static LanguageSupport* m_self; }; } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index be7317d..64161fd 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -74,8 +74,7 @@ ParseJob::~ParseJob() LanguageSupport *ParseJob::python() const { - kDebug() << "language requested"; - return qobject_cast( const_cast( parent() ) ); + return LanguageSupport::self(); } @@ -94,10 +93,14 @@ void ParseJob::run() { kDebug(); - if ( abortRequested() ) + if (abortRequested() || !python() || !python()->language()) { + kWarning() << "Language support is NULL"; return abortJob(); - -// QReadLocker lock(python()->language()->parseLock()); + } + + LanguageSupport* lang = python(); + ILanguage* ilang = lang->language(); + QReadLocker lock(ilang->parseLock()); UrlParseLock urlLock(document()); readContents(); @@ -108,9 +111,10 @@ void ParseJob::run() return abortJob(); // 2) parse - bool matched = m_session->parse( m_ast ); + QPair parserResults = m_session->parse(m_ast); + m_ast = parserResults.first; - if ( matched ) + if ( parserResults.second ) { kDebug() << m_url; // AstPrinter printer; From 06108e3a3808caf961fb6b0d0773f7bfa4a4e017 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 19 Oct 2010 18:12:31 +0200 Subject: [PATCH 033/118] Bugfixes, nullpointer initializations --- parser/ast.cpp | 78 ++++++++++++------------- parser/astbuilder.cpp | 45 +++++++++++++-- parser/astbuilder.h | 5 ++ parser/astdefaultvisitor.cpp | 2 + parser/astvisitor.cpp | 108 +++++++++++++++++------------------ pythonpythonparser.py | 6 +- 6 files changed, 142 insertions(+), 102 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 929e3e9..c802f35 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -28,7 +28,7 @@ namespace Python // there's nothing happening here, don't bother reading the code Ast::Ast( Ast* parent, Ast::AstType type ) : parent(parent), astType( type ) { } -Ast::Ast() { } +Ast::Ast() : parent(0), startCol(0), startLine(0), endCol(0), endLine(0), context(0) { } Ast::~Ast() { } ArgumentsAst::ArgumentsAst(Ast* parent): Ast(parent, Ast::ArgumentsAstType) @@ -36,27 +36,27 @@ ArgumentsAst::ArgumentsAst(Ast* parent): Ast(parent, Ast::ArgumentsAstType) } -AssertionAst::AssertionAst(Ast* parent): StatementAst(parent, Ast::AssertionAstType) +AssertionAst::AssertionAst(Ast* parent): StatementAst(parent, Ast::AssertionAstType) { } -AssignmentAst::AssignmentAst(Ast* parent): StatementAst(parent, Ast::AssignmentAstType) +AssignmentAst::AssignmentAst(Ast* parent): StatementAst(parent, Ast::AssignmentAstType), value(0) { } -AttributeAst::AttributeAst(Ast* parent): ExpressionAst(parent, Ast::AttributeAstType) +AttributeAst::AttributeAst(Ast* parent): ExpressionAst(parent, Ast::AttributeAstType), value(0) { } -AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent): StatementAst(parent, Ast::AugmentedAssignmentAstType) +AugmentedAssignmentAst::AugmentedAssignmentAst(Ast* parent): StatementAst(parent, Ast::AugmentedAssignmentAstType), value(0) { } -BinaryOperationAst::BinaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::BinaryOperationAstType) +BinaryOperationAst::BinaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::BinaryOperationAstType), lhs(0), rhs(0) { } @@ -71,12 +71,12 @@ BreakAst::BreakAst(Ast* parent): StatementAst(parent, Ast::BreakAstType) } -CallAst::CallAst(Ast* parent): ExpressionAst(parent, Ast::CallAstType) +CallAst::CallAst(Ast* parent): ExpressionAst(parent, Ast::CallAstType), function(0), keywordArguments(0) { } -ClassDefinitionAst::ClassDefinitionAst(Ast* parent): StatementAst(parent, Ast::ClassDefinitionAstType) +ClassDefinitionAst::ClassDefinitionAst(Ast* parent): StatementAst(parent, Ast::ClassDefinitionAstType), name(0) { } @@ -86,12 +86,12 @@ CodeAst::CodeAst() astType = Ast::CodeAstType; } -CompareAst::CompareAst(Ast* parent): ExpressionAst(parent, Ast::CompareAstType) +CompareAst::CompareAst(Ast* parent): ExpressionAst(parent, Ast::CompareAstType), leftmostElement(0) { } -ComprehensionAst::ComprehensionAst(Ast* parent): Ast(parent, Ast::ComprehensionAstType) +ComprehensionAst::ComprehensionAst(Ast* parent): Ast(parent, Ast::ComprehensionAstType), target(0), iterator(0) { } @@ -111,17 +111,17 @@ DictAst::DictAst(Ast* parent): ExpressionAst(parent, Ast::DictAstType) } -IndexAst::IndexAst(Ast* parent): SliceAstBase(parent, Ast::IndexAstType) +IndexAst::IndexAst(Ast* parent): SliceAstBase(parent, Ast::IndexAstType), value(0) { } -SliceAst::SliceAst(Ast* parent): SliceAstBase(parent, Ast::SliceAstType) +SliceAst::SliceAst(Ast* parent): SliceAstBase(parent, Ast::SliceAstType), lower(0), upper(0), step(0) { } -DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::DictionaryComprehensionAstType) +DictionaryComprehensionAst::DictionaryComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::DictionaryComprehensionAstType), key(0), value(0) { } @@ -131,22 +131,22 @@ EllipsisAst::EllipsisAst(Ast* parent): SliceAstBase(parent, Ast::EllipsisAstType } -ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::ExceptionHandlerAstType) +ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::ExceptionHandlerAstType), type(0), name(0) { } -ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType) +ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0) { } -ListComprehensionAst::ListComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::ListComprehensionAstType) +ListComprehensionAst::ListComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::ListComprehensionAstType), element(0) { } -ExpressionAst::ExpressionAst(Ast* parent, AstType type): Ast(parent, type) +ExpressionAst::ExpressionAst(Ast* parent, AstType type): Ast(parent, type), value(0) { } @@ -156,17 +156,17 @@ ExtendedSliceAst::ExtendedSliceAst(Ast* parent): SliceAstBase(parent, Ast::Exten } -ForAst::ForAst(Ast* parent): StatementAst(parent, Ast::ForAstType) +ForAst::ForAst(Ast* parent): StatementAst(parent, Ast::ForAstType), target(0), iterator(0) { } -FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent): StatementAst(parent, Ast::FunctionDefinitionAstType) +FunctionDefinitionAst::FunctionDefinitionAst(Ast* parent): StatementAst(parent, Ast::FunctionDefinitionAstType), name(0), arguments(0) { } -GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent): ExpressionAst(parent, Ast::GeneratorExpressionAstType) +GeneratorExpressionAst::GeneratorExpressionAst(Ast* parent): ExpressionAst(parent, Ast::GeneratorExpressionAstType), element(0) { } @@ -181,12 +181,12 @@ Identifier::Identifier(QString value) : value(value) } -IfAst::IfAst(Ast* parent): StatementAst(parent, Ast::IfAstType) +IfAst::IfAst(Ast* parent): StatementAst(parent, Ast::IfAstType), condition(0) { } -IfExpressionAst::IfExpressionAst(Ast* parent): ExpressionAst(parent, Ast::IfExpressionAstType) +IfExpressionAst::IfExpressionAst(Ast* parent): ExpressionAst(parent, Ast::IfExpressionAstType), condition(0) { } @@ -196,17 +196,17 @@ ImportAst::ImportAst(Ast* parent): StatementAst(parent, Ast::ImportAstType) } -ImportFromAst::ImportFromAst(Ast* parent): StatementAst(parent, Ast::ImportFromAstType) +ImportFromAst::ImportFromAst(Ast* parent): StatementAst(parent, Ast::ImportFromAstType), module(0), level(0) { } -KeywordAst::KeywordAst(Ast* parent): Ast(parent, Ast::KeywordAstType) +KeywordAst::KeywordAst(Ast* parent): Ast(parent, Ast::KeywordAstType), argumentName(0), value(0) { } -LambdaAst::LambdaAst(Ast* parent): ExpressionAst(parent, Ast::LambdaAstType) +LambdaAst::LambdaAst(Ast* parent): ExpressionAst(parent, Ast::LambdaAstType), arguments(0) { } @@ -216,12 +216,12 @@ ListAst::ListAst(Ast* parent): ExpressionAst(parent, Ast::ListAstType) } -NameAst::NameAst(Ast* parent): ExpressionAst(parent, Ast::NameAstType) +NameAst::NameAst(Ast* parent): ExpressionAst(parent, Ast::NameAstType), identifier(0) { } -NumberAst::NumberAst(Ast* parent): ExpressionAst(parent, Ast::NumberAstType) +NumberAst::NumberAst(Ast* parent): ExpressionAst(parent, Ast::NumberAstType), value(0) { } @@ -231,22 +231,22 @@ PassAst::PassAst(Ast* parent): StatementAst(parent, Ast::PassAstType) } -PrintAst::PrintAst(Ast* parent): StatementAst(parent, Ast::PrintAstType) +PrintAst::PrintAst(Ast* parent): StatementAst(parent, Ast::PrintAstType), destination(0), newline(0) { } -RaiseAst::RaiseAst(Ast* parent): StatementAst(parent, Ast::RaiseAstType) +RaiseAst::RaiseAst(Ast* parent): StatementAst(parent, Ast::RaiseAstType), type(0) { } -ReprAst::ReprAst(Ast* parent): ExpressionAst(parent, Ast::ReprAstType) +ReprAst::ReprAst(Ast* parent): ExpressionAst(parent, Ast::ReprAstType), value(0) { } -ReturnAst::ReturnAst(Ast* parent): StatementAst(parent, Ast::ReturnAstType) +ReturnAst::ReturnAst(Ast* parent): StatementAst(parent, Ast::ReturnAstType), value(0) { } @@ -256,7 +256,7 @@ SetAst::SetAst(Ast* parent): ExpressionAst(parent, Ast::SetAstType) } -SetComprehensionAst::SetComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::SetComprehensionAstType) +SetComprehensionAst::SetComprehensionAst(Ast* parent): ExpressionAst(parent, Ast::SetComprehensionAstType), element(0) { } @@ -271,12 +271,12 @@ StatementAst::StatementAst(Ast* parent, AstType type): Ast(parent, type) } -StringAst::StringAst(Ast* parent): ExpressionAst(parent, Ast::StringAstType) +StringAst::StringAst(Ast* parent): ExpressionAst(parent, Ast::StringAstType), value(0) { } -SubscriptAst::SubscriptAst(Ast* parent): ExpressionAst(parent, Ast::SubscriptAstType) +SubscriptAst::SubscriptAst(Ast* parent): ExpressionAst(parent, Ast::SubscriptAstType), value(0), slice(0) { } @@ -296,27 +296,27 @@ TupleAst::TupleAst(Ast* parent): ExpressionAst(parent, Ast::TupleAstType) } -UnaryOperationAst::UnaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::UnaryOperationAstType) +UnaryOperationAst::UnaryOperationAst(Ast* parent): ExpressionAst(parent, Ast::UnaryOperationAstType), operand(0) { } -WhileAst::WhileAst(Ast* parent): StatementAst(parent, Ast::WhileAstType) +WhileAst::WhileAst(Ast* parent): StatementAst(parent, Ast::WhileAstType), condition(0) { } -WithAst::WithAst(Ast* parent): StatementAst(parent, Ast::WithAstType) +WithAst::WithAst(Ast* parent): StatementAst(parent, Ast::WithAstType), contextExpression(0) { } -YieldAst::YieldAst(Ast* parent): ExpressionAst(parent, Ast::YieldAstType) +YieldAst::YieldAst(Ast* parent): ExpressionAst(parent, Ast::YieldAstType), value(0) { } -AliasAst::AliasAst(Ast* parent): Ast(parent, Ast::AliasAstType) +AliasAst::AliasAst(Ast* parent): Ast(parent, Ast::AliasAstType), name(0), asName(0) { } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index efaff10..8cf4e2f 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -313,6 +313,39 @@ CodeAst* AstBuilder::populateCodeAst(Ast* ast, const Python::stringDictionary& c return currentNode; } +DeleteAst* AstBuilder::populateDeleteAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + DeleteAst* currentNode = dynamic_cast(ast); + currentNode->targets = resolveNodeList(currentAttributes.value("NRLST_targets")); + return currentNode; +} + +ForAst* AstBuilder::populateForAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ForAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->iterator = resolveNode(currentAttributes.value("NR_iter")); + currentNode->target = resolveNode(currentAttributes.value("NR_target")); + return currentNode; +} + +PrintAst* AstBuilder::populatePrintAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + PrintAst* currentNode = dynamic_cast(ast); + currentNode->destination = resolveNode(currentAttributes.value("NR_dest")); + currentNode->newline = currentAttributes.value("nl") == "True" ? true : false; + currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values")); + return currentNode; +} + +ReturnAst* AstBuilder::populateReturnAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ReturnAst* currentNode = dynamic_cast(ast); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + void AstBuilder::populateAst() { Ast* currentAbstractNode; @@ -333,19 +366,19 @@ void AstBuilder::populateAst() } int startLine = currentAttributes.value("lineno").toInt(); - if ( startLine ) currentAbstractNode->startLine = startLine; + currentAbstractNode->startLine = startLine; int startCol = currentAttributes.value("col_offset").toInt(); - if ( startCol ) currentAbstractNode->startCol = startCol; + currentAbstractNode->startCol = startCol; switch ( currentAbstractNode->astType ) { case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; case Ast::FunctionDefinitionAstType: currentAbstractNode = populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; case Ast::ClassDefinitionAstType: currentAbstractNode = populateClassDefinitonAst(currentAbstractNode, currentAttributes); break; - case Ast::ReturnAstType: break; - case Ast::DeleteAstType: break; + case Ast::ReturnAstType: currentAbstractNode = populateReturnAst(currentAbstractNode, currentAttributes); break; + case Ast::DeleteAstType: currentAbstractNode = populateDeleteAst(currentAbstractNode, currentAttributes); break; case Ast::AssignmentAstType: currentAbstractNode = populateAssignmentAst(currentAbstractNode, currentAttributes); break; case Ast::AugmentedAssignmentAstType: break; - case Ast::ForAstType: break; + case Ast::ForAstType: currentAbstractNode = populateForAst(currentAbstractNode, currentAttributes); break; case Ast::WhileAstType: break; case Ast::IfAstType: break; case Ast::WithAstType: break; @@ -359,7 +392,7 @@ void AstBuilder::populateAst() case Ast::GlobalAstType: break; case Ast::BreakAstType: break; case Ast::ContinueAstType: break; - case Ast::PrintAstType: break; + case Ast::PrintAstType: currentAbstractNode = populatePrintAst(currentAbstractNode, currentAttributes); break; case Ast::PassAstType: break; case Ast::BooleanOperationAstType: break; case Ast::BinaryOperationAstType: break; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 7425971..caa4ab2 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -89,6 +89,11 @@ class AstBuilder CodeAst* populateCodeAst(Ast* ast, const stringDictionary& currentAttributes); ClassDefinitionAst* populateClassDefinitonAst(Ast* ast, const stringDictionary& currentAttributes); NameAst* populateNameAst(Ast* ast, const stringDictionary& currentAttributes); + ReturnAst* populateReturnAst(Ast* ast, const stringDictionary& currentAttributes); + DeleteAst* populateDeleteAst(Ast* ast, const stringDictionary& currentAttributes); + ForAst* populateForAst(Ast* ast, const stringDictionary& currentAttributes); + WhileAst* populateWhileAst(Ast* ast, const stringDictionary& currentAttributes); + PrintAst* populatePrintAst(Ast* ast, const stringDictionary& currentAttributes); }; } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 688ab04..ec28fc4 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -20,6 +20,7 @@ #include "astdefaultvisitor.h" #include "ast.h" +#include namespace Python { @@ -41,6 +42,7 @@ void AstDefaultVisitor::visitString(StringAst* node) { Q_UNUSED(node); } void AstDefaultVisitor::visitCode(CodeAst* node) { + kDebug() << "Visiting code"; foreach (StatementAst* statement, node->body) { visitNode(statement); } diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index e1776ba..6f0abee 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -36,60 +36,60 @@ void AstVisitor::visitNode(Ast* node) { if ( ! node ) return; switch ( node->astType ) { - case Ast::CodeAstType: AstVisitor::visitCode(dynamic_cast(node)); break; - case Ast::FunctionDefinitionAstType: AstVisitor::visitFunctionDefinition(dynamic_cast(node)); break; - case Ast::ClassDefinitionAstType: AstVisitor::visitClassDefinition(dynamic_cast(node)); break; - case Ast::ReturnAstType: AstVisitor::visitReturn(dynamic_cast(node)); break; - case Ast::DeleteAstType: AstVisitor::visitDelete(dynamic_cast(node)); break; - case Ast::AssignmentAstType: AstVisitor::visitAssignment(dynamic_cast(node)); break; - case Ast::AugmentedAssignmentAstType: AstVisitor::visitAugmentedAssignment(dynamic_cast(node)); break; - case Ast::ForAstType: AstVisitor::visitFor(dynamic_cast(node)); break; - case Ast::WhileAstType: AstVisitor::visitWhile(dynamic_cast(node)); break; - case Ast::IfAstType: AstVisitor::visitIf(dynamic_cast(node)); break; - case Ast::WithAstType: AstVisitor::visitWith(dynamic_cast(node)); break; - case Ast::RaiseAstType: AstVisitor::visitRaise(dynamic_cast(node)); break; - case Ast::TryExceptAstType: AstVisitor::visitTryExcept(dynamic_cast(node)); break; - case Ast::TryFinallyAstType: AstVisitor::visitTryFinally(dynamic_cast(node)); break; - case Ast::AssertionAstType: AstVisitor::visitAssertion(dynamic_cast(node)); break; - case Ast::ImportAstType: AstVisitor::visitImport(dynamic_cast(node)); break; - case Ast::ImportFromAstType: AstVisitor::visitImportFrom(dynamic_cast(node)); break; - case Ast::ExecAstType: AstVisitor::visitExec(dynamic_cast(node)); break; - case Ast::GlobalAstType: AstVisitor::visitGlobal(dynamic_cast(node)); break; - case Ast::BreakAstType: AstVisitor::visitBreak(dynamic_cast(node)); break; - case Ast::ContinueAstType: AstVisitor::visitContinue(dynamic_cast(node)); break; - case Ast::PrintAstType: AstVisitor::visitPrint(dynamic_cast(node)); break; - case Ast::PassAstType: AstVisitor::visitPass(dynamic_cast(node)); break; - case Ast::BooleanOperationAstType: AstVisitor::visitBooleanOperation(dynamic_cast(node)); break; - case Ast::BinaryOperationAstType: AstVisitor::visitBinaryOperation(dynamic_cast(node)); break; - case Ast::UnaryOperationAstType: AstVisitor::visitUnaryOperation(dynamic_cast(node)); break; - case Ast::LambdaAstType: AstVisitor::visitLambda(dynamic_cast(node)); break; - case Ast::IfExpressionAstType: AstVisitor::visitIfExpression(dynamic_cast(node)); break; - case Ast::DictAstType: AstVisitor::visitDict(dynamic_cast(node)); break; - case Ast::SetAstType: AstVisitor::visitSet(dynamic_cast(node)); break; - case Ast::ListComprehensionAstType: AstVisitor::visitListComprehension(dynamic_cast(node)); break; - case Ast::SetComprehensionAstType: AstVisitor::visitSetComprehension(dynamic_cast(node)); break; - case Ast::DictionaryComprehensionAstType: AstVisitor::visitDictionaryComprehension(dynamic_cast(node)); break; - case Ast::GeneratorExpressionAstType: AstVisitor::visitGeneratorExpression(dynamic_cast(node)); break; - case Ast::CompareAstType: AstVisitor::visitCompare(dynamic_cast(node)); break; - case Ast::ReprAstType: AstVisitor::visitRepr(dynamic_cast(node)); break; - case Ast::NumberAstType: AstVisitor::visitNumber(dynamic_cast(node)); break; - case Ast::StringAstType: AstVisitor::visitString(dynamic_cast(node)); break; - case Ast::YieldAstType: AstVisitor::visitYield(dynamic_cast(node)); break; - case Ast::NameAstType: AstVisitor::visitName(dynamic_cast(node)); break; - case Ast::CallAstType: AstVisitor::visitCall(dynamic_cast(node)); break; - case Ast::AttributeAstType: AstVisitor::visitAttribute(dynamic_cast(node)); break; - case Ast::SubscriptAstType: AstVisitor::visitSubscript(dynamic_cast(node)); break; - case Ast::ListAstType: AstVisitor::visitList(dynamic_cast(node)); break; - case Ast::TupleAstType: AstVisitor::visitTuple(dynamic_cast(node)); break; - case Ast::EllipsisAstType: AstVisitor::visitEllipsis(dynamic_cast(node)); break; - case Ast::SliceAstType: AstVisitor::visitSlice(dynamic_cast(node)); break; - case Ast::ExtendedSliceAstType: AstVisitor::visitExtendedSlice(dynamic_cast(node)); break; - case Ast::IndexAstType: AstVisitor::visitIndex(dynamic_cast(node)); break; - case Ast::ArgumentsAstType: AstVisitor::visitArguments(dynamic_cast(node)); break; - case Ast::KeywordAstType: AstVisitor::visitKeyword(dynamic_cast(node)); break; - case Ast::ComprehensionAstType: AstVisitor::visitComprehension(dynamic_cast(node)); break; - case Ast::ExceptionHandlerAstType: AstVisitor::visitExceptionHandler(dynamic_cast(node)); break; - case Ast::AliasAstType: AstVisitor::visitAlias(dynamic_cast(node)); break; + case Ast::CodeAstType: this->visitCode(dynamic_cast(node)); break; + case Ast::FunctionDefinitionAstType: this->visitFunctionDefinition(dynamic_cast(node)); break; + case Ast::ClassDefinitionAstType: this->visitClassDefinition(dynamic_cast(node)); break; + case Ast::ReturnAstType: this->visitReturn(dynamic_cast(node)); break; + case Ast::DeleteAstType: this->visitDelete(dynamic_cast(node)); break; + case Ast::AssignmentAstType: this->visitAssignment(dynamic_cast(node)); break; + case Ast::AugmentedAssignmentAstType: this->visitAugmentedAssignment(dynamic_cast(node)); break; + case Ast::ForAstType: this->visitFor(dynamic_cast(node)); break; + case Ast::WhileAstType: this->visitWhile(dynamic_cast(node)); break; + case Ast::IfAstType: this->visitIf(dynamic_cast(node)); break; + case Ast::WithAstType: this->visitWith(dynamic_cast(node)); break; + case Ast::RaiseAstType: this->visitRaise(dynamic_cast(node)); break; + case Ast::TryExceptAstType: this->visitTryExcept(dynamic_cast(node)); break; + case Ast::TryFinallyAstType: this->visitTryFinally(dynamic_cast(node)); break; + case Ast::AssertionAstType: this->visitAssertion(dynamic_cast(node)); break; + case Ast::ImportAstType: this->visitImport(dynamic_cast(node)); break; + case Ast::ImportFromAstType: this->visitImportFrom(dynamic_cast(node)); break; + case Ast::ExecAstType: this->visitExec(dynamic_cast(node)); break; + case Ast::GlobalAstType: this->visitGlobal(dynamic_cast(node)); break; + case Ast::BreakAstType: this->visitBreak(dynamic_cast(node)); break; + case Ast::ContinueAstType: this->visitContinue(dynamic_cast(node)); break; + case Ast::PrintAstType: this->visitPrint(dynamic_cast(node)); break; + case Ast::PassAstType: this->visitPass(dynamic_cast(node)); break; + case Ast::BooleanOperationAstType: this->visitBooleanOperation(dynamic_cast(node)); break; + case Ast::BinaryOperationAstType: this->visitBinaryOperation(dynamic_cast(node)); break; + case Ast::UnaryOperationAstType: this->visitUnaryOperation(dynamic_cast(node)); break; + case Ast::LambdaAstType: this->visitLambda(dynamic_cast(node)); break; + case Ast::IfExpressionAstType: this->visitIfExpression(dynamic_cast(node)); break; + case Ast::DictAstType: this->visitDict(dynamic_cast(node)); break; + case Ast::SetAstType: this->visitSet(dynamic_cast(node)); break; + case Ast::ListComprehensionAstType: this->visitListComprehension(dynamic_cast(node)); break; + case Ast::SetComprehensionAstType: this->visitSetComprehension(dynamic_cast(node)); break; + case Ast::DictionaryComprehensionAstType: this->visitDictionaryComprehension(dynamic_cast(node)); break; + case Ast::GeneratorExpressionAstType: this->visitGeneratorExpression(dynamic_cast(node)); break; + case Ast::CompareAstType: this->visitCompare(dynamic_cast(node)); break; + case Ast::ReprAstType: this->visitRepr(dynamic_cast(node)); break; + case Ast::NumberAstType: this->visitNumber(dynamic_cast(node)); break; + case Ast::StringAstType: this->visitString(dynamic_cast(node)); break; + case Ast::YieldAstType: this->visitYield(dynamic_cast(node)); break; + case Ast::NameAstType: this->visitName(dynamic_cast(node)); break; + case Ast::CallAstType: this->visitCall(dynamic_cast(node)); break; + case Ast::AttributeAstType: this->visitAttribute(dynamic_cast(node)); break; + case Ast::SubscriptAstType: this->visitSubscript(dynamic_cast(node)); break; + case Ast::ListAstType: this->visitList(dynamic_cast(node)); break; + case Ast::TupleAstType: this->visitTuple(dynamic_cast(node)); break; + case Ast::EllipsisAstType: this->visitEllipsis(dynamic_cast(node)); break; + case Ast::SliceAstType: this->visitSlice(dynamic_cast(node)); break; + case Ast::ExtendedSliceAstType: this->visitExtendedSlice(dynamic_cast(node)); break; + case Ast::IndexAstType: this->visitIndex(dynamic_cast(node)); break; + case Ast::ArgumentsAstType: this->visitArguments(dynamic_cast(node)); break; + case Ast::KeywordAstType: this->visitKeyword(dynamic_cast(node)); break; + case Ast::ComprehensionAstType: this->visitComprehension(dynamic_cast(node)); break; + case Ast::ExceptionHandlerAstType: this->visitExceptionHandler(dynamic_cast(node)); break; + case Ast::AliasAstType: this->visitAlias(dynamic_cast(node)); break; case Ast::ExpressionAstType: break; case Ast::StatementAstType: break; } diff --git a/pythonpythonparser.py b/pythonpythonparser.py index de74a1a..886090d 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -43,7 +43,7 @@ def generic_visit(self, node): super(KDevelopNodeVisitor, self).generic_visit(node) - key = 'None' + key = '' for field in fields: multiple_keys = [] value = getattr(node, field) @@ -53,14 +53,14 @@ def generic_visit(self, node): try: multiple_keys.append(str(self.childNodeMap[currentValue])) except KeyError: - multiple_keys.append('None') + multiple_keys.append('') key = ','.join(multiple_keys) node_xmlrepr.setAttribute("NRLST_" + field.lower(), str(key)) else: try: key = self.childNodeMap[value] except KeyError: - key = 'None' + key = '' node_xmlrepr.setAttribute("NR_" + field.lower(), str(key)) From c48b1f55ee3a354014fa58a482ddf1461f818ba2 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 21 Oct 2010 22:14:57 +0200 Subject: [PATCH 034/118] Many more populator functions --- duchain/contextbuilder.cpp | 6 +- duchain/contextbuilder.h | 1 + parser/ast.cpp | 2 +- parser/ast.h | 16 +- parser/astbuilder.cpp | 307 +++++++++++++++++++++++++++++++++---- parser/astbuilder.h | 25 +++ pythonparsejob.cpp | 2 +- pythonpythonparser.py | 1 + 8 files changed, 319 insertions(+), 41 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 449a665..4da9e97 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -50,12 +50,16 @@ PythonEditorIntegrator* ContextBuilder::editor() const TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, ParsingEnvironmentFile* file) { IndexedString currentDocumentUrl = m_editor->parseSession()->currentDocument(); + kDebug() << currentDocumentUrl.str(); if ( !file ) { file = new ParsingEnvironmentFile(currentDocumentUrl); file->setLanguage(IndexedString("python")); } - return new TopDUContext(currentDocumentUrl, range, file); + TopDUContext* top = new TopDUContext(currentDocumentUrl, range, file); + ReferencedTopDUContext ref(top); + m_topContext = ref; + return top; } void ContextBuilder::setEditor(PythonEditorIntegrator* editor) diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index af4a4cc..214de05 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -81,6 +81,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public } bool m_mapAst; + ReferencedTopDUContext m_topContext; private: void openContextForStatementList( const QList& ); diff --git a/parser/ast.cpp b/parser/ast.cpp index c802f35..8c70368 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -71,7 +71,7 @@ BreakAst::BreakAst(Ast* parent): StatementAst(parent, Ast::BreakAstType) } -CallAst::CallAst(Ast* parent): ExpressionAst(parent, Ast::CallAstType), function(0), keywordArguments(0) +CallAst::CallAst(Ast* parent): ExpressionAst(parent, Ast::CallAstType), function(0), keywordArguments(0), starArguments(0) { } diff --git a/parser/ast.h b/parser/ast.h index 9e1369b..54879dc 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -132,7 +132,8 @@ class KDEVPYTHONPARSER_EXPORT Ast enum BooleanOperationTypes { BooleanAnd, - BooleanOr + BooleanOr, + BooleanInvalidOperation }; enum OperatorTypes { @@ -147,14 +148,16 @@ class KDEVPYTHONPARSER_EXPORT Ast OperatorBitwiseOr, OperatorBitwiseXor, OperatorBitwiseAnd, - OperatorFloorDivision + OperatorFloorDivision, + OperatorInvalid }; enum UnaryOperatorTypes { UnaryOperatorInvert, UnaryOperatorNot, UnaryOperatorAdd, - UnaryOperatorSub + UnaryOperatorSub, + UnaryOperatorInvalid }; enum ComparisonOperatorTypes { @@ -167,7 +170,8 @@ class KDEVPYTHONPARSER_EXPORT Ast ComparisonOperatorIs, ComparisonOperatorIsNot, ComparisonOperatorIn, - ComparisonOperatorNotIn + ComparisonOperatorNotIn, + ComparisonOperatorInvalid }; Ast(Ast* parent, AstType type); @@ -504,8 +508,8 @@ class KDEVPYTHONPARSER_EXPORT CallAst : public ExpressionAst { ExpressionAst* function; QList arguments; QList keywords; - ExpressionAst* starArguments; ExpressionAst* keywordArguments; + ExpressionAst* starArguments; }; class KDEVPYTHONPARSER_EXPORT AttributeAst : public ExpressionAst { @@ -606,7 +610,7 @@ class KDEVPYTHONPARSER_EXPORT AliasAst : public Ast { public: AliasAst(Ast* parent); Identifier* name; - Identifier* asName; + NameAst* asName; }; } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 8cf4e2f..6b30198 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -269,6 +269,44 @@ ExpressionAst::Context AstBuilder::resolveContext(const QString& identifier) return m_contextNodeMap.value(id); } +Ast::BooleanOperationTypes AstBuilder::resolveBooleanOperator(const QString& identifier) +{ + int id = identifier.toInt(); + if ( ! id ) return Ast::BooleanInvalidOperation; + return m_boolOpNodeMap.value(id); +} + +Ast::OperatorTypes AstBuilder::resolveOperator(const QString& identifier) +{ + int id = identifier.toInt(); + if ( ! id ) return Ast::OperatorInvalid; + return m_opNodeMap.value(id); +} + +Ast::UnaryOperatorTypes AstBuilder::resolveUnaryOperator(const QString& identifier) +{ + int id = identifier.toInt(); + if ( ! id ) return Ast::UnaryOperatorInvalid; + return m_unaryOpNodeMap.value(id); +} + +Ast::ComparisonOperatorTypes AstBuilder::resolveComparisonOperator(const QString& identifier) +{ + int id = identifier.toInt(); + if ( ! id ) return Ast::ComparisonOperatorInvalid; + return m_compOpNodeMap.value(id); +} + +QList< Ast::ComparisonOperatorTypes > AstBuilder::resolveComparisonOperatorList(const QString& identifiers) +{ + QList items; + QList ids = identifiers.split(","); + for ( int i=0; i < ids.length(); i++ ) { + items << resolveComparisonOperator(ids.at(i)); + } + return items; +} + NameAst* AstBuilder::populateNameAst(Ast* ast, const Python::stringDictionary& currentAttributes) { NameAst* currentNode = dynamic_cast(ast); @@ -346,6 +384,208 @@ ReturnAst* AstBuilder::populateReturnAst(Ast* ast, const Python::stringDictionar return currentNode; } +IfAst* AstBuilder::populateIfAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + IfAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->condition = resolveNode(currentAttributes.value("NR_test")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + return currentNode; +} + +BooleanOperationAst* AstBuilder::populateBooleanOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + BooleanOperationAst* currentNode = dynamic_cast(ast); + currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values")); + currentNode->type = resolveBooleanOperator(currentAttributes.value("NR_op")); + return currentNode; +} + +CallAst* AstBuilder::populateCallAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + CallAst* currentNode = dynamic_cast(ast); + currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args")); + currentNode->function = resolveNode(currentAttributes.value("NR_func")); + currentNode->keywordArguments = resolveNode(currentAttributes.value("NR_kwargs")); + currentNode->keywords = resolveNodeList(currentAttributes.value("NRLST_keywords")); + currentNode->starArguments = resolveNode(currentAttributes.value("NR_starargs")); + return currentNode; +} + +LambdaAst* AstBuilder::populateLambdaAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + LambdaAst* currentNode = dynamic_cast(ast); + currentNode->arguments = resolveNode(currentAttributes.value("NR_args")); + currentNode->body = resolveNode(currentAttributes.value("NR_body")); + return currentNode; +} + +WhileAst* AstBuilder::populateWhileAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + WhileAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->condition = resolveNode(currentAttributes.value("NR_test")); + return currentNode; +} + +DictAst* AstBuilder::populateDictAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + DictAst* currentNode = dynamic_cast(ast); + currentNode->keys = resolveNodeList(currentAttributes.value("NRLST_keys")); + currentNode->values = resolveNode(currentAttributes.value("NRLST_values")); + return currentNode; +} + +ListAst* AstBuilder::populateListAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ListAst* currentNode = dynamic_cast(ast); + currentNode->elements = resolveNode(currentAttributes.value("NRLST_elts")); + currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); + return currentNode; +} + +TupleAst* AstBuilder::populateTupleAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + TupleAst* currentNode = dynamic_cast(ast); + currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); + currentNode->elements = resolveNode(currentAttributes.value("NRLST_elts")); + return currentNode; +} + +AugmentedAssignmentAst* AstBuilder::populateAugmentedAssignmentAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + AugmentedAssignmentAst* currentNode = dynamic_cast(ast); + currentNode->op = resolveOperator(currentAttributes.value("NR_op")); + currentNode->target = resolveNode(currentAttributes.value("NR_target")); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + +RaiseAst* AstBuilder::populateRaiseAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + RaiseAst* currentNode = dynamic_cast(ast); + currentNode->type = resolveNode(currentAttributes.value("NR_type")); + return currentNode; +} + +TryExceptAst* AstBuilder::populateTryExceptAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + TryExceptAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->handlers = resolveNodeList(currentAttributes.value("NRLST_handlers")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + return currentNode; +} + +TryFinallyAst* AstBuilder::populateTryFinallyAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + TryFinallyAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->finalbody = resolveNodeList(currentAttributes.value("NRLST_finalbody")); + return currentNode; +} + +AssertionAst* AstBuilder::populateAssertionAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + AssertionAst* currentNode = dynamic_cast(ast); + currentNode->condition = resolveNode(currentAttributes.value("NR_test")); + currentNode->message = resolveNode(currentAttributes.value("NR_msg")); + return currentNode; +} + +BinaryOperationAst* AstBuilder::populateBinaryOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + BinaryOperationAst* currentNode = dynamic_cast(ast); + currentNode->rhs = resolveNode(currentAttributes.value("NR_right")); + currentNode->lhs = resolveNode(currentAttributes.value("NR_left")); + currentNode->type = resolveOperator(currentAttributes.value("NR_op")); + return currentNode; +} + +ImportAst* AstBuilder::populateImportAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ImportAst* currentNode = dynamic_cast(ast); + currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); + return currentNode; +} + +ImportFromAst* AstBuilder::populateImportFromAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ImportFromAst* currentNode = dynamic_cast(ast); + currentNode->level = currentAttributes.value("level").toInt(); + currentNode->module = new Identifier(currentAttributes.value("module")); + currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); + return currentNode; +} + +AliasAst* AstBuilder::populateAliasAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + AliasAst* currentNode = dynamic_cast(ast); + currentNode->asName = resolveNode(currentAttributes.value("NR_asname")); + currentNode->name = new Identifier(currentAttributes.value("name")); + return currentNode; +} + +GlobalAst* AstBuilder::populateGlobalAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + GlobalAst* currentNode = dynamic_cast(ast); +// currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); // TODO the parser does not write this correctly! also, need to fix resolve + return currentNode; +} + +UnaryOperationAst* AstBuilder::populateUnaryOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + UnaryOperationAst* currentNode = dynamic_cast(ast); + currentNode->operand = resolveNode(currentAttributes.value("NR_operand")); + currentNode->type = resolveUnaryOperator(currentAttributes.value("NR_op")); + return currentNode; +} + +IfExpressionAst* AstBuilder::populateIfExpressionAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + IfExpressionAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNode(currentAttributes.value("NR_body")); + currentNode->orelse = resolveNode(currentAttributes.value("NR_orelse")); + currentNode->condition = resolveNode(currentAttributes.value("NR_test")); + return currentNode; +} + +ListComprehensionAst* AstBuilder::populateListComprehensionAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ListComprehensionAst* currentNode = dynamic_cast(ast); + currentNode->generators = resolveNodeList(currentAttributes.value("NRLST_generators")); + currentNode->element = resolveNode(currentAttributes.value("NR_elt")); + return currentNode; +} + +WithAst* AstBuilder::populateWithAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + WithAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->contextExpression = resolveNode(currentAttributes.value("NR_context_expr")); + currentNode->optionalVars = resolveNode(currentAttributes.value("NR_optional_vars")); + return currentNode; +} + +ComprehensionAst* AstBuilder::populateComprehensionAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ComprehensionAst* currentNode = dynamic_cast(ast); + currentNode->conditions = resolveNodeList(currentAttributes.value("NRLST_ifs")); + currentNode->iterator = resolveNode(currentAttributes.value("NR_iter")); + currentNode->target = resolveNode(currentAttributes.value("NR_target")); + return currentNode; +} + +CompareAst* AstBuilder::populateCompareAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + CompareAst* currentNode = dynamic_cast(ast); + currentNode->comparands = resolveNodeList(currentAttributes.value("NRLST_comparators")); + currentNode->operators = resolveComparisonOperatorList(currentAttributes.value("NRLST_ops")); + currentNode->leftmostElement = resolveNode(currentAttributes.value("NR_left")); + return currentNode; +} + void AstBuilder::populateAst() { Ast* currentAbstractNode; @@ -367,8 +607,11 @@ void AstBuilder::populateAst() int startLine = currentAttributes.value("lineno").toInt(); currentAbstractNode->startLine = startLine; + currentAbstractNode->endLine = startLine; int startCol = currentAttributes.value("col_offset").toInt(); currentAbstractNode->startCol = startCol; + currentAbstractNode->endCol = startCol + 10; // TODO fix this ;p + switch ( currentAbstractNode->astType ) { case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; @@ -377,54 +620,54 @@ void AstBuilder::populateAst() case Ast::ReturnAstType: currentAbstractNode = populateReturnAst(currentAbstractNode, currentAttributes); break; case Ast::DeleteAstType: currentAbstractNode = populateDeleteAst(currentAbstractNode, currentAttributes); break; case Ast::AssignmentAstType: currentAbstractNode = populateAssignmentAst(currentAbstractNode, currentAttributes); break; - case Ast::AugmentedAssignmentAstType: break; + case Ast::AugmentedAssignmentAstType: currentAbstractNode = populateAugmentedAssignmentAst(currentAbstractNode, currentAttributes); break; case Ast::ForAstType: currentAbstractNode = populateForAst(currentAbstractNode, currentAttributes); break; - case Ast::WhileAstType: break; - case Ast::IfAstType: break; - case Ast::WithAstType: break; - case Ast::RaiseAstType: break; - case Ast::TryExceptAstType: break; - case Ast::TryFinallyAstType: break; - case Ast::AssertionAstType: break; - case Ast::ImportAstType: break; - case Ast::ImportFromAstType: break; - case Ast::ExecAstType: break; - case Ast::GlobalAstType: break; - case Ast::BreakAstType: break; - case Ast::ContinueAstType: break; + case Ast::WhileAstType: currentAbstractNode = populateWhileAst(currentAbstractNode, currentAttributes); break; + case Ast::IfAstType: currentAbstractNode = populateIfAst(currentAbstractNode, currentAttributes); break; + case Ast::WithAstType: currentAbstractNode = populateWithAst(currentAbstractNode, currentAttributes); break; + case Ast::RaiseAstType: currentAbstractNode = populateRaiseAst(currentAbstractNode, currentAttributes); break; + case Ast::TryExceptAstType: currentAbstractNode = populateTryExceptAst(currentAbstractNode, currentAttributes); break; + case Ast::TryFinallyAstType: currentAbstractNode = populateTryFinallyAst(currentAbstractNode, currentAttributes); break; + case Ast::AssertionAstType: currentAbstractNode = populateAssertionAst(currentAbstractNode, currentAttributes); break; + case Ast::ImportAstType: currentAbstractNode = populateImportAst(currentAbstractNode, currentAttributes); break; + case Ast::ImportFromAstType: currentAbstractNode = populateImportFromAst(currentAbstractNode, currentAttributes); break; +// case Ast::ExecAstType: break; // TODO support this? or better not? :] + case Ast::GlobalAstType: currentAbstractNode = populateGlobalAst(currentAbstractNode, currentAttributes); break; + case Ast::BreakAstType: break; // ok + case Ast::ContinueAstType: break; // ok case Ast::PrintAstType: currentAbstractNode = populatePrintAst(currentAbstractNode, currentAttributes); break; - case Ast::PassAstType: break; - case Ast::BooleanOperationAstType: break; - case Ast::BinaryOperationAstType: break; - case Ast::UnaryOperationAstType: break; - case Ast::LambdaAstType: break; - case Ast::IfExpressionAstType: break; - case Ast::DictAstType: break; - case Ast::SetAstType: break; - case Ast::ListComprehensionAstType: break; - case Ast::SetComprehensionAstType: break; - case Ast::DictionaryComprehensionAstType: break; - case Ast::GeneratorExpressionAstType: break; - case Ast::CompareAstType: break; + case Ast::PassAstType: break; // ok + case Ast::BooleanOperationAstType: currentAbstractNode = populateBooleanOperationAst(currentAbstractNode, currentAttributes); break; + case Ast::BinaryOperationAstType: currentAbstractNode = populateBinaryOperationAst(currentAbstractNode, currentAttributes); break; + case Ast::UnaryOperationAstType: currentAbstractNode = populateUnaryOperationAst(currentAbstractNode, currentAttributes); break; + case Ast::LambdaAstType: currentAbstractNode = populateLambdaAst(currentAbstractNode, currentAttributes); break; + case Ast::IfExpressionAstType: currentAbstractNode = populateIfExpressionAst(currentAbstractNode, currentAttributes); break; + case Ast::DictAstType: currentAbstractNode = populateDictAst(currentAbstractNode, currentAttributes); break; +// case Ast::SetAstType: break; // TODO support this (read about sets) + case Ast::ListComprehensionAstType: currentAbstractNode = populateListComprehensionAst(currentAbstractNode, currentAttributes); break; +// case Ast::SetComprehensionAstType: break; // TODO support this +// case Ast::DictionaryComprehensionAstType: break; // TODO fix this for python 2.7+ +// case Ast::GeneratorExpressionAstType: break; // TODO read about this + case Ast::CompareAstType: currentAbstractNode = populateCompareAst(currentAbstractNode, currentAttributes); break; case Ast::ReprAstType: break; case Ast::NumberAstType: break; case Ast::StringAstType: break; case Ast::YieldAstType: break; case Ast::NameAstType: currentAbstractNode = populateNameAst(currentAbstractNode, currentAttributes); break; - case Ast::CallAstType: break; + case Ast::CallAstType: currentAbstractNode = populateCallAst(currentAbstractNode, currentAttributes); break; case Ast::AttributeAstType: break; case Ast::SubscriptAstType: break; - case Ast::ListAstType: break; - case Ast::TupleAstType: break; + case Ast::ListAstType: currentAbstractNode = populateListAst(currentAbstractNode, currentAttributes); break; + case Ast::TupleAstType: currentAbstractNode = populateTupleAst(currentAbstractNode, currentAttributes); break; case Ast::EllipsisAstType: break; case Ast::SliceAstType: break; case Ast::ExtendedSliceAstType: break; case Ast::IndexAstType: break; case Ast::ArgumentsAstType: break; case Ast::KeywordAstType: break; - case Ast::ComprehensionAstType: break; + case Ast::ComprehensionAstType: currentAbstractNode = populateComprehensionAst(currentAbstractNode, currentAttributes); break; case Ast::ExceptionHandlerAstType: break; - case Ast::AliasAstType: break; + case Ast::AliasAstType: currentAbstractNode = populateAliasAst(currentAbstractNode, currentAttributes); break; case Ast::ExpressionAstType: break; case Ast::StatementAstType: break; } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index caa4ab2..c1315f8 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -94,6 +94,31 @@ class AstBuilder ForAst* populateForAst(Ast* ast, const stringDictionary& currentAttributes); WhileAst* populateWhileAst(Ast* ast, const stringDictionary& currentAttributes); PrintAst* populatePrintAst(Ast* ast, const stringDictionary& currentAttributes); + IfAst* populateIfAst(Ast* ast, const stringDictionary& currentAttributes); + LambdaAst* populateLambdaAst(Ast* ast, const stringDictionary& currentAttributes); + BooleanOperationAst* populateBooleanOperationAst(Ast* ast, const stringDictionary& currentAttributes); + CallAst* populateCallAst(Ast* ast, const stringDictionary& currentAttributes); + DictAst* populateDictAst(Ast* ast, const stringDictionary& currentAttributes); + ListAst* populateListAst(Ast* ast, const stringDictionary& currentAttributes); + TupleAst* populateTupleAst(Ast* ast, const stringDictionary& currentAttributes); + AugmentedAssignmentAst* populateAugmentedAssignmentAst(Ast* ast, const stringDictionary& currentAttributes); + WithAst* populateWithAst(Ast* ast, const stringDictionary& currentAttributes); + RaiseAst* populateRaiseAst(Ast* ast, const stringDictionary& currentAttributes); + TryExceptAst* populateTryExceptAst(Ast* ast, const stringDictionary& currentAttributes); + TryFinallyAst* populateTryFinallyAst(Ast* ast, const stringDictionary& currentAttributes); + AssertionAst* populateAssertionAst(Ast* ast, const stringDictionary& currentAttributes); + ImportAst* populateImportAst(Ast* ast, const stringDictionary& currentAttributes); + ImportFromAst* populateImportFromAst(Ast* ast, const stringDictionary& currentAttributes); + ExecAst* populateExecAst(Ast* ast, const stringDictionary& currentAttributes); + GlobalAst* populateGlobalAst(Ast* ast, const stringDictionary& currentAttributes); + BinaryOperationAst* populateBinaryOperationAst(Ast* ast, const stringDictionary& currentAttributes); + AliasAst* populateAliasAst(Ast* ast, const stringDictionary& currentAttributes); + UnaryOperationAst* populateUnaryOperationAst(Ast* ast, const stringDictionary& currentAttributes); + IfExpressionAst* populateIfExpressionAst(Ast* ast, const stringDictionary& currentAttributes); + ListComprehensionAst* populateListComprehensionAst(Ast* ast, const stringDictionary& currentAttributes); + GeneratorExpressionAst* populateGeneratorExpressionAst(Ast* ast, const stringDictionary& currentAttributes); + ComprehensionAst* populateComprehensionAst(Ast* ast, const stringDictionary& currentAttributes); + CompareAst* populateCompareAst(Ast* ast, const stringDictionary& currentAttributes); }; } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 64161fd..4032755 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -158,7 +158,7 @@ void ParseJob::run() } else { - kDebug() << "===Failed==="; + kWarning() << "===Failed==="; // cleanupSmartRevision(); return; } diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 886090d..56d320a 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -53,6 +53,7 @@ def generic_visit(self, node): try: multiple_keys.append(str(self.childNodeMap[currentValue])) except KeyError: + sys.stderr.write("Warning: missing key on node " + str(node) + "\n") multiple_keys.append('') key = ','.join(multiple_keys) node_xmlrepr.setAttribute("NRLST_" + field.lower(), str(key)) From 04e1e61ae49c1e3cdb52ee6fef70e99ebead6106 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 21 Oct 2010 22:34:43 +0200 Subject: [PATCH 035/118] Implemented almost all populator functions --- parser/astbuilder.cpp | 113 +++++++++++++++++++++++++++++++++++------- parser/astbuilder.h | 9 ++++ 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 6b30198..2bbda26 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -544,7 +544,7 @@ UnaryOperationAst* AstBuilder::populateUnaryOperationAst(Ast* ast, const Python: IfExpressionAst* AstBuilder::populateIfExpressionAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - IfExpressionAst* currentNode = dynamic_cast(ast); + IfExpressionAst* currentNode = dynamic_cast(ast); currentNode->body = resolveNode(currentAttributes.value("NR_body")); currentNode->orelse = resolveNode(currentAttributes.value("NR_orelse")); currentNode->condition = resolveNode(currentAttributes.value("NR_test")); @@ -561,7 +561,7 @@ ListComprehensionAst* AstBuilder::populateListComprehensionAst(Ast* ast, const P WithAst* AstBuilder::populateWithAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - WithAst* currentNode = dynamic_cast(ast); + WithAst* currentNode = dynamic_cast(ast); currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->contextExpression = resolveNode(currentAttributes.value("NR_context_expr")); currentNode->optionalVars = resolveNode(currentAttributes.value("NR_optional_vars")); @@ -570,7 +570,7 @@ WithAst* AstBuilder::populateWithAst(Ast* ast, const Python::stringDictionary& c ComprehensionAst* AstBuilder::populateComprehensionAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - ComprehensionAst* currentNode = dynamic_cast(ast); + ComprehensionAst* currentNode = dynamic_cast(ast); currentNode->conditions = resolveNodeList(currentAttributes.value("NRLST_ifs")); currentNode->iterator = resolveNode(currentAttributes.value("NR_iter")); currentNode->target = resolveNode(currentAttributes.value("NR_target")); @@ -579,13 +579,88 @@ ComprehensionAst* AstBuilder::populateComprehensionAst(Ast* ast, const Python::s CompareAst* AstBuilder::populateCompareAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - CompareAst* currentNode = dynamic_cast(ast); + CompareAst* currentNode = dynamic_cast(ast); currentNode->comparands = resolveNodeList(currentAttributes.value("NRLST_comparators")); currentNode->operators = resolveComparisonOperatorList(currentAttributes.value("NRLST_ops")); currentNode->leftmostElement = resolveNode(currentAttributes.value("NR_left")); return currentNode; } +NumberAst* AstBuilder::populateNumberAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + NumberAst* currentNode = dynamic_cast(ast); + currentNode->value = currentAttributes.value("n"); // save this as a QString to aviod problems with python number formats like 3j+2 (complex), 3L, 3.35, etc. + return currentNode; +} + +StringAst* AstBuilder::populateStringAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + StringAst* currentNode = dynamic_cast(ast); + currentNode->value = currentAttributes.value("s"); + return currentNode; +} + +AttributeAst* AstBuilder::populateAttributeAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + AttributeAst* currentNode = dynamic_cast(ast); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + currentNode->attribute = new Identifier(currentAttributes.value("attr")); + currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); + return currentNode; +} + +SubscriptAst* AstBuilder::populateSubscriptAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + SubscriptAst* currentNode = dynamic_cast(ast); + currentNode->context = resolveContext("NR_ctx"); + currentNode->slice = resolveNode(currentAttributes.value("NR_slice")); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + +SliceAst* AstBuilder::populateSliceAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + SliceAst* currentNode = dynamic_cast(ast); + currentNode->lower = resolveNode(currentAttributes.value("NR_lower")); + currentNode->upper = resolveNode(currentAttributes.value("NR_upper")); + currentNode->step = resolveNode(currentAttributes.value("NR_step")); + return currentNode; +} + +ArgumentsAst* AstBuilder::populateArgumentsAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ArgumentsAst* currentNode = dynamic_cast(ast); + currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args")); + currentNode->defaultValues = resolveNodeList(currentAttributes.value("NRLST_defaults")); + currentNode->kwarg = currentAttributes.value("kwarg"); + currentNode->vararg = currentAttributes.value("paramstar"); + return currentNode; +} + +ExceptionHandlerAst* AstBuilder::populateExceptionHandlerAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ExceptionHandlerAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->name = resolveNode(currentAttributes.value("NR_name")); + currentNode->type = resolveNode(currentAttributes.value("NR_type")); + return currentNode; +} + +IndexAst* AstBuilder::populateIndexAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + IndexAst* currentNode = dynamic_cast(ast); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + +KeywordAst* AstBuilder::populateKeywordAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + KeywordAst* currentNode = dynamic_cast(ast); + currentNode->argumentName = currentAttributes.value("arg"); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + void AstBuilder::populateAst() { Ast* currentAbstractNode; @@ -649,27 +724,27 @@ void AstBuilder::populateAst() // case Ast::DictionaryComprehensionAstType: break; // TODO fix this for python 2.7+ // case Ast::GeneratorExpressionAstType: break; // TODO read about this case Ast::CompareAstType: currentAbstractNode = populateCompareAst(currentAbstractNode, currentAttributes); break; - case Ast::ReprAstType: break; - case Ast::NumberAstType: break; - case Ast::StringAstType: break; - case Ast::YieldAstType: break; +// case Ast::ReprAstType: break; // TODO support this + case Ast::NumberAstType: currentAbstractNode = populateNumberAst(currentAbstractNode, currentAttributes); break; + case Ast::StringAstType: currentAbstractNode = populateStringAst(currentAbstractNode, currentAttributes); break; +// case Ast::YieldAstType: break; // TODO TODO case Ast::NameAstType: currentAbstractNode = populateNameAst(currentAbstractNode, currentAttributes); break; case Ast::CallAstType: currentAbstractNode = populateCallAst(currentAbstractNode, currentAttributes); break; - case Ast::AttributeAstType: break; - case Ast::SubscriptAstType: break; + case Ast::AttributeAstType: currentAbstractNode = populateAttributeAst(currentAbstractNode, currentAttributes); break; + case Ast::SubscriptAstType: currentAbstractNode = populateSubscriptAst(currentAbstractNode, currentAttributes); break; case Ast::ListAstType: currentAbstractNode = populateListAst(currentAbstractNode, currentAttributes); break; case Ast::TupleAstType: currentAbstractNode = populateTupleAst(currentAbstractNode, currentAttributes); break; - case Ast::EllipsisAstType: break; - case Ast::SliceAstType: break; - case Ast::ExtendedSliceAstType: break; - case Ast::IndexAstType: break; - case Ast::ArgumentsAstType: break; - case Ast::KeywordAstType: break; +// case Ast::EllipsisAstType: break; // TODO TODO + case Ast::SliceAstType: currentAbstractNode = populateSliceAst(currentAbstractNode, currentAttributes); break; +// case Ast::ExtendedSliceAstType: break; // TODO TODO + case Ast::IndexAstType: currentAbstractNode = populateIndexAst(currentAbstractNode, currentAttributes); break; + case Ast::ArgumentsAstType: currentAbstractNode = populateArgumentsAst(currentAbstractNode, currentAttributes); break; + case Ast::KeywordAstType: currentAbstractNode = populateKeywordAst(currentAbstractNode, currentAttributes); break; case Ast::ComprehensionAstType: currentAbstractNode = populateComprehensionAst(currentAbstractNode, currentAttributes); break; - case Ast::ExceptionHandlerAstType: break; + case Ast::ExceptionHandlerAstType: currentAbstractNode = populateExceptionHandlerAst(currentAbstractNode, currentAttributes); break; case Ast::AliasAstType: currentAbstractNode = populateAliasAst(currentAbstractNode, currentAttributes); break; - case Ast::ExpressionAstType: break; - case Ast::StatementAstType: break; + case Ast::ExpressionAstType: break; // ok + case Ast::StatementAstType: break; // ok } } } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index c1315f8..51f2319 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -119,6 +119,15 @@ class AstBuilder GeneratorExpressionAst* populateGeneratorExpressionAst(Ast* ast, const stringDictionary& currentAttributes); ComprehensionAst* populateComprehensionAst(Ast* ast, const stringDictionary& currentAttributes); CompareAst* populateCompareAst(Ast* ast, const stringDictionary& currentAttributes); + NumberAst* populateNumberAst(Ast* ast, const stringDictionary& currentAttributes); + StringAst* populateStringAst(Ast* ast, const stringDictionary& currentAttributes); + AttributeAst* populateAttributeAst(Ast* ast, const stringDictionary& currentAttributes); + SubscriptAst* populateSubscriptAst(Ast* ast, const stringDictionary& currentAttributes); + SliceAst* populateSliceAst(Ast* ast, const stringDictionary& currentAttributes); + KeywordAst* populateKeywordAst(Ast* ast, const stringDictionary& currentAttributes); + ArgumentsAst* populateArgumentsAst(Ast* ast, const stringDictionary& currentAttributes); + IndexAst* populateIndexAst(Ast* ast, const stringDictionary& currentAttributes); + ExceptionHandlerAst* populateExceptionHandlerAst(Ast* ast, const stringDictionary& currentAttributes); }; } From c9ab75ba59942edc12ee6e4f76baad3529eab109 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 21 Oct 2010 22:37:36 +0200 Subject: [PATCH 036/118] Fixed build errors --- parser/astbuilder.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 2bbda26..10db19f 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -433,14 +433,14 @@ DictAst* AstBuilder::populateDictAst(Ast* ast, const Python::stringDictionary& c { DictAst* currentNode = dynamic_cast(ast); currentNode->keys = resolveNodeList(currentAttributes.value("NRLST_keys")); - currentNode->values = resolveNode(currentAttributes.value("NRLST_values")); + currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values")); return currentNode; } ListAst* AstBuilder::populateListAst(Ast* ast, const Python::stringDictionary& currentAttributes) { ListAst* currentNode = dynamic_cast(ast); - currentNode->elements = resolveNode(currentAttributes.value("NRLST_elts")); + currentNode->elements = resolveNodeList(currentAttributes.value("NRLST_elts")); currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); return currentNode; } @@ -449,7 +449,7 @@ TupleAst* AstBuilder::populateTupleAst(Ast* ast, const Python::stringDictionary& { TupleAst* currentNode = dynamic_cast(ast); currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); - currentNode->elements = resolveNode(currentAttributes.value("NRLST_elts")); + currentNode->elements = resolveNodeList(currentAttributes.value("NRLST_elts")); return currentNode; } @@ -506,7 +506,7 @@ BinaryOperationAst* AstBuilder::populateBinaryOperationAst(Ast* ast, const Pytho ImportAst* AstBuilder::populateImportAst(Ast* ast, const Python::stringDictionary& currentAttributes) { ImportAst* currentNode = dynamic_cast(ast); - currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); + currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); return currentNode; } @@ -629,17 +629,17 @@ SliceAst* AstBuilder::populateSliceAst(Ast* ast, const Python::stringDictionary& ArgumentsAst* AstBuilder::populateArgumentsAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - ArgumentsAst* currentNode = dynamic_cast(ast); + ArgumentsAst* currentNode = dynamic_cast(ast); currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args")); currentNode->defaultValues = resolveNodeList(currentAttributes.value("NRLST_defaults")); - currentNode->kwarg = currentAttributes.value("kwarg"); - currentNode->vararg = currentAttributes.value("paramstar"); + currentNode->kwarg = new Identifier(currentAttributes.value("kwarg")); + currentNode->vararg = new Identifier(currentAttributes.value("paramstar")); return currentNode; } ExceptionHandlerAst* AstBuilder::populateExceptionHandlerAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - ExceptionHandlerAst* currentNode = dynamic_cast(ast); + ExceptionHandlerAst* currentNode = dynamic_cast(ast); currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->name = resolveNode(currentAttributes.value("NR_name")); currentNode->type = resolveNode(currentAttributes.value("NR_type")); @@ -648,15 +648,15 @@ ExceptionHandlerAst* AstBuilder::populateExceptionHandlerAst(Ast* ast, const Pyt IndexAst* AstBuilder::populateIndexAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - IndexAst* currentNode = dynamic_cast(ast); + IndexAst* currentNode = dynamic_cast(ast); currentNode->value = resolveNode(currentAttributes.value("NR_value")); return currentNode; } KeywordAst* AstBuilder::populateKeywordAst(Ast* ast, const Python::stringDictionary& currentAttributes) { - KeywordAst* currentNode = dynamic_cast(ast); - currentNode->argumentName = currentAttributes.value("arg"); + KeywordAst* currentNode = dynamic_cast(ast); + currentNode->argumentName = new Identifier(currentAttributes.value("arg")); currentNode->value = resolveNode(currentAttributes.value("NR_value")); return currentNode; } From 7145631aa7ec61390da1f1ae5d29aa26d85a2d42 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 21 Oct 2010 23:14:42 +0200 Subject: [PATCH 037/118] Bugfixes, CMake adjustment for pythonpythonparser.py --- CMakeLists.txt | 1 + parser/astbuilder.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dda0955..dc7c418 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,3 +54,4 @@ target_link_libraries(kdevpythonlanguagesupport install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES pythonpythonparser.py DESTINATION ${PLUGIN_INSTALL_DIR}) \ No newline at end of file diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 10db19f..a97a2d2 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -45,7 +45,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) { QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST - parser->start("/home/sven/projects/kde4/python/pythonpythonparser.py", QStringList(filename.path())); // TODO fix this + parser->start("./pythonpythonparser.py", QStringList(filename.path())); // TODO fix this parser->waitForFinished(); // TODO this is not clean From f3f2c2f899c0ea01cdece0a73b1d9187652d5953 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 21 Oct 2010 23:58:28 +0200 Subject: [PATCH 038/118] CMake fix for python parser (2) --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc7c418..a388d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories( ${KDE4_INCLUDES} ${KDE4_INCLUDE_DIR}/threadweaver ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/duchain ${CMAKE_CURRENT_SOURCE_DIR}/parser ${CMAKE_CURRENT_BINARY_DIR}/parser @@ -54,4 +55,4 @@ target_link_libraries(kdevpythonlanguagesupport install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) -install(FILES pythonpythonparser.py DESTINATION ${PLUGIN_INSTALL_DIR}) \ No newline at end of file +install(FILES pythonpythonparser.py DESTINATION ${LIB_INSTALL_DIR}) \ No newline at end of file From 0b894ee1fd3afb23e65bafdf66ea30394d3049f9 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 23 Oct 2010 13:58:38 +0200 Subject: [PATCH 039/118] Highlighting now takes place again --- CMakeLists.txt | 2 +- parser/CMakeLists.txt | 1 + parser/astbuilder.cpp | 18 ++++++++++++++---- parser/parsesession.cpp | 14 +++++++------- parser/parsesession.h | 2 +- parser/pythondriver.cpp | 40 +++++++++++----------------------------- parser/pythondriver.h | 6 ++++-- pythonhighlighting.h | 1 - pythonparsejob.cpp | 11 +++++++++-- 9 files changed, 48 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a388d17..3d777ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,4 +55,4 @@ target_link_libraries(kdevpythonlanguagesupport install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) -install(FILES pythonpythonparser.py DESTINATION ${LIB_INSTALL_DIR}) \ No newline at end of file +install(FILES pythonpythonparser.py DESTINATION ${BIN_INSTALL_DIR}) diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index e61bb70..7118f68 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -8,6 +8,7 @@ set(parser_STAT_SRCS astdefaultvisitor.cpp astvisitor.cpp astbuilder.cpp + pythondriver.cpp ) # kdevpgqt_generate(_kdevpgList python NAMESPACE PythonParser diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index a97a2d2..5b4a869 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -31,6 +31,7 @@ #include "kurl.h" #include #include +#include namespace Python { @@ -45,7 +46,8 @@ QString AstBuilder::getXmlForFile(KUrl filename) { QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST - parser->start("./pythonpythonparser.py", QStringList(filename.path())); // TODO fix this + kDebug() << QDir::current(); + parser->start("/usr/bin/env", QStringList() << "python" << "/home/sven/projects/compiled/kde4/bin/pythonpythonparser.py" << filename.path()); parser->waitForFinished(); // TODO this is not clean @@ -62,6 +64,8 @@ QString AstBuilder::getXmlForFile(KUrl filename) CodeAst* AstBuilder::parseXmlAst(QString xml) { + Q_ASSERT(xml.length()); + QXmlStreamReader* xmlast = new QXmlStreamReader(); xmlast->addData(xml); @@ -72,8 +76,7 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) populateAst(); CodeAst* codeAst = dynamic_cast(m_currentNode); - if ( ! codeAst ) - Q_ASSERT(codeAst); + Q_ASSERT(codeAst); return codeAst; } @@ -242,6 +245,7 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea m_attributeStore.insert(node_id, attributeDict); m_nodeStack.append(ast); + kDebug() << "Stack size: " << m_nodeStack.length(); return true; } @@ -685,8 +689,14 @@ void AstBuilder::populateAst() currentAbstractNode->endLine = startLine; int startCol = currentAttributes.value("col_offset").toInt(); currentAbstractNode->startCol = startCol; - currentAbstractNode->endCol = startCol + 10; // TODO fix this ;p + currentAbstractNode->endCol = startCol + 100; // TODO fix this ;p + if ( ! currentAbstractNode->startLine && currentAbstractNode->parent ) { + currentAbstractNode->startLine = currentAbstractNode->parent->startLine; + currentAbstractNode->endLine = currentAbstractNode->parent->endLine; + currentAbstractNode->startCol = currentAbstractNode->parent->startCol; + currentAbstractNode->endCol = currentAbstractNode->parent->endCol; + } switch ( currentAbstractNode->astType ) { case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index c852e18..af31425 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -42,12 +42,12 @@ ParseSession::~ParseSession() void ParseSession::setCurrentDocument(KUrl& filename) { - m_currentDocument = filename; + m_currentDocument = KDevelop::IndexedString(filename); } IndexedString ParseSession::currentDocument() { - return KDevelop::IndexedString(m_currentDocument.fileName()); + return m_currentDocument; } @@ -63,11 +63,11 @@ void ParseSession::setContents( const QString& contents ) QPair ParseSession::parse( Python::CodeAst* ast ) { - AstBuilder parser; - ast = parser.parse(m_currentDocument); - if ( ! ast ) - Q_ASSERT(false); - return QPair(ast, true); + Driver driver; + driver.setCurrentDocument(m_currentDocument.toUrl()); + QPair result = driver.parse(ast); + Q_ASSERT(result.first); + return result; } } diff --git a/parser/parsesession.h b/parser/parsesession.h index 87ae758..a6cfc23 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -64,7 +64,7 @@ class KDEVPYTHONPARSER_EXPORT ParseSession private: QString m_contents; - KUrl m_currentDocument; + KDevelop::IndexedString m_currentDocument; }; diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 223d595..3d6a057 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -60,41 +60,23 @@ void Driver::setDebug( bool debug ) m_debug = debug; } -bool Driver::parse( Python::CodeAst** ast ) +void Driver::setCurrentDocument(KUrl url) { - if(!m_tokenstream) - m_tokenstream = new KDevPG::TokenStream(); - if(!m_pool) - m_pool = new KDevPG::MemoryPool(); - - PythonParser::Parser pythonparser; - pythonparser.setTokenStream( m_tokenstream ); - pythonparser.setMemoryPool( m_pool ); - pythonparser.setDebug( m_debug ); + m_currentDocument = url; +} - pythonparser.tokenize(m_content); - PythonParser::ProjectAst* srcast; - bool matched = pythonparser.parseProject( &srcast ); - if( matched ) +QPair Driver::parse( Python::CodeAst* ast ) +{ + AstBuilder pythonparser; + QPair matched; + matched.first = pythonparser.parse( m_currentDocument ); + matched.second = true; // TODO fix this + if( matched.second ) { kDebug() << "Sucessfully parsed"; -// if( m_debug ) -// { -// PythonParser::DebugVisitor d( pythonparser.tokenStream ); -// d.visitProject(*srcast); -// } - Python::AstBuilder builder(&pythonparser); - builder.visitProject( srcast ); - for ( int i=0; i < builder.mNodeStack.count(); i++ ) { - Ast* dbg_node = builder.mNodeStack.at(i); - kDebug() << dbg_node; - } - *ast = builder.codeAst(); - }else { - *ast = 0; - pythonparser.expectedSymbol(PythonParser::AstNode::ProjectKind, "project"); + matched.first = 0; kDebug() << "Couldn't parse content"; } return matched; diff --git a/parser/pythondriver.h b/parser/pythondriver.h index 9104d55..405c285 100644 --- a/parser/pythondriver.h +++ b/parser/pythondriver.h @@ -23,6 +23,7 @@ #include #include "parserexport.h" +#include namespace KDevPG { class MemoryPool; @@ -45,15 +46,16 @@ class KDEVPYTHONPARSER_EXPORT Driver bool readFile( const QString&, const char* = 0 ); void setContent( const QString& ); void setDebug( bool ); - bool parse( Python::CodeAst** ast ); + QPair parse( Python::CodeAst* ast ); void setTokenStream( KDevPG::TokenStream* ); void setMemoryPool( KDevPG::MemoryPool* ); + void setCurrentDocument(KUrl url); private: QString m_content; bool m_debug; KDevPG::MemoryPool* m_pool; KDevPG::TokenStream* m_tokenstream; - + KUrl m_currentDocument; }; } diff --git a/pythonhighlighting.h b/pythonhighlighting.h index 2459001..354fa84 100644 --- a/pythonhighlighting.h +++ b/pythonhighlighting.h @@ -38,7 +38,6 @@ class Highlighting : public KDevelop::CodeHighlighting Q_OBJECT public: Highlighting( QObject* parent ); - }; } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 4032755..66793ef 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -49,6 +49,10 @@ #include "usebuilder.h" // #include "astprinter.h" // #include "usebuilder.h" +#include +#include +#include + using namespace KDevelop; @@ -107,6 +111,9 @@ void ParseJob::run() m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); m_session->setCurrentDocument(m_url); + IndexedString test(m_url); + kDebug() << m_url.toLocalFile(); + if ( abortRequested() ) return abortJob(); @@ -138,7 +145,7 @@ void ParseJob::run() usebuilder.buildUses(m_ast); kDebug() << "----Parsing Succeded---***"; - + // { // DUChainReadLocker lock( DUChain::lock() ); // DumpChain dump; @@ -148,7 +155,7 @@ void ParseJob::run() { if ( m_parent && m_parent->codeHighlighting() ) { kDebug() << m_duContext.data(); -// DUChainReadLocker lock(DUChain::lock()); + DUChainReadLocker lock(DUChain::lock()); KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); hl->highlightDUChain(m_duContext); } From fcb274f4256573ccf334ba8f91d5b8937f7a699f Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 23 Oct 2010 18:48:27 +0200 Subject: [PATCH 040/118] Basic highlighting restored, bugs fixed --- duchain/contextbuilder.cpp | 11 ++++++----- duchain/contextbuilder.h | 2 +- duchain/declarationbuilder.cpp | 14 ++++++++++++++ duchain/declarationbuilder.h | 1 + duchain/usebuilder.cpp | 13 ++++++++++++- duchain/usebuilder.h | 2 ++ parser/astbuilder.cpp | 34 ++++++++++++++++++++++++---------- parser/astbuilder.h | 2 ++ 8 files changed, 62 insertions(+), 17 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 4da9e97..b1ed3f0 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -21,7 +21,7 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ -#include +#include "contextbuilder.h" // #include #include #include @@ -38,18 +38,19 @@ using namespace KDevelop; using namespace KTextEditor; +Python::PythonEditorIntegrator* Python::ContextBuilder::m_editor; + namespace Python { PythonEditorIntegrator* ContextBuilder::editor() const { -// return static_cast(ContextBuilderBase::editor()); - return m_editor; + return ContextBuilder::m_editor; } TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, ParsingEnvironmentFile* file) { - IndexedString currentDocumentUrl = m_editor->parseSession()->currentDocument(); + IndexedString currentDocumentUrl = ContextBuilder::m_editor->parseSession()->currentDocument(); kDebug() << currentDocumentUrl.str(); if ( !file ) { @@ -65,7 +66,7 @@ TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, Parsin void ContextBuilder::setEditor(PythonEditorIntegrator* editor) { //m_identifierCompiler = new IdentifierCompiler(editor->parseSession()); - m_editor = editor; + ContextBuilder::m_editor = editor; } void ContextBuilder::setEditor(ParseSession* session) diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 214de05..07eca2e 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -66,7 +66,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitWhile( WhileAst* node ); virtual void visitIf( IfAst* node ); - PythonEditorIntegrator *m_editor; + static PythonEditorIntegrator* m_editor; TopDUContext* newTopContext(const RangeInRevision& range, ParsingEnvironmentFile* file); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 95d7bb0..556023b 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -40,6 +40,7 @@ #include #include "pythoneditorintegrator.h" +#include "QtGlobal" using namespace KTextEditor; @@ -80,6 +81,19 @@ void DeclarationBuilder::closeDeclaration() DeclarationBuilderBase::closeDeclaration(); } +void DeclarationBuilder::visitAssignment(AssignmentAst* node) +{ + NameAst* currentVariableDefinition; + foreach ( ExpressionAst* target, node->targets ) { + if ( target->astType == Ast::NameAstType ) { + currentVariableDefinition = dynamic_cast(target); + openDeclaration(currentVariableDefinition->identifier, currentVariableDefinition); + closeDeclaration(); + } + } + visitNode(node->value); +} + // void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) // { // Python::AstDefaultVisitor::visitIdentifierTarget(node); diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 240c493..569bd01 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -49,6 +49,7 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitFunctionDefinition( FunctionDefinitionAst* node ); virtual void visitArguments( ArgumentsAst* node ); virtual void visitLambda( LambdaAst* node ); + virtual void visitAssignment(AssignmentAst* node); // virtual void visitIdentifierTarget( IdentifierTargetAst * node ); diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index d7da97e..a154d13 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -40,7 +40,7 @@ using namespace KDevelop; namespace Python { -UseBuilder::UseBuilder (PythonEditorIntegrator* editor) +UseBuilder::UseBuilder (PythonEditorIntegrator* editor) : m_editor(editor) { } @@ -51,6 +51,17 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) // // top->setHasUses(true); // } +void UseBuilder::visitName(NameAst* node) +{ + DUChainWriteLocker lock(DUChain::lock()); + QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).start); + if ( ! declarations.length() ) return; + Declaration* dec = declarations.last(); + if ( node->context == ExpressionAst::Load ) { + UseBuilderBase::newUse(node, dec); + } +} + void UseBuilder::visitIdentifier(Identifier* node) { DUChainWriteLocker lock( DUChain::lock() ); diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 0e38dc0..915945e 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -48,8 +48,10 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase virtual void closeContext(); virtual void visitIdentifier(Identifier* node); + virtual void visitName(NameAst* node); private: ParseSession* m_session; + PythonEditorIntegrator* m_editor; // void newUse(std::size_t name, Ast *rangenode); inline int& nextUseIndex() { diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 5b4a869..bd892db 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -266,6 +266,16 @@ template QList AstBuilder::resolveNodeList(const QString& comma return items; } +Identifier* AstBuilder::createIdentifier(const QString& name, Ast* range) +{ + Identifier* ident = new Identifier(name); + ident->startCol = range->startCol; + ident->endCol = range->startCol + name.length() - 1; + ident->startLine = range->startLine; + ident->endLine = range->endLine; + return ident; +} + ExpressionAst::Context AstBuilder::resolveContext(const QString& identifier) { int id = identifier.toInt(); @@ -315,7 +325,7 @@ NameAst* AstBuilder::populateNameAst(Ast* ast, const Python::stringDictionary& c { NameAst* currentNode = dynamic_cast(ast); currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); - currentNode->identifier = new Identifier(currentAttributes.value("id")); + currentNode->identifier = createIdentifier(currentAttributes.value("id"), currentNode); kDebug() << "Processing NameAst" << currentNode->identifier->value; return currentNode; } @@ -326,7 +336,9 @@ ClassDefinitionAst* AstBuilder::populateClassDefinitonAst(Ast* ast, const Python currentNode->baseClasses = resolveNodeList(currentAttributes.value("NRLST_bases")); currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); - currentNode->name = new Identifier(currentAttributes.value("name")); + currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode); + currentNode->name->startCol += 6; // TODO fix this! ;D + currentNode->name->endCol += 6; return currentNode; } @@ -336,7 +348,9 @@ FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const currentNode->arguments = resolveNode(currentAttributes.value("NR_args")); currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); - currentNode->name = new Identifier(currentAttributes.value("name")); + currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode); + currentNode->name->startCol += 4; // TODO fix this! ;D + currentNode->name->endCol += 4; return currentNode; } @@ -518,7 +532,7 @@ ImportFromAst* AstBuilder::populateImportFromAst(Ast* ast, const Python::stringD { ImportFromAst* currentNode = dynamic_cast(ast); currentNode->level = currentAttributes.value("level").toInt(); - currentNode->module = new Identifier(currentAttributes.value("module")); + currentNode->module = createIdentifier(currentAttributes.value("module"), currentNode); currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); return currentNode; } @@ -527,7 +541,7 @@ AliasAst* AstBuilder::populateAliasAst(Ast* ast, const Python::stringDictionary& { AliasAst* currentNode = dynamic_cast(ast); currentNode->asName = resolveNode(currentAttributes.value("NR_asname")); - currentNode->name = new Identifier(currentAttributes.value("name")); + currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode); return currentNode; } @@ -608,7 +622,7 @@ AttributeAst* AstBuilder::populateAttributeAst(Ast* ast, const Python::stringDic { AttributeAst* currentNode = dynamic_cast(ast); currentNode->value = resolveNode(currentAttributes.value("NR_value")); - currentNode->attribute = new Identifier(currentAttributes.value("attr")); + currentNode->attribute = createIdentifier(currentAttributes.value("attr"), currentNode); currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); return currentNode; } @@ -636,8 +650,8 @@ ArgumentsAst* AstBuilder::populateArgumentsAst(Ast* ast, const Python::stringDic ArgumentsAst* currentNode = dynamic_cast(ast); currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args")); currentNode->defaultValues = resolveNodeList(currentAttributes.value("NRLST_defaults")); - currentNode->kwarg = new Identifier(currentAttributes.value("kwarg")); - currentNode->vararg = new Identifier(currentAttributes.value("paramstar")); + currentNode->kwarg = createIdentifier(currentAttributes.value("kwarg"), currentNode); + currentNode->vararg = createIdentifier(currentAttributes.value("paramstar"), currentNode); return currentNode; } @@ -660,7 +674,7 @@ IndexAst* AstBuilder::populateIndexAst(Ast* ast, const Python::stringDictionary& KeywordAst* AstBuilder::populateKeywordAst(Ast* ast, const Python::stringDictionary& currentAttributes) { KeywordAst* currentNode = dynamic_cast(ast); - currentNode->argumentName = new Identifier(currentAttributes.value("arg")); + currentNode->argumentName = createIdentifier(currentAttributes.value("arg"), currentNode); currentNode->value = resolveNode(currentAttributes.value("NR_value")); return currentNode; } @@ -684,7 +698,7 @@ void AstBuilder::populateAst() ++i; } - int startLine = currentAttributes.value("lineno").toInt(); + int startLine = currentAttributes.value("lineno").toInt() - 1; // start = 0 <> start = 1 currentAbstractNode->startLine = startLine; currentAbstractNode->endLine = startLine; int startCol = currentAttributes.value("col_offset").toInt(); diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 51f2319..1763483 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -84,6 +84,8 @@ class AstBuilder template QList resolveNodeList(const QString& commaSeperatedIdentifiers); template T* resolveNode(const QString& identifier); + Identifier* createIdentifier(const QString& name, Ast* range); + FunctionDefinitionAst* populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes); AssignmentAst* populateAssignmentAst(Ast* ast, const stringDictionary& currentAttributes); CodeAst* populateCodeAst(Ast* ast, const stringDictionary& currentAttributes); From 366230653af1e2d57e77dc0fafa447eeeb2bb48d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 01:13:23 +0200 Subject: [PATCH 041/118] Fixed various bugs and added new features. --- duchain/declarationbuilder.cpp | 44 ++++++++++++++++++++++++++++++---- duchain/declarationbuilder.h | 6 +++++ parser/astbuilder.cpp | 23 ++++++++++++++++-- parser/parsesession.cpp | 1 - parser/pythondriver.cpp | 2 +- pythonpythonparser.py | 8 +++++-- 6 files changed, 74 insertions(+), 10 deletions(-) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 556023b..a77424f 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -81,14 +81,50 @@ void DeclarationBuilder::closeDeclaration() DeclarationBuilderBase::closeDeclaration(); } +void DeclarationBuilder::visitVariableDeclaration(Ast* node) +{ + NameAst* currentVariableDefinition = dynamic_cast(node); + kDebug() << node->astType; + Q_ASSERT(currentVariableDefinition); + openDeclaration(currentVariableDefinition->identifier, currentVariableDefinition); + closeDeclaration(); +} + +void DeclarationBuilder::visitVariableDeclaration(Identifier* node) +{ + openDeclaration(node, node); + closeDeclaration(); +} + +void DeclarationBuilder::visitFor(ForAst* node) +{ + Python::ContextBuilder::visitFor(node); + visitVariableDeclaration(node->target); +} + +void DeclarationBuilder::visitImport(ImportAst* node) +{ + Python::AstDefaultVisitor::visitImport(node); + foreach ( AliasAst* name, node->names ) { + if ( name->asName ) visitVariableDeclaration(name->asName); + else visitVariableDeclaration(name->name); + } +} + +void DeclarationBuilder::visitImportFrom(ImportFromAst* node) +{ + Python::AstDefaultVisitor::visitImportFrom(node); + foreach ( AliasAst* name, node->names ) { + if ( name->asName ) visitVariableDeclaration(name->asName); + else visitVariableDeclaration(name->name); + } +} + void DeclarationBuilder::visitAssignment(AssignmentAst* node) { - NameAst* currentVariableDefinition; foreach ( ExpressionAst* target, node->targets ) { if ( target->astType == Ast::NameAstType ) { - currentVariableDefinition = dynamic_cast(target); - openDeclaration(currentVariableDefinition->identifier, currentVariableDefinition); - closeDeclaration(); + visitVariableDeclaration(target); } } visitNode(node->value); diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 569bd01..1d26aa9 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -50,6 +50,12 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitArguments( ArgumentsAst* node ); virtual void visitLambda( LambdaAst* node ); virtual void visitAssignment(AssignmentAst* node); + virtual void visitFor(ForAst* node); + virtual void visitImport(ImportAst* node); + virtual void visitImportFrom(ImportFromAst* node); + + void visitVariableDeclaration(Ast* node); + void visitVariableDeclaration(Identifier* node); // virtual void visitIdentifierTarget( IdentifierTargetAst * node ); diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index bd892db..dd9340d 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include namespace Python { @@ -47,7 +49,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST kDebug() << QDir::current(); - parser->start("/usr/bin/env", QStringList() << "python" << "/home/sven/projects/compiled/kde4/bin/pythonpythonparser.py" << filename.path()); + parser->start("/usr/bin/env", QStringList() << "python" << "pythonpythonparser.py" << filename.path()); parser->waitForFinished(); // TODO this is not clean @@ -58,6 +60,19 @@ QString AstBuilder::getXmlForFile(KUrl filename) QString result = parser->readAllStandardOutput(); kDebug() << "XML for " << filename << ":" << result; + + if ( ! result.length() ) { + result = parser->readAllStandardError(); + result.split(":"); + int lineno = result[0].toAscii(); + int colno = result[1].toAscii(); + KDevelop::ProblemPointer p(new KDevelop::Problem()); + p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno, lineno, colno + 1))); + p->setSource(KDevelop::ProblemData::Disk); + p->setDescription(result); + kWarning() << "Parse Error: " << result; + return "0"; + } delete parser; return result; } @@ -66,6 +81,10 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) { Q_ASSERT(xml.length()); + if ( xml == "0" ) { + return 0; + } + QXmlStreamReader* xmlast = new QXmlStreamReader(); xmlast->addData(xml); @@ -261,7 +280,7 @@ template QList AstBuilder::resolveNodeList(const QString& comma QList items; QStringList identifiers = commaSeperatedIdentifiers.split(","); for ( int i=0; i(identifiers.at(i)); + if ( identifiers.at(i).length() ) items << resolveNode(identifiers.at(i)); } return items; } diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index af31425..4d4cdf3 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -66,7 +66,6 @@ QPair ParseSession::parse( Python::CodeAst* ast ) Driver driver; driver.setCurrentDocument(m_currentDocument.toUrl()); QPair result = driver.parse(ast); - Q_ASSERT(result.first); return result; } diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 3d6a057..1ad64ad 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -70,7 +70,7 @@ QPair Driver::parse( Python::CodeAst* ast ) AstBuilder pythonparser; QPair matched; matched.first = pythonparser.parse( m_currentDocument ); - matched.second = true; // TODO fix this + matched.second = matched.first ? true : false; // check wether an AST was returned and react accordingly if( matched.second ) { kDebug() << "Sucessfully parsed"; diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 56d320a..0484f5e 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -69,5 +69,9 @@ def generic_visit(self, node): f = open(sys.argv[1]).read() v = KDevelopNodeVisitor() -v.visit(ast.parse(f)) -print v.xmlrepr.toprettyxml(indent = " ") +try: + v.visit(ast.parse(f)) +except Exception as e: + sys.stderr.write(str(e.lineno) + ':' + str(e.offset)) +else: + sys.stdout.write(v.xmlrepr.toprettyxml(indent = " ")) From 83c1c3dbce4fd41042b1286a2d147ad721dce2bc Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 09:57:48 +0200 Subject: [PATCH 042/118] Fixed the python parser's PATH problem --- CMakeLists.txt | 2 ++ parser/astbuilder.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d777ec..c45a236 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ target_link_libraries(kdevpythonlanguagesupport kdev4pythonduchain ) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/parser/parserConfig.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/parser/parserConfig.h" ) + install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index dd9340d..81b422d 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -35,6 +35,8 @@ #include #include +#include "parserConfig.h" + namespace Python { @@ -49,7 +51,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST kDebug() << QDir::current(); - parser->start("/usr/bin/env", QStringList() << "python" << "pythonpythonparser.py" << filename.path()); + parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py") << filename.path()); parser->waitForFinished(); // TODO this is not clean From cae635c46c1bd2b99a9b21f42ecc2654385ad5f2 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 09:58:57 +0200 Subject: [PATCH 043/118] Added missing .h.in file --- parser/parserConfig.h.in | 1 + 1 file changed, 1 insertion(+) create mode 100644 parser/parserConfig.h.in diff --git a/parser/parserConfig.h.in b/parser/parserConfig.h.in new file mode 100644 index 0000000..783dac2 --- /dev/null +++ b/parser/parserConfig.h.in @@ -0,0 +1 @@ +#define INSTALL_PATH "@BIN_INSTALL_DIR@" \ No newline at end of file From 7dc516aea1b616fc917db77ce68c6f987864bb5a Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 11:07:46 +0200 Subject: [PATCH 044/118] Added argument definitions (untested), UseBuilder fixes --- duchain/contextbuilder.cpp | 26 +++---------- duchain/contextbuilder.h | 1 + duchain/declarationbuilder.cpp | 47 ++++++++++++++++++++--- duchain/declarationbuilder.h | 6 +-- duchain/usebuilder.cpp | 70 +++++++++++++++++----------------- duchain/usebuilder.h | 2 +- parser/astbuilder.cpp | 5 ++- 7 files changed, 89 insertions(+), 68 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index b1ed3f0..aa37d52 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -135,32 +135,18 @@ void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) closeContext(); } +void ContextBuilder::visitArguments(ArgumentsAst* node) +{ + +} + void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << "building function definition context"; kDebug() << node->startLine; ClassDefinitionAst* classast = dynamic_cast( node->parent ); - if ( classast ) - { -// DUChainReadLocker lock( DUChain::lock() ); -// QList classContexts = currentContext()->findContexts( DUContext::Class, QualifiedIdentifier( classast->context->localScopeIdentifier(). ) ); - -// if ( classContexts.count() != 1 ) -// { -// m_importedParentContexts.append( classContexts.first() ); - m_importedParentContexts.append( currentContext() ); -// } - -// if ( classContexts.count() > 1 ) -// { -// kWarning() << "Multiple class contexts for" << classast->className->identifier << classast->context->localScopeIdentifier() << "shouldn't happen!"; -// foreach( DUContext* classContext, classContexts ) -// { -// kDebug() << "Context" << classContext->scopeIdentifier( true ) << "range" << classContext->range().textRange() << "in" << classContext->url().str(); -// } -// } - } + if ( classast ) m_importedParentContexts.append( currentContext() ); visitNodeList( node->decorators ); diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 07eca2e..e50fbe8 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -65,6 +65,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitWith( WithAst* node ); virtual void visitWhile( WhileAst* node ); virtual void visitIf( IfAst* node ); + virtual void visitArguments(ArgumentsAst* node); static PythonEditorIntegrator* m_editor; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index a77424f..62f1078 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -81,19 +81,38 @@ void DeclarationBuilder::closeDeclaration() DeclarationBuilderBase::closeDeclaration(); } -void DeclarationBuilder::visitVariableDeclaration(Ast* node) +Declaration* DeclarationBuilder::visitVariableDeclaration(Ast* node) { NameAst* currentVariableDefinition = dynamic_cast(node); kDebug() << node->astType; Q_ASSERT(currentVariableDefinition); - openDeclaration(currentVariableDefinition->identifier, currentVariableDefinition); - closeDeclaration(); + if ( currentVariableDefinition->context != ExpressionAst::Store + && currentVariableDefinition->context != ExpressionAst::Parameter) { + return 0; + } + Identifier* id = currentVariableDefinition->identifier; + return visitVariableDeclaration(id, currentVariableDefinition); } -void DeclarationBuilder::visitVariableDeclaration(Identifier* node) +Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* originalAst) { - openDeclaration(node, node); - closeDeclaration(); + DUChainWriteLocker lock(DUChain::lock()); + + QList existingDeclarations; + CursorInRevision until = editorFindRange(node, node).end; + + existingDeclarations = currentContext()->findDeclarations(identifierForNode(node), until); + + Declaration* dec = 0; + + if ( ! existingDeclarations.length() ) { + kDebug() << "Creating variable definition for " << node->value << node->startLine << ":" << node->startCol; + dec = openDeclaration(node, originalAst ? originalAst : node); + closeDeclaration(); + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); + } + else kDebug() << "Not updating existing declaration for " << node->value; + return dec; } void DeclarationBuilder::visitFor(ForAst* node) @@ -196,6 +215,22 @@ void DeclarationBuilder::visitLambda( LambdaAst* node ) void DeclarationBuilder::visitArguments( ArgumentsAst* node ) { AstDefaultVisitor::visitArguments(node); + + AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); + if ( function ) { + NameAst* realParam; + foreach (ExpressionAst* expression, node->arguments) { + visitNode(expression); + realParam = dynamic_cast(expression); + if ( realParam && realParam->context == ExpressionAst::Parameter ) { + Declaration* paramDeclaration = visitVariableDeclaration(realParam); + function->addDefaultParameter(IndexedString(realParam->identifier->value)); + FunctionType::Ptr type = currentType(); + if ( type && paramDeclaration ) type->addArgument(paramDeclaration->abstractType()); + } + } + } + // ContextBuilder::visitDefaultParameter( node ); // // AbstractFunctionDeclaration* function = currentDeclaration(); // AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 1d26aa9..acecb49 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -47,15 +47,15 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitClassDefinition( ClassDefinitionAst* node ); virtual void visitFunctionDefinition( FunctionDefinitionAst* node ); - virtual void visitArguments( ArgumentsAst* node ); virtual void visitLambda( LambdaAst* node ); virtual void visitAssignment(AssignmentAst* node); virtual void visitFor(ForAst* node); virtual void visitImport(ImportAst* node); virtual void visitImportFrom(ImportFromAst* node); + virtual void visitArguments(ArgumentsAst* node); - void visitVariableDeclaration(Ast* node); - void visitVariableDeclaration(Identifier* node); + Declaration* visitVariableDeclaration(Ast* node); + Declaration* visitVariableDeclaration(Identifier* node, Ast* originalAst = 0); // virtual void visitIdentifierTarget( IdentifierTargetAst * node ); diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index a154d13..5f4329f 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -54,45 +54,43 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) : m_editor(editor) void UseBuilder::visitName(NameAst* node) { DUChainWriteLocker lock(DUChain::lock()); - QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).start); - if ( ! declarations.length() ) return; - Declaration* dec = declarations.last(); - if ( node->context == ExpressionAst::Load ) { - UseBuilderBase::newUse(node, dec); + QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); + if ( declarations.length() ) { + UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), declarations.last()); // +1 for whatever reason } } -void UseBuilder::visitIdentifier(Identifier* node) -{ - DUChainWriteLocker lock( DUChain::lock() ); - QualifiedIdentifier id = identifierForNode(node); - RangeInRevision range = editorFindRange(node, node); - CursorInRevision until = range.start; - QList allDeclarations = currentContext()->findDeclarations(id, until); - - kDebug() << " >> scanning " << node->value; - kDebug() << " > searching for declaration until" << until.line << ":" << until.column << "; " << allDeclarations.length() << "Declarations found"; - - Declaration *globalDeclaration = 0; - foreach ( Declaration* dec, allDeclarations ) { - if ( dec->context() == dec->topContext() ) { - kDebug() << "There's already a global declaration for" << node->value; - globalDeclaration = dec; - } - } - - // if there's a local declaration, use the last one of those - if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { - kDebug() << " ++ Created a use of local declaration for node" << node->value; - UseBuilderBase::newUse(node, allDeclarations.last()); - } - // otherwise, use the global one. - // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 - else if ( globalDeclaration ) { - kDebug() << " ++ Created a use of global declaration for node" << node->value; - UseBuilderBase::newUse(node, globalDeclaration); - } -} +// void UseBuilder::visitIdentifier(Identifier* node) +// { +// DUChainWriteLocker lock( DUChain::lock() ); +// QualifiedIdentifier id = identifierForNode(node); +// RangeInRevision range = editorFindRange(node, node); +// CursorInRevision until = range.start; +// QList allDeclarations = currentContext()->findDeclarations(id, until); +// +// kDebug() << " >> scanning " << node->value; +// kDebug() << " > searching for declaration until" << until.line << ":" << until.column << "; " << allDeclarations.length() << "Declarations found"; +// +// Declaration *globalDeclaration = 0; +// foreach ( Declaration* dec, allDeclarations ) { +// if ( dec->context() == dec->topContext() ) { +// kDebug() << "There's already a global declaration for" << node->value; +// globalDeclaration = dec; +// } +// } +// +// // if there's a local declaration, use the last one of those +// if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { +// kDebug() << " ++ Created a use of local declaration for node" << node->value; +// UseBuilderBase::newUse(node, allDeclarations.last()); +// } +// // otherwise, use the global one. +// // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 +// else if ( globalDeclaration ) { +// kDebug() << " ++ Created a use of global declaration for node" << node->value; +// UseBuilderBase::newUse(node, globalDeclaration); +// } +// } // void UseBuilder::visitIdentifierTarget(IdentifierTargetAst* node) // { diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 915945e..1109ccc 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -47,7 +47,7 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase virtual void openContext(KDevelop::DUContext* newContext); virtual void closeContext(); - virtual void visitIdentifier(Identifier* node); +// virtual void visitIdentifier(Identifier* node); virtual void visitName(NameAst* node); private: ParseSession* m_session; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 81b422d..034e05d 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -224,6 +224,7 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea else if ( name == "storeast") m_contextNodeMap.insert(node_id, ExpressionAst::Store); else if ( name == "deleteast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Delete); else if ( name == "augassignast" ) m_contextNodeMap.insert(node_id, ExpressionAst::AugStore); + else if ( name == "paramast" ) m_contextNodeMap.insert(node_id, ExpressionAst::Parameter); else if ( name == "addast" ) m_opNodeMap.insert(node_id, Ast::OperatorAdd); else if ( name == "subast" ) m_opNodeMap.insert(node_id, Ast::OperatorSub); @@ -724,9 +725,9 @@ void AstBuilder::populateAst() currentAbstractNode->endLine = startLine; int startCol = currentAttributes.value("col_offset").toInt(); currentAbstractNode->startCol = startCol; - currentAbstractNode->endCol = startCol + 100; // TODO fix this ;p + currentAbstractNode->endCol = startCol; // this is justified if necessary (only an AST with an actual value or identifier will know the true range) - if ( ! currentAbstractNode->startLine && currentAbstractNode->parent ) { + if ( ! currentAttributes.value("lineno").length() && currentAbstractNode->parent ) { currentAbstractNode->startLine = currentAbstractNode->parent->startLine; currentAbstractNode->endLine = currentAbstractNode->parent->endLine; currentAbstractNode->startCol = currentAbstractNode->parent->startCol; From 1c508a1e89dfc240773f4b46359ee0f00150faea Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 13:09:27 +0200 Subject: [PATCH 045/118] Fixed of highlighting & crash bugs, removed debug output --- duchain/contextbuilder.cpp | 9 ++---- duchain/declarationbuilder.cpp | 9 +++++- duchain/pythoneditorintegrator.cpp | 1 + parser/astbuilder.cpp | 50 ++++++++++++++++++++---------- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index aa37d52..f7fd89c 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -137,7 +137,7 @@ void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) void ContextBuilder::visitArguments(ArgumentsAst* node) { - + AstDefaultVisitor::visitArguments(node); } void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) @@ -213,11 +213,8 @@ void ContextBuilder::visitIf( IfAst* node ) visitNode( node->condition ); openContextForStatementList( node->body ); - QList ::const_iterator it, end = node->body.constEnd(); - - for ( it = node->body.begin(); it != end; ++it ) - { - visitNode(*it); + foreach ( StatementAst* current, node->body) { + visitNode(current); } openContextForStatementList( node->orelse ); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 62f1078..10fb36e 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -118,7 +118,12 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* void DeclarationBuilder::visitFor(ForAst* node) { Python::ContextBuilder::visitFor(node); - visitVariableDeclaration(node->target); + if ( node->target->astType == Ast::NameAstType ) visitVariableDeclaration(node->target); + else if ( node->target->astType == Ast::TupleAstType ) { + foreach ( ExpressionAst* tupleMember, dynamic_cast(node->target)->elements ) { + if ( tupleMember->astType == Ast::NameAstType ) visitVariableDeclaration(tupleMember); + } + } } void DeclarationBuilder::visitImport(ImportAst* node) @@ -189,6 +194,8 @@ void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << "opening function definition"; + int decoratorOffset = node->decorators.length(); // adjust the actual range of the functions' name + node->name->startLine += decoratorOffset; node->name->endLine += decoratorOffset; FunctionDeclaration* dec = openDeclaration( node->name, node ); FunctionType::Ptr type(new FunctionType); diff --git a/duchain/pythoneditorintegrator.cpp b/duchain/pythoneditorintegrator.cpp index 68fc415..ae35f58 100644 --- a/duchain/pythoneditorintegrator.cpp +++ b/duchain/pythoneditorintegrator.cpp @@ -56,6 +56,7 @@ void PythonEditorIntegrator::setParseSession(ParseSession* session) CursorInRevision PythonEditorIntegrator::findPosition( Ast* node , Edge edge ) const { + Q_ASSERT(node); if ( edge == BackEdge ) { // Apparently KTE expects a range to go until _after_ the last character that should be included diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 034e05d..478859a 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -50,7 +50,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) { QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST - kDebug() << QDir::current(); +// kDebug() << QDir::current(); parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py") << filename.path()); parser->waitForFinished(); @@ -61,7 +61,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) } QString result = parser->readAllStandardOutput(); - kDebug() << "XML for " << filename << ":" << result; + kDebug() << "XML for " << filename << ": length" << result.length(); if ( ! result.length() ) { result = parser->readAllStandardError(); @@ -127,10 +127,10 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok continue; } - kDebug() << "Token: " << token << "; " << "Name: " << currentElementName << "; Text: " << currentElementText; - for ( int i=0; i attributeDict; for ( int i=0; i T* AstBuilder::resolveNode(const QString& identifier) { int id = identifier.toInt(); if ( ! id ) return 0; - return dynamic_cast(m_nodeMap.value(id)); + Ast* found = m_nodeMap.value(id); + T* ret = dynamic_cast(found); + Q_ASSERT(found || ! ret); + return found ? ret : 0; } template QList AstBuilder::resolveNodeList(const QString& commaSeperatedIdentifiers) { QList items; QStringList identifiers = commaSeperatedIdentifiers.split(","); + T* found; for ( int i=0; i(identifiers.at(i)); + // make sure we have no null pointers in our lists + found = 0; + if ( identifiers.at(i).length() ) found = resolveNode(identifiers.at(i)); + if ( found ) items << found; } return items; } @@ -343,12 +350,21 @@ QList< Ast::ComparisonOperatorTypes > AstBuilder::resolveComparisonOperatorList( return items; } +ExecAst* AstBuilder::populateExecAst(Ast* ast, const Python::stringDictionary& currentAttributes) +{ + ExecAst* currentNode = dynamic_cast(ast); + currentNode->body = resolveNode(currentAttributes.value("NR_body")); + currentNode->locals = resolveNode(currentAttributes.value("NR_locals")); + currentNode->globals = resolveNode(currentAttributes.value("NR_globals")); + return currentNode; +} + NameAst* AstBuilder::populateNameAst(Ast* ast, const Python::stringDictionary& currentAttributes) { NameAst* currentNode = dynamic_cast(ast); currentNode->context = resolveContext(currentAttributes.value("NR_ctx")); currentNode->identifier = createIdentifier(currentAttributes.value("id"), currentNode); - kDebug() << "Processing NameAst" << currentNode->identifier->value; +// kDebug() << "Processing NameAst" << currentNode->identifier->value; return currentNode; } @@ -711,14 +727,14 @@ void AstBuilder::populateAst() currentAbstractNode = i.value(); currentAttributes = m_attributeStore.value(i.key()); - kDebug() << "Processing AST node ID " << i.key(); - kDebug() << "Amount of attributes: " << currentAttributes.size(); +// kDebug() << "Processing AST node ID " << i.key(); +// kDebug() << "Amount of attributes: " << currentAttributes.size(); stringDictionary::const_iterator i = currentAttributes.begin(); - while ( i != currentAttributes.end() ) { - kDebug() << i.key() << i.value(); - ++i; - } +// while ( i != currentAttributes.end() ) { +// kDebug() << i.key() << i.value(); +// ++i; +// } int startLine = currentAttributes.value("lineno").toInt() - 1; // start = 0 <> start = 1 currentAbstractNode->startLine = startLine; From e417fa4fc1e1fc716ae696789a96c331ed066dc1 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 24 Oct 2010 19:52:09 +0200 Subject: [PATCH 046/118] Functionality of old parser is now restored. --- duchain/contextbuilder.cpp | 15 +++++---------- duchain/declarationbuilder.cpp | 7 ++++--- duchain/usebuilder.cpp | 12 +++++++++--- parser/ast.h | 2 ++ parser/astbuilder.cpp | 17 ++++++++--------- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index f7fd89c..380df32 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -105,7 +105,6 @@ void ContextBuilder::addImportedContexts() { if ( compilingContexts() && !m_importedParentContexts.isEmpty() ) { - kDebug() << "Adding Imported Contexts"; DUChainWriteLocker lock( DUChain::lock() ); foreach( DUContext* imported, m_importedParentContexts ) currentContext()->addImportedParentContext( imported ); @@ -118,7 +117,10 @@ void ContextBuilder::openContextForStatementList( const QList& l { if ( l.count() > 0 ) { - openContext( l.first(), l.last(), DUContext::Other ); + Ast* first = l.first(); + Ast* last = l.last(); + openContext(first, RangeInRevision(first->startLine - 1, first->startCol, last->endLine + 1, 10000), DUContext::Other ); + kDebug() << " +++ opening context: " << first->startLine - 1 << ":" << first->startCol << " -- " << last->endLine + 1 << "inf"; addImportedContexts(); visitNodeList( l ); closeContext(); @@ -127,7 +129,6 @@ void ContextBuilder::openContextForStatementList( const QList& l void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { - kDebug() << "Visiting Class Declaration"; openContext( node, DUContext::Class, identifierForNode( node->name ) ); addImportedContexts(); visitNodeList( node->baseClasses ); @@ -142,8 +143,7 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { - kDebug() << "building function definition context"; - kDebug() << node->startLine; + kDebug() << " Building function definition context: " << node->name; ClassDefinitionAst* classast = dynamic_cast( node->parent ); if ( classast ) m_importedParentContexts.append( currentContext() ); @@ -165,7 +165,6 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) void ContextBuilder::visitFor( ForAst* node ) { - kDebug() << "Found for, building context"; DUContext* forctx = openContext( node, KDevelop::DUContext::Other ); visitNode(node->target); closeContext(); @@ -180,7 +179,6 @@ void ContextBuilder::visitFor( ForAst* node ) void ContextBuilder::visitWhile( WhileAst* node ) { - kDebug() << "Creating contexts for while"; visitNode( node->condition ); openContextForStatementList( node->body ); openContextForStatementList( node->orelse ); @@ -188,8 +186,6 @@ void ContextBuilder::visitWhile( WhileAst* node ) void ContextBuilder::visitWith( WithAst * node ) { - kDebug() << "creating contexts for With"; - m_importedParentContexts = QList() << openContext( node->contextExpression, DUContext::Other ); visitNode( node->contextExpression ); closeContext(); @@ -209,7 +205,6 @@ void ContextBuilder::visitWith( WithAst * node ) void ContextBuilder::visitIf( IfAst* node ) { - kDebug() << "creating contexts for if"; visitNode( node->condition ); openContextForStatementList( node->body ); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 10fb36e..7094abb 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -84,10 +84,11 @@ void DeclarationBuilder::closeDeclaration() Declaration* DeclarationBuilder::visitVariableDeclaration(Ast* node) { NameAst* currentVariableDefinition = dynamic_cast(node); - kDebug() << node->astType; Q_ASSERT(currentVariableDefinition); if ( currentVariableDefinition->context != ExpressionAst::Store - && currentVariableDefinition->context != ExpressionAst::Parameter) { + && currentVariableDefinition->context != ExpressionAst::Parameter + && currentVariableDefinition->context != ExpressionAst::AugStore + ) { return 0; } Identifier* id = currentVariableDefinition->identifier; @@ -106,7 +107,7 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* Declaration* dec = 0; if ( ! existingDeclarations.length() ) { - kDebug() << "Creating variable definition for " << node->value << node->startLine << ":" << node->startCol; + kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; dec = openDeclaration(node, originalAst ? originalAst : node); closeDeclaration(); dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 5f4329f..0e18ea0 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -54,10 +54,16 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) : m_editor(editor) void UseBuilder::visitName(NameAst* node) { DUChainWriteLocker lock(DUChain::lock()); + DUContext* current = currentContext(); QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); - if ( declarations.length() ) { - UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), declarations.last()); // +1 for whatever reason - } + Declaration* declaration; + if ( declarations.length() ) declaration = declarations.last(); + else declaration = 0; + + Q_ASSERT(node->identifier); + Q_ASSERT(node->hasUsefulRangeInformation); // TODO remove this! + kDebug() << " Registeriung use for " << node->identifier->value << " at " << node->identifier->startLine << ":" << node->identifier->endCol << "->" << node->identifier->endLine << ":" << node->identifier->endCol + 1 << "with dec" << declaration; + UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), declaration); // +1 for whatever reason } // void UseBuilder::visitIdentifier(Identifier* node) diff --git a/parser/ast.h b/parser/ast.h index 54879dc..0bd780b 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -185,6 +185,8 @@ class KDEVPYTHONPARSER_EXPORT Ast qint64 endCol; qint64 endLine; + bool hasUsefulRangeInformation; + KDevelop::DUContext* context; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 478859a..414d645 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -51,8 +51,10 @@ QString AstBuilder::getXmlForFile(KUrl filename) QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST // kDebug() << QDir::current(); + kDebug() << "+++ Starting parser for file " << filename.path(); parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py") << filename.path()); parser->waitForFinished(); + kDebug() << " ** Reading results..."; // TODO this is not clean if ( parser->exitStatus() != QProcess::NormalExit ) { @@ -61,7 +63,7 @@ QString AstBuilder::getXmlForFile(KUrl filename) } QString result = parser->readAllStandardOutput(); - kDebug() << "XML for " << filename << ": length" << result.length(); + kDebug() << " ** XML for " << filename << ": length" << result.length(); if ( ! result.length() ) { result = parser->readAllStandardError(); @@ -273,8 +275,8 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea template T* AstBuilder::resolveNode(const QString& identifier) { + if ( ! identifier.length() ) return 0; int id = identifier.toInt(); - if ( ! id ) return 0; Ast* found = m_nodeMap.value(id); T* ret = dynamic_cast(found); Q_ASSERT(found || ! ret); @@ -284,6 +286,7 @@ template T* AstBuilder::resolveNode(const QString& identifier) template QList AstBuilder::resolveNodeList(const QString& commaSeperatedIdentifiers) { QList items; + items.clear(); QStringList identifiers = commaSeperatedIdentifiers.split(","); T* found; for ( int i=0; i 0 && currentAttributes.value("col_offset").length() > 0 ) + currentAbstractNode->hasUsefulRangeInformation = true; + else currentAbstractNode->hasUsefulRangeInformation = false; int startLine = currentAttributes.value("lineno").toInt() - 1; // start = 0 <> start = 1 currentAbstractNode->startLine = startLine; @@ -743,13 +749,6 @@ void AstBuilder::populateAst() currentAbstractNode->startCol = startCol; currentAbstractNode->endCol = startCol; // this is justified if necessary (only an AST with an actual value or identifier will know the true range) - if ( ! currentAttributes.value("lineno").length() && currentAbstractNode->parent ) { - currentAbstractNode->startLine = currentAbstractNode->parent->startLine; - currentAbstractNode->endLine = currentAbstractNode->parent->endLine; - currentAbstractNode->startCol = currentAbstractNode->parent->startCol; - currentAbstractNode->endCol = currentAbstractNode->parent->endCol; - } - switch ( currentAbstractNode->astType ) { case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break; case Ast::FunctionDefinitionAstType: currentAbstractNode = populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break; From 0500a17d2377216903bb8dbac0d20df4e4b9f53d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 25 Oct 2010 20:59:34 +0200 Subject: [PATCH 047/118] Parser now reads stuff from stdin instead of filesystem --- parser/astbuilder.cpp | 15 +++++++++++---- parser/astbuilder.h | 4 ++-- parser/parsesession.cpp | 1 + parser/pythondriver.cpp | 2 +- pythonpythonparser.py | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 414d645..09e89fd 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -40,19 +40,26 @@ namespace Python { -CodeAst* AstBuilder::parse(KUrl filename) +CodeAst* AstBuilder::parse(KUrl filename, const QString& contents) { - CodeAst* ast = parseXmlAst(getXmlForFile(filename)); + CodeAst* ast = parseXmlAst(getXmlForFile(filename, contents)); return ast; } -QString AstBuilder::getXmlForFile(KUrl filename) +QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) { QProcess* parser = new QProcess(); // we call a python script to parse the code for us. It returns an XML string with the AST // kDebug() << QDir::current(); kDebug() << "+++ Starting parser for file " << filename.path(); - parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py") << filename.path()); + parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py")); + qint64 length = contents.length(); + qint64 written = parser->write(contents.toAscii().data(), length); + kDebug() << "Content length: " << length << ", Bytes written: " << written; + parser->closeWriteChannel(); + if ( written != length ) { + Q_ASSERT(false); + } parser->waitForFinished(); kDebug() << " ** Reading results..."; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 1763483..0f689ed 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -46,10 +46,10 @@ class AstBuilder { public: - CodeAst* parse(KUrl filename); + CodeAst* parse(KUrl filename, const QString& contents); private: CodeAst* parseXmlAst(QString xml); - QString getXmlForFile(KUrl filename); + QString getXmlForFile(KUrl filename, const QString& contents); void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); bool parseAstNode(QString name, QString text, const QList& attributes); diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index 4d4cdf3..d8d5aa5 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -65,6 +65,7 @@ QPair ParseSession::parse( Python::CodeAst* ast ) { Driver driver; driver.setCurrentDocument(m_currentDocument.toUrl()); + driver.setContent(m_contents); QPair result = driver.parse(ast); return result; } diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 1ad64ad..e3056a8 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -69,7 +69,7 @@ QPair Driver::parse( Python::CodeAst* ast ) { AstBuilder pythonparser; QPair matched; - matched.first = pythonparser.parse( m_currentDocument ); + matched.first = pythonparser.parse(m_currentDocument, m_content); matched.second = matched.first ? true : false; // check wether an AST was returned and react accordingly if( matched.second ) { diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 0484f5e..4dc11d8 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -67,7 +67,7 @@ def generic_visit(self, node): self.currentnode = save_currentnode -f = open(sys.argv[1]).read() +f = sys.stdin.read() v = KDevelopNodeVisitor() try: v.visit(ast.parse(f)) From c406271f980be94d0b2724580b2acb8063a140d4 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 25 Oct 2010 21:42:33 +0200 Subject: [PATCH 048/118] Trying to add a parse problem to --- parser/astbuilder.cpp | 17 ++++++++++++++++- parser/astbuilder.h | 3 +++ parser/pythondriver.cpp | 7 +++++++ pythonparsejob.cpp | 20 +++++++++++++------- pythonparsejob.h | 7 +++---- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 09e89fd..0c2f24f 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -34,14 +34,23 @@ #include #include #include +#include #include "parserConfig.h" +#include + +using namespace KDevelop; namespace Python { CodeAst* AstBuilder::parse(KUrl filename, const QString& contents) { + { + DUChainWriteLocker lock(DUChain::lock()); + m_topContext = DUChain::self()->chainForDocument(filename); + Q_ASSERT(m_topContext); + } CodeAst* ast = parseXmlAst(getXmlForFile(filename, contents)); return ast; } @@ -66,7 +75,7 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) // TODO this is not clean if ( parser->exitStatus() != QProcess::NormalExit ) { kError() << "Error parsing file: " << parser->errorString(); - return ""; + return "0"; } QString result = parser->readAllStandardOutput(); @@ -81,6 +90,12 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno, lineno, colno + 1))); p->setSource(KDevelop::ProblemData::Disk); p->setDescription(result); + { + DUChainWriteLocker lock(DUChain::lock()); + m_topContext->addProblem(p); + DUChain::self()->updateContextForUrl(IndexedString(filename), m_topContext->features()); + kDebug() << m_topContext->problems(); + } kWarning() << "Parse Error: " << result; return "0"; } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 0f689ed..dc682e8 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -28,6 +28,7 @@ #include #include "kdebug.h" #include "QXmlStreamReader" +#include namespace PythonParser { @@ -53,6 +54,8 @@ class AstBuilder void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); bool parseAstNode(QString name, QString text, const QList& attributes); + KDevelop::TopDUContext* m_topContext; + QList m_nodeStack; // one map for regular ast nodes, and the others for primitive nodes of different types diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index e3056a8..ef98020 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -29,6 +29,12 @@ #include "astbuilder.h" +#include +#include + + +using namespace KDevelop; + namespace Python { @@ -71,6 +77,7 @@ QPair Driver::parse( Python::CodeAst* ast ) QPair matched; matched.first = pythonparser.parse(m_currentDocument, m_content); matched.second = matched.first ? true : false; // check wether an AST was returned and react accordingly + if( matched.second ) { kDebug() << "Sucessfully parsed"; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 66793ef..e08d41e 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -111,12 +111,20 @@ void ParseJob::run() m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); m_session->setCurrentDocument(m_url); - IndexedString test(m_url); - kDebug() << m_url.toLocalFile(); - if ( abortRequested() ) return abortJob(); - + + IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); + + { + DUChainWriteLocker lock(DUChain::lock()); + ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); + IndexedString langstring("python"); + file->setLanguage(langstring); + m_top = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); + DUChain::self()->addDocumentChain(m_top); + } + // 2) parse QPair parserResults = m_session->parse(m_ast); m_ast = parserResults.first; @@ -134,8 +142,6 @@ void ParseJob::run() PythonEditorIntegrator editor; DeclarationBuilder builder( &editor ); - IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); - editor.setParseSession(m_session); m_duContext = builder.build(filename, m_ast); @@ -167,7 +173,7 @@ void ParseJob::run() { kWarning() << "===Failed==="; // cleanupSmartRevision(); - return; + return abortJob(); } // cleanupSmartRevision(); } diff --git a/pythonparsejob.h b/pythonparsejob.h index dbbe9ce..180d3f0 100644 --- a/pythonparsejob.h +++ b/pythonparsejob.h @@ -33,13 +33,11 @@ #include #include +#include -namespace KDevelop -{ -class TopDUContext; -} +using namespace KDevelop; namespace Python { @@ -66,6 +64,7 @@ class ParseJob : public KDevelop::ParseJob bool wasReadFromDisk() const; const LanguageSupport* m_parent; + TopDUContext* m_top; protected: virtual void run(); From 28a162e18dc9b92aa88194814d7c6c09fc461d3b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 26 Oct 2010 18:08:29 +0200 Subject: [PATCH 049/118] Parse errors are reported, but not highlighted yet --- parser/astbuilder.cpp | 12 ++++++++---- pythonparsejob.cpp | 7 ++++--- pythonparsejob.h | 1 - 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 0c2f24f..6c3539d 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -83,13 +83,17 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) if ( ! result.length() ) { result = parser->readAllStandardError(); - result.split(":"); - int lineno = result[0].toAscii(); - int colno = result[1].toAscii(); + QStringList position = result.split(":"); + qint64 lineno = position.at(0).toInt() - 1; + qint64 colno = position.at(0).toInt() - 1; + + kDebug() << lineno << colno; + KDevelop::ProblemPointer p(new KDevelop::Problem()); - p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno, lineno, colno + 1))); + p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno - 1, lineno, colno + 1))); p->setSource(KDevelop::ProblemData::Disk); p->setDescription(result); + p->setSeverity(KDevelop::ProblemData::Error); { DUChainWriteLocker lock(DUChain::lock()); m_topContext->addProblem(p); diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index e08d41e..5fdf256 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -121,8 +121,9 @@ void ParseJob::run() ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); IndexedString langstring("python"); file->setLanguage(langstring); - m_top = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); - DUChain::self()->addDocumentChain(m_top); + m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); + m_duContext->setType(KDevelop::DUContext::Global); + DUChain::self()->addDocumentChain(m_duContext); } // 2) parse @@ -144,7 +145,7 @@ void ParseJob::run() editor.setParseSession(m_session); - m_duContext = builder.build(filename, m_ast); + m_duContext = builder.build(filename, m_ast, m_duContext); setDuChain(m_duContext); UseBuilder usebuilder( &editor ); diff --git a/pythonparsejob.h b/pythonparsejob.h index 180d3f0..affeada 100644 --- a/pythonparsejob.h +++ b/pythonparsejob.h @@ -64,7 +64,6 @@ class ParseJob : public KDevelop::ParseJob bool wasReadFromDisk() const; const LanguageSupport* m_parent; - TopDUContext* m_top; protected: virtual void run(); From 5817009e728ce23413687d502182925ba773f8fd Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 30 Oct 2010 16:40:48 +0200 Subject: [PATCH 050/118] The python documentation generator does... something --- python_helpers/generate_docs.py | 152 ++++++++++++++++++++++++++++++++ pythonparsejob.cpp | 50 +++++------ 2 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 python_helpers/generate_docs.py diff --git a/python_helpers/generate_docs.py b/python_helpers/generate_docs.py new file mode 100644 index 0000000..b71f9a9 --- /dev/null +++ b/python_helpers/generate_docs.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +import pydoc + +modules = ['random'] +code = '' + +current_name = [] + +import types +import pydoc +import subprocess + +import re + +import os + +modules_done = [] + +import sys + +from PyQt4.QtCore import pyqtWrapperType + +def dbg(s): + sys.stderr.write(s) + sys.stderr.write("\n") + +def walk_directory(path): + modules_found = [] + for root, dirs, files in os.walk(path): + for current_file in files: + if not ( current_file.endswith('.so') or current_file.endswith('.py') ) or current_file.startswith('__init__'): + continue + module_path = root.replace(path, '').replace('/', '.') + '.' + current_file.replace('.so', '').replace('.py', '') + if module_path.startswith('.'): + module_path = module_path[1:] + modules_found.append(module_path) + dbg("Modules found: " + str(modules_found)) + return modules_found + +def indent(moar = 0): + ret = '' + for i in xrange(0, len(current_name) + moar - 1): + ret += " " + return ret + +def removeIndent(line): + m = re.search(r'^ *', line) + return line[:m.start()] + line[m.end():] + +validMethodTypes = [types.UnboundMethodType, types.FunctionType, types.BuiltinFunctionType] +validModuleTypes = [pyqtWrapperType, types.FunctionType] + +def process(obj): + try: + if obj.__name__.startswith('__'): + raise AttributeError + except: + dbg("Aborting, name starts with __") + return + + try: + current_name.append(obj.__name__) + except: + current_name.append('') + dbg(" ++ Process called with argument " + str(obj)) + + if type(obj) == types.ModuleType or type(obj) in validModuleTypes: + properties = dir(obj) + #print obj, properties, type(obj) + if not obj.__name__.startswith('_'): + print indent() + "class " + obj.__name__ + "(): pass" + + for current_property in properties: + current_property = getattr(obj, current_property) + if type(current_property) in validMethodTypes: + dbg(" >> Processing property: " + str(current_property)) + process(current_property) + if type(current_property) in validModuleTypes: + dbg(" MODULE: " + str(current_property)) + for item in dir(current_property): + if type(current_property) in validMethodTypes: + process(getattr(current_property, item)) + else: + pass + #dbg(" -- Skipped property of invalid type " + str(type(current_property))) + + if type(obj) in validMethodTypes: + dbg(" !! Generating documentation for " + str(obj)) + dbg('.'.join(current_name)) + documentation = subprocess.Popen(['/usr/bin/pydoc', '.'.join(current_name)], stdout = subprocess.PIPE).stdout.read() + lines = documentation.split("\n") + + split = lines[2].split("=") + try: + if split[1][:2] == ' _': + current_name.pop() + return + except: + pass + print indent() + "# Generated Documentation for ", ''.join(split[:1]) + if not '='.join(split[1:]): + dbg("Skipping invalid function") + current_name.pop() + return + lines[2] = "def" + '='.join(split[1:]) + + split = lines[2].split('method of') + lines[2] = 'method of'.join(split[:1]) + ":" + + documentation = "\n".join(lines[3:]) + + lines[2] = lines[2].replace('<', '"').replace('>', '"') + + print indent() + lines[2] + print indent(1) + '"""' + for line in lines[3:]: + print indent(1) + removeIndent(line) + print indent(1) + '"""' + print indent(1) + "pass \n\n" + + current_name.pop() + +root_path = '' +f = open('modules') +for module in walk_directory('/usr/lib/python2.6/'): + module = module.replace("\n", "") + module_parts = module.split('.') + try: + current_m = __import__(root_path + module) + except: + dbg("Could not import module " + module) + continue + #if len(module_parts) > 1: + #dbg(str(current_m)) + #for part in module_parts[1:]: + #dbg(root_path + '.'.join(module_parts)) + #__import__(root_path + '.'.join(module_parts)) + #current_m = getattr(current_m, part) + + get_attributes = module.split('.') + + for attrib in get_attributes: + try: + current_m = getattr(current_m, attrib) + dbg(" ##### " + str(root_path + module) + " > " + str(current_m) + " (" + str(attrib) + ")") + except AttributeError: + continue + + dbg(" >>> CALL :: " + module) + process(current_m) + dbg(" <<< RETURN") diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 5fdf256..6dd124e 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -135,39 +135,35 @@ void ParseJob::run() kDebug() << m_url; // AstPrinter printer; // printer.visitCode( m_ast ); - { - - if ( abortRequested() ) - return abortJob(); - - PythonEditorIntegrator editor; - DeclarationBuilder builder( &editor ); - - editor.setParseSession(m_session); - - m_duContext = builder.build(filename, m_ast, m_duContext); - setDuChain(m_duContext); - - UseBuilder usebuilder( &editor ); - usebuilder.buildUses(m_ast); - - kDebug() << "----Parsing Succeded---***"; - + if ( abortRequested() ) + return abortJob(); + + PythonEditorIntegrator editor; + DeclarationBuilder builder( &editor ); + + editor.setParseSession(m_session); + + m_duContext = builder.build(filename, m_ast, m_duContext); + setDuChain(m_duContext); + + UseBuilder usebuilder( &editor ); + usebuilder.buildUses(m_ast); + + kDebug() << "----Parsing Succeded---***"; + // { // DUChainReadLocker lock( DUChain::lock() ); // DumpChain dump; // dump.dump( m_duContext ); // } - - { - if ( m_parent && m_parent->codeHighlighting() ) { - kDebug() << m_duContext.data(); - DUChainReadLocker lock(DUChain::lock()); - KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); - hl->highlightDUChain(m_duContext); - } + + { + if ( m_parent && m_parent->codeHighlighting() ) { + kDebug() << m_duContext.data(); + DUChainReadLocker lock(DUChain::lock()); + KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); + hl->highlightDUChain(m_duContext); } - } } else From 82c9b4cc5d83ebcb568692338f1e86d35d7176e2 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 31 Oct 2010 12:27:05 +0100 Subject: [PATCH 051/118] New DocumentationGenerator (not working yet) --- python_helpers/documentationgenerator.py | 160 +++++++++++++++++++++++ python_helpers/generate_docs.py | 46 ++++--- pythonparsejob.cpp | 2 + 3 files changed, 190 insertions(+), 18 deletions(-) create mode 100644 python_helpers/documentationgenerator.py diff --git a/python_helpers/documentationgenerator.py b/python_helpers/documentationgenerator.py new file mode 100644 index 0000000..cdd7a92 --- /dev/null +++ b/python_helpers/documentationgenerator.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# -*- Coding: utf-8 -*- + +import types +from PyQt4.QtCore import pyqtWrapperType + +import subprocess + +import os, sys + +import re + +def dbg(*args): + for arg in args: + sys.stdout.write(str(arg) + ' ') + sys.stdout.write('\n') + +def removeIndent(line): + m = re.search(r'^ *', line) + return line[:m.start()] + line[m.end():] + +class DocumentationGenerator(): + validMethodTypes = [types.UnboundMethodType, types.FunctionType, types.BuiltinFunctionType] + validModuleTypes = [pyqtWrapperType, types.FunctionType, types.ModuleType, types.ClassType] + + current_file = None + open_files = dict() + + exclude_packages = ['_sane', 'sane', 'this', 'Pyrex.Plex.test_tm'] + + def walk_directory(self, path): + modules_found = [] + for root, dirs, files in os.walk(path): + for current_file in files: + if not ( current_file.endswith('.so') or current_file.endswith('.py') ) or current_file.startswith('__init__'): + continue + module_path = root.replace(path, '').replace('/', '.') + '.' + current_file.replace('.so', '').replace('.py', '') + module_path = module_path.replace('site-packages.', '') + + if module_path.startswith('.'): + module_path = module_path[1:] + + if module_path in self.exclude_packages or module_path.find('test') != -1: + continue + + modules_found.append(module_path) + dbg("Modules found: " + str(modules_found)) + return modules_found + + def run(self, basepath): + for module_name in self.walk_directory(basepath): + try: + current_m = __import__(module_name) + except: + dbg("Could not import module " + module_name) + continue + self.walk_module(current_m, module_name) + + def walk_module(self, module, module_name): + dbg("CHECKMODULE> ", module_name, module, type(module)) + if type(module) in self.validModuleTypes: + properties = dir(module) + for current_property_name in properties: + if current_property_name.startswith('_'): + continue + + current_property = getattr(module, current_property_name) + current_type = type(current_property) + dbg("CHECK> ", module_name, module, current_property, current_type) + if current_type in self.validModuleTypes: + self.walk_module(current_property, module_name + '.' + current_property_name) + if current_type in self.validMethodTypes: + self.generate_documentation_for(module_name + '.' + current_property_name) + self.generate_documentation_for(module_name) + + def write_docfile(self, *args): + for item in args: + self.current_file.write(str(item)) + self.current_file.write('\n') + + def get_docfile(self, module_name): + pathspec = module_name.split('.') + relative_path = 'results/' + '/'.join(pathspec) + '.py' + dbg("PATH> ", relative_path, " (from ", module_name, ")") + try: + self.current_file = self.open_files[relative_path] + return self.current_file + except KeyError: + pass + try: + self.current_file = open(relative_path, 'w') + self.open_files[relative_path] = self.current_file + return self.current_file + except IOError: + pass + try: + path = 'results/' + for part in pathspec: + path += part + '/' + if not os.path.exists(path): + dbg("CREATE> ", path) + os.mkdir(path) + dbg("CREATE> ", relative_path) + self.current_file = open(relative_path, 'w') + self.open_files[relative_path] = self.current_file + return self.current_file + except IOError: + raise IOError('Could not create valid docfile') + + def close_files(self): + for key, f in self.open_files.iteritems(): + f.close() + + def indent(self, moar = 0): + ret = '' + for i in xrange(0, moar): + ret += " " + return ret + + def generate_documentation_for(self, module_name): + dbg("PYDOC> ", module_name) + documentation = subprocess.Popen(['/usr/bin/pydoc', module_name], stdout = subprocess.PIPE).stdout.read() + lines = documentation.split("\n") + + docfile = self.get_docfile(module_name) + + split = lines[2].split("=") + try: + if split[1][:2] == ' _': + return + except: + pass + self.write_docfile(self.indent() + "# Generated Documentation for ", ''.join(split[:1])) + if not '='.join(split[1:]): + dbg("SKIP> Skipping invalid function") + dbg("SKIP> Error was", documentation) + return + lines[2] = "def" + '='.join(split[1:]) + + split = lines[2].split('method of') + lines[2] = 'method of'.join(split[:1]) + ":" + + documentation = "\n".join(lines[3:]) + + lines[2] = lines[2].replace('{', "''' ").replace('}', " '''").replace('function ', 'lambda_func').replace('<', '"').replace('>', '"').replace('...', "args=''") + + self.write_docfile(self.indent() + lines[2]) + self.write_docfile(self.indent(1) + '"""') + for line in lines[3:]: + self.write_docfile(self.indent(1) + removeIndent(line)) + self.write_docfile(self.indent(1) + '"""') + self.write_docfile(self.indent(1) + "pass \n\n") + +try: + generator = DocumentationGenerator() + generator.run('/usr/lib/python2.6/') +except Exception as e: + print e +finally: + generator.close_files() \ No newline at end of file diff --git a/python_helpers/generate_docs.py b/python_helpers/generate_docs.py index b71f9a9..dd498ce 100644 --- a/python_helpers/generate_docs.py +++ b/python_helpers/generate_docs.py @@ -53,28 +53,29 @@ def removeIndent(line): def process(obj): try: - if obj.__name__.startswith('__'): + if obj.__name__.startswith('_'): raise AttributeError except: - dbg("Aborting, name starts with __") + #dbg("Aborting, name starts with __") return try: current_name.append(obj.__name__) except: current_name.append('') - dbg(" ++ Process called with argument " + str(obj)) + #dbg(" ++ Process called with argument " + str(obj)) if type(obj) == types.ModuleType or type(obj) in validModuleTypes: properties = dir(obj) #print obj, properties, type(obj) - if not obj.__name__.startswith('_'): - print indent() + "class " + obj.__name__ + "(): pass" + if type(obj) == types.ModuleType: + print indent() + "class " + obj.__name__.replace('<','').replace('>','') + "():" + print indent(1) + "pass" for current_property in properties: current_property = getattr(obj, current_property) if type(current_property) in validMethodTypes: - dbg(" >> Processing property: " + str(current_property)) + #dbg(" >> Processing property: " + str(current_property)) process(current_property) if type(current_property) in validModuleTypes: dbg(" MODULE: " + str(current_property)) @@ -86,8 +87,8 @@ def process(obj): #dbg(" -- Skipped property of invalid type " + str(type(current_property))) if type(obj) in validMethodTypes: - dbg(" !! Generating documentation for " + str(obj)) - dbg('.'.join(current_name)) + dbg(" ++ Generating documentation for " + str(obj)) + dbg(" ++ [" + '.'.join(current_name) + "]") documentation = subprocess.Popen(['/usr/bin/pydoc', '.'.join(current_name)], stdout = subprocess.PIPE).stdout.read() lines = documentation.split("\n") @@ -110,7 +111,7 @@ def process(obj): documentation = "\n".join(lines[3:]) - lines[2] = lines[2].replace('<', '"').replace('>', '"') + lines[2] = lines[2].replace('{', "''' ").replace('}', " '''").replace('function ', 'lambda_func').replace('<', '"').replace('>', '"').replace('...', "args=''") print indent() + lines[2] print indent(1) + '"""' @@ -122,22 +123,31 @@ def process(obj): current_name.pop() root_path = '' -f = open('modules') +exclude_packages = ['_sane', 'sane', 'this', 'Pyrex.Plex.test_tm'] +current_file = None +result_basepath = 'results/' for module in walk_directory('/usr/lib/python2.6/'): - module = module.replace("\n", "") + module = module.replace("\n", "").replace('site-packages.', '') module_parts = module.split('.') + try: + current_file = open(result_basepath + module.replace('.', '/'), 'w') + except IOError: + path = result_basepath + for part in module_parts: + path += part + '/' + if not os.path.exists(path): + os.mkdir(path) + current_file = open(result_basepath + module.replace('.', '/'), 'w') + + dbg(" >> Processing MODULE: " + module) + if module in exclude_packages or module.find('test') != -1: # exclude tests and stuff + continue try: current_m = __import__(root_path + module) except: dbg("Could not import module " + module) continue - #if len(module_parts) > 1: - #dbg(str(current_m)) - #for part in module_parts[1:]: - #dbg(root_path + '.'.join(module_parts)) - #__import__(root_path + '.'.join(module_parts)) - #current_m = getattr(current_m, part) - + get_attributes = module.split('.') for attrib in get_attributes: diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 6dd124e..04df501 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -124,8 +124,10 @@ void ParseJob::run() m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); m_duContext->setType(KDevelop::DUContext::Global); DUChain::self()->addDocumentChain(m_duContext); + m_duContext->clearProblems(); } + // 2) parse QPair parserResults = m_session->parse(m_ast); m_ast = parserResults.first; From 38f31f8194ceaf24773f96518c86710ead5aea93 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 1 Nov 2010 15:02:26 +0100 Subject: [PATCH 052/118] Documentation generator, 3rd try --- python_helpers/documentationgenerator.py | 12 ++-- python_helpers/pydocparser.py | 71 ++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 python_helpers/pydocparser.py diff --git a/python_helpers/documentationgenerator.py b/python_helpers/documentationgenerator.py index cdd7a92..5899844 100644 --- a/python_helpers/documentationgenerator.py +++ b/python_helpers/documentationgenerator.py @@ -68,7 +68,8 @@ def walk_module(self, module, module_name): current_type = type(current_property) dbg("CHECK> ", module_name, module, current_property, current_type) if current_type in self.validModuleTypes: - self.walk_module(current_property, module_name + '.' + current_property_name) + dbg("RECURSIVE_CHECK> ", module_name, current_property_name) + self.walk_module(current_property_name, module_name + '.' + current_property_name) if current_type in self.validMethodTypes: self.generate_documentation_for(module_name + '.' + current_property_name) self.generate_documentation_for(module_name) @@ -79,7 +80,7 @@ def write_docfile(self, *args): self.current_file.write('\n') def get_docfile(self, module_name): - pathspec = module_name.split('.') + pathspec = module_name.split('.')[:-1] relative_path = 'results/' + '/'.join(pathspec) + '.py' dbg("PATH> ", relative_path, " (from ", module_name, ")") try: @@ -130,10 +131,12 @@ def generate_documentation_for(self, module_name): return except: pass - self.write_docfile(self.indent() + "# Generated Documentation for ", ''.join(split[:1])) if not '='.join(split[1:]): dbg("SKIP> Skipping invalid function") - dbg("SKIP> Error was", documentation) + dbg("SKIP> Failed to get documentation for", module_name) + return + if '='.join(split[1:]).find('class ') != -1: + dbg("SKIP_CLS> skipping class", module_name) return lines[2] = "def" + '='.join(split[1:]) @@ -144,6 +147,7 @@ def generate_documentation_for(self, module_name): lines[2] = lines[2].replace('{', "''' ").replace('}', " '''").replace('function ', 'lambda_func').replace('<', '"').replace('>', '"').replace('...', "args=''") + self.write_docfile(self.indent() + "# Generated Documentation for ", ''.join(split[:1])) self.write_docfile(self.indent() + lines[2]) self.write_docfile(self.indent(1) + '"""') for line in lines[3:]: diff --git a/python_helpers/pydocparser.py b/python_helpers/pydocparser.py new file mode 100644 index 0000000..b350e22 --- /dev/null +++ b/python_helpers/pydocparser.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python2.6 + +import re +import os +import sys +import subprocess + +modules = ['random'] +state = None + +PackageScanState, ClassScanState = 'pkg', 'cls' +ClassScanState_Outline, ClassScanState_MethodResolution, ClassScanState_MethodDefinition, ClassScanState_DataDescriptors, ClassScanState_Attributes, ClassScanState_InheritedMethods = 'c_otl', 'c_res', 'c_mdf', 'c_dat', 'c_att', 'c_inh' +ClassScanState_InheritedAttributes, ClassScanState_MethodDocumentation = 'c_iat', 'c_mdc' + +ClassMatchRegex = re.compile(r' (class .*?\(.*?\).*?)') +InClassMatchRegex = re.compile(r' \| ') +ResolvedMethodMatchRegex = re.compile(r' \| ([A-Za-z_]*?\(.*?\))') +UnresolvedMethodMatchRegex = re.compile(r' \| (.*? = \)') +CouldBeMethodDocLineRegex = re.compile(r' \| (.*)') + +class method(): + documentation = '' + name = '' + parameters = [] + + def __repr__(self): + return '<'+self.name+'>' + +for module in modules: + doctext = subprocess.Popen(['/usr/bin/pydoc', module], stdout = subprocess.PIPE).stdout.read() + doctext_lines = doctext.split('\n') + methods = [] + currentMethod = None + state = None + classState = None + + for line in doctext_lines: + print state, classState, line[:70] + if state == None: + if re.match(ClassMatchRegex, line): + state = ClassScanState + classState = ClassScanState_Outline + if re.match(ResolvedMethodMatchRegex, line): pass + elif state == ClassScanState: + if not re.match(InClassMatchRegex, line): + state = None + classState = None + continue + if line == ' | Method resolution order:': + classState = ClassScanState_MethodResolution + continue + if line == ' | Methods defined here:': + classState = ClassScanState_MethodDefinition + continue + + if classState == ClassScanState_MethodDocumentation: + if re.match(CouldBeMethodDocLineRegex, line): + currentMethod.documentation += line + else: + classState = ClassScanState_MethodDefinition + + if classState == ClassScanState_MethodDefinition: + if re.match(ResolvedMethodMatchRegex, line): + if currentMethod is not None: + methods.append(currentMethod) + currentMethod = method() + currentMethod.name = line + classState = ClassScanState_MethodDocumentation + +for m in methods: + print m From f472066a84e6d16a65c94d26f450357a090b07fb Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 1 Nov 2010 17:30:08 +0100 Subject: [PATCH 053/118] Fixed two bugs with highlighting and fixed error reporting --- duchain/contextbuilder.cpp | 60 +++++++++++++++++----------------- duchain/contextbuilder.h | 6 ++-- duchain/declarationbuilder.cpp | 2 +- pythonparsejob.cpp | 20 ++++++++---- 4 files changed, 48 insertions(+), 40 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 380df32..7beb618 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -163,26 +163,26 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) m_importedParentContexts.clear(); } -void ContextBuilder::visitFor( ForAst* node ) -{ - DUContext* forctx = openContext( node, KDevelop::DUContext::Other ); - visitNode(node->target); - closeContext(); - - visitNode(node->iterator); - - m_importedParentContexts = QList() << forctx; - openContextForStatementList( node->body ); - openContextForStatementList( node->orelse ); - m_importedParentContexts.clear(); -} +// void ContextBuilder::visitFor( ForAst* node ) +// { +// DUContext* forctx = openContext( node, KDevelop::DUContext::Other ); +// visitNode(node->target); +// closeContext(); +// +// visitNode(node->iterator); +// +// m_importedParentContexts = QList() << forctx; +// openContextForStatementList( node->body ); +// openContextForStatementList( node->orelse ); +// m_importedParentContexts.clear(); +// } -void ContextBuilder::visitWhile( WhileAst* node ) -{ - visitNode( node->condition ); - openContextForStatementList( node->body ); - openContextForStatementList( node->orelse ); -} +// void ContextBuilder::visitWhile( WhileAst* node ) +// { +// visitNode( node->condition ); +// openContextForStatementList( node->body ); +// openContextForStatementList( node->orelse ); +// } void ContextBuilder::visitWith( WithAst * node ) { @@ -203,16 +203,16 @@ void ContextBuilder::visitWith( WithAst * node ) // openContextForStatementList( node->finallyBody ); // } -void ContextBuilder::visitIf( IfAst* node ) -{ - visitNode( node->condition ); - openContextForStatementList( node->body ); - - foreach ( StatementAst* current, node->body) { - visitNode(current); - } - - openContextForStatementList( node->orelse ); -} +// void ContextBuilder::visitIf( IfAst* node ) +// { +// visitNode( node->condition ); +// openContextForStatementList( node->body ); +// +// foreach ( StatementAst* current, node->body) { +// visitNode(current); +// } +// +// openContextForStatementList( node->orelse ); +// } } diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index e50fbe8..9f08370 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -61,10 +61,10 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitFunctionDefinition( FunctionDefinitionAst* ); virtual void visitClassDefinition( ClassDefinitionAst* ); - virtual void visitFor( ForAst* node ); +// virtual void visitFor( ForAst* node ); virtual void visitWith( WithAst* node ); - virtual void visitWhile( WhileAst* node ); - virtual void visitIf( IfAst* node ); +// virtual void visitWhile( WhileAst* node ); +// virtual void visitIf( IfAst* node ); virtual void visitArguments(ArgumentsAst* node); static PythonEditorIntegrator* m_editor; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 7094abb..d22e0c1 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -118,13 +118,13 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* void DeclarationBuilder::visitFor(ForAst* node) { - Python::ContextBuilder::visitFor(node); if ( node->target->astType == Ast::NameAstType ) visitVariableDeclaration(node->target); else if ( node->target->astType == Ast::TupleAstType ) { foreach ( ExpressionAst* tupleMember, dynamic_cast(node->target)->elements ) { if ( tupleMember->astType == Ast::NameAstType ) visitVariableDeclaration(tupleMember); } } + Python::ContextBuilder::visitFor(node); } void DeclarationBuilder::visitImport(ImportAst* node) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 04df501..1aa36bd 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -104,7 +104,7 @@ void ParseJob::run() LanguageSupport* lang = python(); ILanguage* ilang = lang->language(); - QReadLocker lock(ilang->parseLock()); + QReadLocker parselock(ilang->parseLock()); UrlParseLock urlLock(document()); readContents(); @@ -116,22 +116,25 @@ void ParseJob::run() IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); + ParsingEnvironmentFile* file = 0; { DUChainWriteLocker lock(DUChain::lock()); - ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); + + file = new ParsingEnvironmentFile(document()); + file->setModificationRevision(contents().modification); IndexedString langstring("python"); file->setLanguage(langstring); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); m_duContext->setType(KDevelop::DUContext::Global); DUChain::self()->addDocumentChain(m_duContext); - m_duContext->clearProblems(); + m_duContext->clearProblems(); + lock.unlock(); } - // 2) parse QPair parserResults = m_session->parse(m_ast); m_ast = parserResults.first; - + if ( parserResults.second ) { kDebug() << m_url; @@ -162,16 +165,21 @@ void ParseJob::run() { if ( m_parent && m_parent->codeHighlighting() ) { kDebug() << m_duContext.data(); - DUChainReadLocker lock(DUChain::lock()); + DUChainReadLocker rlock(DUChain::lock()); KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); hl->highlightDUChain(m_duContext); } } + { + DUChainWriteLocker lock(DUChain::lock()); + file->setModificationRevision(contents().modification); + } } else { kWarning() << "===Failed==="; // cleanupSmartRevision(); + setDuChain(m_duContext); return abortJob(); } // cleanupSmartRevision(); From e205077aefc40c3d7139c8dd346bd64bb3de0da9 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 1 Nov 2010 18:13:42 +0100 Subject: [PATCH 054/118] Improved the "flickering colors" problem, but no fix yet --- duchain/contextbuilder.cpp | 2 +- duchain/declarationbuilder.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 7beb618..b2c4462 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -143,7 +143,7 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { - kDebug() << " Building function definition context: " << node->name; + kDebug() << " Building function definition context: " << node->name->value; ClassDefinitionAst* classast = dynamic_cast( node->parent ); if ( classast ) m_importedParentContexts.append( currentContext() ); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index d22e0c1..b1b9b30 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -197,6 +197,14 @@ void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) kDebug() << "opening function definition"; int decoratorOffset = node->decorators.length(); // adjust the actual range of the functions' name node->name->startLine += decoratorOffset; node->name->endLine += decoratorOffset; + kDebug() << "Function definition RANGE:" << node->name->startLine << node->name->startCol << node->name->endLine << node->name->endCol; + + // adjust range of arguments, too + if ( node->arguments ) { + node->arguments->startLine += decoratorOffset; + node->arguments->endLine += decoratorOffset; + } + FunctionDeclaration* dec = openDeclaration( node->name, node ); FunctionType::Ptr type(new FunctionType); @@ -222,13 +230,11 @@ void DeclarationBuilder::visitLambda( LambdaAst* node ) void DeclarationBuilder::visitArguments( ArgumentsAst* node ) { - AstDefaultVisitor::visitArguments(node); - AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); + kDebug() << "Current context for parameters: " << currentContext(); if ( function ) { NameAst* realParam; foreach (ExpressionAst* expression, node->arguments) { - visitNode(expression); realParam = dynamic_cast(expression); if ( realParam && realParam->context == ExpressionAst::Parameter ) { Declaration* paramDeclaration = visitVariableDeclaration(realParam); @@ -236,9 +242,12 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) FunctionType::Ptr type = currentType(); if ( type && paramDeclaration ) type->addArgument(paramDeclaration->abstractType()); } + visitNode(expression); } } + AstDefaultVisitor::visitArguments(node); + // ContextBuilder::visitDefaultParameter( node ); // // AbstractFunctionDeclaration* function = currentDeclaration(); // AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); From 077845da422f934c5bde27fc4dc26c26d6b37e96 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 2 Nov 2010 01:12:33 +0100 Subject: [PATCH 055/118] Fix build error --- duchain/contextbuilder.cpp | 8 ++++++++ duchain/contextbuilder.h | 1 + pythonparsejob.cpp | 15 +++++++++++++++ pythonparsejob.h | 4 ++++ 4 files changed, 28 insertions(+) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index b2c4462..6a32dc1 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -33,6 +33,7 @@ #include "dumpchain.h" #include #include +#include using namespace KDevelop; @@ -42,6 +43,8 @@ Python::PythonEditorIntegrator* Python::ContextBuilder::m_editor; namespace Python { + +TopDUContext* ParseJob::m_internalFunctions; PythonEditorIntegrator* ContextBuilder::editor() const { @@ -141,6 +144,11 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) AstDefaultVisitor::visitArguments(node); } +void ContextBuilder::visitCode(CodeAst* node) { + AstDefaultVisitor::visitCode(node); + currentContext()->addImportedParentContext(ParseJob::m_internalFunctions); +} + void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << " Building function definition context: " << node->name->value; diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 9f08370..5c5a8b6 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -66,6 +66,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public // virtual void visitWhile( WhileAst* node ); // virtual void visitIf( IfAst* node ); virtual void visitArguments(ArgumentsAst* node); + virtual void visitCode(CodeAst* node); static PythonEditorIntegrator* m_editor; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 1aa36bd..5b22904 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -59,6 +59,7 @@ using namespace KDevelop; namespace Python { +TopDUContext* ParseJob::m_internalFunctions; ParseJob::ParseJob(LanguageSupport* parent, const KUrl &url ) : KDevelop::ParseJob( url ) @@ -70,6 +71,8 @@ ParseJob::ParseJob(LanguageSupport* parent, const KUrl &url ) { kDebug(); m_parent = parent; + ParseJob::internalFunctionsFile = new KUrl("/home/sven/projects/kde4/python/documentation/test.py"); + ParseJob::m_internalFunctions = 0; } ParseJob::~ParseJob() @@ -93,9 +96,21 @@ bool ParseJob::wasReadFromDisk() const return m_readFromDisk; } +void ParseJob::checkInternalFunctionsParsed() +{ + if ( ! ParseJob::m_internalFunctions ) { + Python::ParseJob* internal = dynamic_cast(Python::LanguageSupport::self()->createParseJob(*internalFunctionsFile)); + internal->run(); + ParseJob::m_internalFunctions = internal->duChain(); + kDebug() << ParseJob::m_internalFunctions; + } +} + void ParseJob::run() { kDebug(); + + if ( m_url != *internalFunctionsFile ) checkInternalFunctionsParsed(); if (abortRequested() || !python() || !python()->language()) { kWarning() << "Language support is NULL"; diff --git a/pythonparsejob.h b/pythonparsejob.h index affeada..b9db7af 100644 --- a/pythonparsejob.h +++ b/pythonparsejob.h @@ -64,6 +64,10 @@ class ParseJob : public KDevelop::ParseJob bool wasReadFromDisk() const; const LanguageSupport* m_parent; + static TopDUContext* m_internalFunctions; + const KUrl* internalFunctionsFile; + + void checkInternalFunctionsParsed(); protected: virtual void run(); From 8715075d01bd8460633c31b05395bac176c04113 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 2 Nov 2010 01:37:58 +0100 Subject: [PATCH 056/118] Simple declarations can now be made in an experimental doc file --- duchain/contextbuilder.cpp | 3 ++- pythonparsejob.cpp | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 6a32dc1..b7e91c3 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -146,7 +146,8 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) void ContextBuilder::visitCode(CodeAst* node) { AstDefaultVisitor::visitCode(node); - currentContext()->addImportedParentContext(ParseJob::m_internalFunctions); + DUChainWriteLocker lock(DUChain::lock()); + currentContext()->addImportedParentContext(DUChain::self()->chainForDocument(KUrl("/home/sven/projects/kde4/python/documentation/test.py"))); } void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 5b22904..3cf01fb 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -52,7 +52,7 @@ #include #include #include - +#include using namespace KDevelop; @@ -99,10 +99,7 @@ bool ParseJob::wasReadFromDisk() const void ParseJob::checkInternalFunctionsParsed() { if ( ! ParseJob::m_internalFunctions ) { - Python::ParseJob* internal = dynamic_cast(Python::LanguageSupport::self()->createParseJob(*internalFunctionsFile)); - internal->run(); - ParseJob::m_internalFunctions = internal->duChain(); - kDebug() << ParseJob::m_internalFunctions; + DUChain::self()->updateContextForUrl(IndexedString(*internalFunctionsFile), minimumFeatures()); } } From 8118e4c76273775d35e6d91296b860f711ade555 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 2 Nov 2010 19:18:53 +0100 Subject: [PATCH 057/118] Python parser with etree instead of minidom --- pythonpythonparser.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 4dc11d8..b302526 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -2,20 +2,18 @@ import ast from xml.dom.minidom import Document +from lxml import etree import types import sys class KDevelopNodeVisitor(ast.NodeVisitor): - xmlrepr = Document() - basenode = None + basenode = etree.Element("pythonast") currentnode = None nodecnt = 0 childNodeMap = {} def __init__(self, *arg, **args): super(KDevelopNodeVisitor, self).__init__(*arg, **args) - self.basenode = self.xmlrepr.createElement("pythonast") - self.xmlrepr.appendChild(self.basenode) self.currentnode = self.basenode def generic_visit(self, node): @@ -24,9 +22,9 @@ def generic_visit(self, node): #self.childNodeMap[self.nodecnt] = node self.childNodeMap[node] = self.nodecnt - node_xmlrepr = self.xmlrepr.createElement(node.__class__.__name__ + "Ast") - node_xmlrepr.setAttribute('nodecnt', str(self.nodecnt)) - self.currentnode.appendChild(node_xmlrepr) + node_xmlrepr = etree.Element(node.__class__.__name__ + "Ast") + node_xmlrepr.set('nodecnt', str(self.nodecnt)) + self.currentnode.append(node_xmlrepr) save_currentnode = self.currentnode self.currentnode = node_xmlrepr @@ -39,7 +37,7 @@ def generic_visit(self, node): value = getattr(node, field) if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: continue - node_xmlrepr.setAttribute(field.lower(), str(value)) + node_xmlrepr.set(field.lower(), str(value)) super(KDevelopNodeVisitor, self).generic_visit(node) @@ -56,13 +54,13 @@ def generic_visit(self, node): sys.stderr.write("Warning: missing key on node " + str(node) + "\n") multiple_keys.append('') key = ','.join(multiple_keys) - node_xmlrepr.setAttribute("NRLST_" + field.lower(), str(key)) + node_xmlrepr.set("NRLST_" + field.lower(), str(key)) else: try: key = self.childNodeMap[value] except KeyError: key = '' - node_xmlrepr.setAttribute("NR_" + field.lower(), str(key)) + node_xmlrepr.set("NR_" + field.lower(), str(key)) self.currentnode = save_currentnode @@ -74,4 +72,4 @@ def generic_visit(self, node): except Exception as e: sys.stderr.write(str(e.lineno) + ':' + str(e.offset)) else: - sys.stdout.write(v.xmlrepr.toprettyxml(indent = " ")) + sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True)) From 4c7be80e131e81c37056fd39d7c6d269db2e5741 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 2 Nov 2010 19:20:41 +0100 Subject: [PATCH 058/118] Attempt to add completion items --- codecompletion/CMakeLists.txt | 2 + .../pythoncodecompletioncontext.cpp | 16 +- parser/ast.cpp | 2 +- parser/astbuilder.cpp | 3 +- parser/astprinter.cpp | 204 ------ parser/astprinter.h | 53 -- parser/kwcheck.cpp | 459 ------------ parser/kwcheck.h | 42 -- parser/numbercheck.cpp | 50 -- parser/numbercheck.h | 35 - parser/python.g | 675 ------------------ parser/pythonlexer.cpp | 651 ----------------- parser/pythonlexer.h | 81 --- 13 files changed, 18 insertions(+), 2255 deletions(-) delete mode 100644 parser/astprinter.cpp delete mode 100644 parser/astprinter.h delete mode 100644 parser/kwcheck.cpp delete mode 100644 parser/kwcheck.h delete mode 100644 parser/numbercheck.cpp delete mode 100644 parser/numbercheck.h delete mode 100644 parser/python.g delete mode 100644 parser/pythonlexer.cpp delete mode 100644 parser/pythonlexer.h diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 1a03ac5..1231c12 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -15,6 +15,8 @@ kde4_add_library(kdev4pythoncompletion SHARED ${completion_SRCS}) target_link_libraries(kdev4pythoncompletion ${KDE4_KDECORE_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} + ${KDEVPLATFORM_INTERFACES_LIBRARIES} + ${KDEVPLATFORM_PROJECT_LIBRARIES} kdev4pythonduchain ) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index ce98954..10fee9c 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -11,6 +11,10 @@ #include "navigationwidget.h" #include "importfileitem.h" #include +#include +#include +#include +#include using namespace KDevelop; @@ -34,9 +38,15 @@ QList PythonCodeCompletionContext::completionItems(bo kDebug() << "Adding testing item to completion list"; - IncludeItem item; - item.name = "Foo"; - items << CompletionTreeItemPointer( new ImportFileItem(item) ); + foreach (IProject* project, ICore::self()->projectController()->projects() ) { + foreach ( ProjectFolderItem* folder, project->foldersForUrl( KUrl(project->folder().url()) ) ) { + foreach ( ProjectFileItem* file, folder->fileList() ) { + IncludeItem item; + item.name = file->fileName(); + items << CompletionTreeItemPointer( new ImportFileItem(item) ); + } + } + } return items; } diff --git a/parser/ast.cpp b/parser/ast.cpp index 8c70368..9a6087e 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -136,7 +136,7 @@ ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::Exceptio } -ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0) +ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0), locals(0), globals(0) { } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 6c3539d..362ffd7 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -96,9 +96,10 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) p->setSeverity(KDevelop::ProblemData::Error); { DUChainWriteLocker lock(DUChain::lock()); + m_topContext->clearProblems(); m_topContext->addProblem(p); DUChain::self()->updateContextForUrl(IndexedString(filename), m_topContext->features()); - kDebug() << m_topContext->problems(); + kDebug() << "Added problem: " << m_topContext->problems(); } kWarning() << "Parse Error: " << result; return "0"; diff --git a/parser/astprinter.cpp b/parser/astprinter.cpp deleted file mode 100644 index 64b2a0e..0000000 --- a/parser/astprinter.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2008 Andreas Pakulat * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License as * - * published by the Free Software Foundation; either version 2 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include "astprinter.h" - -#include - -namespace Python -{ - -static QString names[] = { -"Argument", -"Assert", -"Assignment", -"Atom", -"AttributeReference", -"AttributeReferenceTarget", -"BinaryExpression", -"BooleanNotOperation", -"BooleanAndOperation", -"BooleanOrOperation", -"Break", -"Call", -"ClassDefinition", -"Code", -"Comparison", -"ConditionalExpression", -"Continue", -"Decorator", -"DefaultParameter", -"Del", -"Dictionary", -"DictionaryParameter", -"EllipsisSliceItem", -"Enclosure", -"Except", -"Exec", -"ExpressionSliceItem", -"ExpressionStatement", -"ExtendedSlice", -"For", -"FromImport", -"FunctionDefinition", -"Generator", -"GeneratorFor", -"GeneratorIf", -"Global", -"Identifier", -"IdentifierParameterPart", -"IdentifierTarget", -"If", -"Lambda", -"List", -"ListFor", -"ListIf", -"ListParameter", -"ListParameterPart", -"ListTarget", -"Literal", -"Pass", -"PlainImport", -"Print", -"ProperSliceItem", -"Raise", -"Return", -"SimpleSlice", -"SliceTarget", -"StarImport", -"Subscript", -"SubscriptTarget", -"TupleTarget", -"Try", -"UnaryExpression", -"While", -"With", -"Yield", -}; - -AstPrinter::AstPrinter() - : AstDefaultVisitor(), indent( 0 ) -{ -} - -AstPrinter::~AstPrinter() -{ -} - -void AstPrinter::visitNode( Ast* node ) -{ - if( node ) - { - kDebug() << indentation() + "\\ " + names[node->astType] + "[(" + QString::number( node->start ) + ")]"; - ++indent; - } - AstDefaultVisitor::visitNode( node ); - if(node) - { - --indent; - kDebug() << indentation() + "/ " + names[node->astType] + "[(" + QString::number( node->end ) + ")]"; - } -} - -QString AstPrinter::indentation() const -{ - QString s; - for( int a = 0; a < indent; a++ ) - s += "| "; - return s; -} - -void AstPrinter::visitIdentifier( IdentifierAst * ast ) -{ - kDebug() << indentation() + " Identifier ==" << ast->identifier; -} - -void AstPrinter::visitLiteral( LiteralAst * ast ) -{ - kDebug() << indentation() + " literal type ==" << ast->literalType; - kDebug() << indentation() + " Literal ==" << ast->value; -} - -void AstPrinter::visitArgument( ArgumentAst* node ) -{ - kDebug() << indentation() + " ArgumentType ==" << node->argumentType; - AstDefaultVisitor::visitArgument( node ); -} - -void AstPrinter::visitFromImport( FromImportAst* node ) -{ - kDebug() << indentation() + " leading dots ==" << node->numLeadingDots; - AstDefaultVisitor::visitFromImport( node ); -} - -void AstPrinter::visitAssignment( AssignmentAst* node ) -{ - QList, AssignmentAst::OpType > >::const_iterator it; - QList, AssignmentAst::OpType > >::const_iterator end; - it = node->targets.begin(); - end = node->targets.end(); - for( ; it != end; ++it ) - { - QList tl = (*it).first; - foreach( TargetAst* t, tl ) - { - visitNode( t ); - } - kDebug() << indentation() + " op type ==" << (*it).second; - } - - foreach( ExpressionAst* e, node->value ) - { - visitNode( e ); - } - visitNode( node->yieldValue ); -} - -void AstPrinter::visitEnclosure( EnclosureAst* node ) -{ - kDebug() << indentation() + " enclosure type ==" << node->encType; - AstDefaultVisitor::visitEnclosure( node ); -} - -void AstPrinter::visitComparison( ComparisonAst* node ) -{ - visitNode( node->firstComparator ); - QList< QPair< ComparisonAst::ComparisonOperator, ExpressionAst*> >::iterator it; - QList< QPair< ComparisonAst::ComparisonOperator, ExpressionAst*> >::iterator end = node->comparatorList.end(); - for( it = node->comparatorList.begin(); it != end; ++it ) - { - kDebug() << indentation() + " comparison type" << (*it).first; - visitNode( (*it).second ); - } -} - -void AstPrinter::visitBinaryExpression( BinaryExpressionAst* node ) -{ - kDebug() << indentation() + " binary op ==" << node->opType; - AstDefaultVisitor::visitBinaryExpression( node ); -} - -void AstPrinter::visitUnaryExpression( UnaryExpressionAst* node ) -{ - kDebug() << indentation() + " binary op ==" << node->opType; - AstDefaultVisitor::visitUnaryExpression( node ); -} - -} diff --git a/parser/astprinter.h b/parser/astprinter.h deleted file mode 100644 index 34c7945..0000000 --- a/parser/astprinter.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2008 Andreas Pakulat * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License as * - * published by the Free Software Foundation; either version 2 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef ASTPRINTER_H -#define ASTPRINTER_H - -#include "astdefaultvisitor.h" -#include "parserexport.h" - -namespace Python -{ - -class KDEVPYTHONPARSER_EXPORT AstPrinter : public AstDefaultVisitor -{ -public: - AstPrinter(); - ~AstPrinter(); - virtual void visitIdentifier( IdentifierAst* ast ); - virtual void visitLiteral( LiteralAst* ast ); - virtual void visitNode( Ast* ast ); - virtual void visitUnaryExpression( UnaryExpressionAst* node ); - virtual void visitBinaryExpression( BinaryExpressionAst* node ); - virtual void visitComparison( ComparisonAst* node ); - virtual void visitEnclosure( EnclosureAst* node ); - virtual void visitAssignment( AssignmentAst* node ); - virtual void visitFromImport( FromImportAst* node ); - virtual void visitArgument( ArgumentAst* node ); - -private: - QString indentation() const; - int indent; -}; - -} - -#endif diff --git a/parser/kwcheck.cpp b/parser/kwcheck.cpp deleted file mode 100644 index c77a576..0000000 --- a/parser/kwcheck.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/* KDevelop Python Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "kwcheck.h" -#include "pythonparser.h" - -namespace PythonParser -{ - -int checkForKeyword( const QChar* txt, int len ) -{ - switch( len ) - { - case 2: - return kwcheck2(txt); - case 3: - return kwcheck3(txt); - case 4: - return kwcheck4(txt); - case 5: - return kwcheck5(txt); - case 6: - return kwcheck6(txt); - case 7: - return kwcheck7(txt); - case 8: - return kwcheck8(txt); - default: - return Parser::Token_IDENTIFIER; - } -} - -int kwcheck2( const QChar* s ) -{ - if( s[0] == 'a' ) - { - if( s[1] == 's' ) - { - return Parser::Token_AS; - } - }else if( s[0] == 'i' ) - { - if( s[1] == 's' ) - { - return Parser::Token_IS; - }else if( s[1] == 'n' ) - { - return Parser::Token_IN; - }else if( s[1] == 'f' ) - { - return Parser::Token_IF; - } - }else if( s[0] == 'o' ) - { - if( s[1] == 'r' ) - return Parser::Token_OR; - } - return Parser::Token_IDENTIFIER; -} - -int kwcheck3( const QChar* s ) -{ - if( s[0] == 'a' ) - { - if( s[1] == 'n' ) - { - if( s[2] == 'd' ) - { - return Parser::Token_AND; - } - } - } else if( s[0] == 'd' ) - { - if( s[1] == 'e' ) - { - if( s[2] == 'l' ) - { - return Parser::Token_DEL; - }else if( s[2] == 'f' ) - { - return Parser::Token_DEF; - } - } - } else if( s[0] == 'f' ) - { - if( s[1] == 'o' ) - { - if( s[2] == 'r' ) - { - return Parser::Token_FOR; - } - } - }else if( s[0] == 'n' ) - { - if( s[1] == 'o' ) - { - if( s[2] == 't' ) - { - return Parser::Token_NOT; - } - } - }else if( s[0] == 't' ) - { - if( s[1] == 'r' ) - { - if( s[2] == 'y' ) - { - return Parser::Token_TRY; - } - } - } - return Parser::Token_IDENTIFIER; -} - - -int kwcheck4( const QChar* s ) -{ - if( s[0] == 'e' ) - { - if( s[1] == 'l' ) - { - if( s[2] == 's' ) - { - if( s[3] == 'e' ) - { - return Parser::Token_ELSE; - } - }else if( s[2] == 'i' ) - { - if( s[3] == 'f' ) - { - return Parser::Token_ELIF; - } - } - }else if( s[1] == 'x' ) - { - if( s[2] == 'e' ) - { - if( s[3] == 'c' ) - { - return Parser::Token_EXEC; - } - } - } - }else if( s[0] == 'f' ) - { - if( s[1] == 'r' ) - { - if( s[2] == 'o' ) - { - if( s[3] == 'm' ) - { - return Parser::Token_FROM; - } - } - } - }else if( s[0] == 'p' ) - { - if( s[1] == 'a' ) - { - if( s[2] == 's' ) - { - if( s[3] == 's' ) - { - return Parser::Token_PASS; - } - } - } - } - return Parser::Token_IDENTIFIER; -} - -int kwcheck5( const QChar* s ) -{ - if( s[0] == 'b' ) - { - if( s[1] == 'r' ) - { - if( s[2] == 'e' ) - { - if( s[3] == 'a' ) - { - if( s[4] == 'k' ) - { - return Parser::Token_BREAK; - } - } - } - } - }else if( s[0] == 'c' ) - { - if( s[1] == 'l' ) - { - if( s[2] == 'a' ) - { - if( s[3] == 's' ) - { - if( s[4] == 's' ) - { - return Parser::Token_CLASS; - } - } - } - } - }else if( s[0] == 'p' ) - { - if( s[1] == 'r' ) - { - if( s[2] == 'i' ) - { - if( s[3] == 'n' ) - { - if( s[4] == 't' ) - { - return Parser::Token_PRINT; - } - } - } - } - }else if( s[0] == 'r' ) - { - if( s[1] == 'a' ) - { - if( s[2] == 'i' ) - { - if( s[3] == 's' ) - { - if( s[4] == 'e' ) - { - return Parser::Token_RAISE; - } - } - } - } - }else if( s[0] == 'w' ) - { - if( s[1] == 'h' ) - { - if( s[2] == 'i' ) - { - if( s[3] == 'l' ) - { - if( s[4] == 'e' ) - { - return Parser::Token_WHILE; - } - } - } - } - }else if( s[0] == 'y' ) - { - if( s[1] == 'i' ) - { - if( s[2] == 'e' ) - { - if( s[3] == 'l' ) - { - if( s[4] == 'd' ) - { - return Parser::Token_YIELD; - } - } - } - } - } - return Parser::Token_IDENTIFIER; -} - -int kwcheck6( const QChar* s ) -{ - if( s[0] == 'a' ) - { - if( s[1] == 's' ) - { - if( s[2] == 's' ) - { - if( s[3] == 'e' ) - { - if( s[4] == 'r' ) - { - if( s[5] == 't' ) - { - return Parser::Token_ASSERT; - } - } - } - } - } - }else if( s[0] == 'e' ) - { - if( s[1] == 'x' ) - { - if( s[2] == 'c' ) - { - if( s[3] == 'e' ) - { - if( s[4] == 'p' ) - { - if( s[5] == 't' ) - { - return Parser::Token_EXCEPT; - } - } - } - } - } - }else if( s[0] == 'g' ) - { - if( s[1] == 'l' ) - { - if( s[2] == 'o' ) - { - if( s[3] == 'b' ) - { - if( s[4] == 'a' ) - { - if( s[5] == 'l' ) - { - return Parser::Token_GLOBAL; - } - } - } - } - } - }else if( s[0] == 'i' ) - { - if( s[1] == 'm' ) - { - if( s[2] == 'p' ) - { - if( s[3] == 'o' ) - { - if( s[4] == 'r' ) - { - if( s[5] == 't' ) - { - return Parser::Token_IMPORT; - } - } - } - } - } - }else if( s[0] == 'l' ) - { - if( s[1] == 'a' ) - { - if( s[2] == 'm' ) - { - if( s[3] == 'b' ) - { - if( s[4] == 'd' ) - { - if( s[5] == 'a' ) - { - return Parser::Token_LAMBDA; - } - } - } - } - } - }else if( s[0] == 'r' ) - { - if( s[1] == 'e' ) - { - if( s[2] == 't' ) - { - if( s[3] == 'u' ) - { - if( s[4] == 'r' ) - { - if( s[5] == 'n' ) - { - return Parser::Token_RETURN; - } - } - } - } - } - } - return Parser::Token_IDENTIFIER; -} - -int kwcheck7( const QChar* s ) -{ - if( s[0] == 'f' ) - { - if( s[1] == 'i' ) - { - if( s[2] == 'n' ) - { - if( s[3] == 'a' ) - { - if( s[4] == 'l' ) - { - if( s[5] == 'l' ) - { - if( s[6] == 'y' ) - { - return Parser::Token_FINALLY; - } - } - } - } - } - } - } - return Parser::Token_IDENTIFIER; -} - -int kwcheck8( const QChar* s ) -{ - if( s[0] == 'c' ) - { - if( s[1] == 'o' ) - { - if( s[2] == 'n' ) - { - if( s[3] == 't' ) - { - if( s[4] == 'i' ) - { - if( s[5] == 'n' ) - { - if( s[6] == 'u' ) - { - if( s[7] == 'e' ) - { - return Parser::Token_CONTINUE; - } - } - } - } - } - } - } - } - return Parser::Token_IDENTIFIER; -} - -} - -// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on diff --git a/parser/kwcheck.h b/parser/kwcheck.h deleted file mode 100644 index b4a54ca..0000000 --- a/parser/kwcheck.h +++ /dev/null @@ -1,42 +0,0 @@ -/* KDevelop Python Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef KWCHECK_H -#define KWCHECK_H - -class QChar; - -namespace PythonParser -{ - -int kwcheck2( const QChar* s ); -int kwcheck3( const QChar* s ); -int kwcheck4( const QChar* s ); -int kwcheck5( const QChar* s ); -int kwcheck6( const QChar* s ); -int kwcheck7( const QChar* s ); -int kwcheck8( const QChar* s ); -int checkForKeyword( const QChar* txt, int len ); - -} - -#endif - -// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on diff --git a/parser/numbercheck.cpp b/parser/numbercheck.cpp deleted file mode 100644 index fb07025..0000000 --- a/parser/numbercheck.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* KDevelop Python Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "numbercheck.h" -#include "pythonparser.h" - -#include -#include -#include - -namespace PythonParser -{ -QRegExp intnum("((0|[1-9][0-9]*)|0[0-7]+|0(x|X)[0-9a-fA-F]+)(l|L)?"); -QRegExp floatnum("(([0-9]+)?\\.[0-9]+|[0-9]+\\.)|(([0-9]+|(([0-9]+)?\\.[0-9]+|[0-9]+\\.))(e|E)[-+]?[0-9]+)"); -QRegExp imagnum("("+floatnum.pattern()+"|[0-9]+)(j|J)"); - -int getTokenForNumberString( const QString& s ) -{ - if( intnum.exactMatch( s ) ) - { - return Parser::Token_INTEGER; - }else if( floatnum.exactMatch( s ) ) - { - return Parser::Token_FLOAT; - }else if( imagnum.exactMatch( s ) ) - { - return Parser::Token_IMAGNUM; - } - return Parser::Token_INVALID; -} -} - -// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on diff --git a/parser/numbercheck.h b/parser/numbercheck.h deleted file mode 100644 index e8271c2..0000000 --- a/parser/numbercheck.h +++ /dev/null @@ -1,35 +0,0 @@ -/* KDevelop Python Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef NUMBERCHECK_H -#define NUMBERCHECK_H - -class QString; - -namespace PythonParser -{ - -int getTokenForNumberString( const QString& ); - -} - -#endif - -// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on diff --git a/parser/python.g b/parser/python.g deleted file mode 100644 index 2afc5a4..0000000 --- a/parser/python.g +++ /dev/null @@ -1,675 +0,0 @@ -------------------------------------------------------------------------------- --- Copyright (c) 2006 Andreas Pakulat --- Copyright (c) 2007 Piyush Verma --- --- Permission is hereby granted, free of charge, to any person obtaining --- a copy of this software and associated documentation files (the --- "Software"), to deal in the Software without restriction, including --- without limitation the rights to use, copy, modify, merge, publish, --- distribute, sublicense, and/or sell copies of the Software, and to --- permit persons to whom the Software is furnished to do so, subject to --- the following conditions: --- --- The above copyright notice and this permission notice shall be --- included in all copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, --- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF --- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND --- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE --- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION --- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION --- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- - ------------------------------------------------------------ --- Grammar for Python2.5 --- Modelled after the Grammar files shipped with Python2.4 --- source, the Python Language Reference documentation, --- also included with Python --- And after the Python 2.3.3 Antlr grammar found on the --- antlr grammar list page ------------------------------------------------------------ - ------------------------------------------------------------ --- TODO: Error recovery --- %parserclass (private declaration) --- [: --- parser::pythonCompatibilityMode m_compatibilityMode; --- --- struct ParserState { --- }; --- ParserState m_state; --- :] --- Parser::parserState *Parser::copyCurrentState() --- { --- ParserState *state = new ParserState(); --- return state; --- } --- --- void Parser::restoreState( Parser::ParserState *state ) --- { --- } --- --- Then a rule like (stmt)* -> project can be written --- as try/recover(stmt)* -> project and the parser --- will skip any errornous statements - ------------------------------------------------------------ --- Global declarations ------------------------------------------------------------ - -[: - -#include -#include - -namespace PythonParser -{ - class Lexer; - - enum OperatorType { - LeftShiftOp, - RightShiftOp, - PlusOp, - MinusOp, - StarOp, - SlashOp, - ModuloOp, - DoubleSlashOp, - UnaryPlusOp, - UnaryMinusOp, - UnaryTildeOp, - PlusEqOp, - MinusEqOp, - StarEqOp, - SlashEqOp, - ModuloEqOp, - AndEqOp, - OrEqOp, - HatEqOp, - LeftShiftEqOp, - RightShiftEqOp, - DoublestarEqOp, - DoubleslashEqOp, - LessOp, - GreaterOp, - IsEqualOp, - GreaterEqOp, - LessEqOp, - UnEqualOp, - InOp, - NotInOp, - IsOp, - IsNotOp - }; - enum NumericType { - IntegerNumeric, - FloatNumeric, - ImaginaryNumeric - }; -} -:] - - ------------------------------------------------------------- --- Export macro to use the parser in a shared lib ------------------------------------------------------------- -%export_macro "KDEVPYTHONPARSER_EXPORT" -%export_macro_header "parserexport.h" - ------------------------------------------------------------- --- Parser class members ------------------------------------------------------------- - -%parserclass (public declaration) -[: - /** - * Transform the raw input into tokens. - * When this method returns, the parser's token stream has been filled - * and any parse_*() method can be called. - */ - void tokenize( const QString& contents ); - - enum ProblemType { - Error, - Warning, - Info - }; - void reportProblem( Parser::ProblemType type, const QString& message ); - QString tokenText(qint64 begin, qint64 end); - void setDebug(bool debug); - -:] - -%parserclass (private declaration) -[: - QString mContents; - bool mDebug; -:] - ------------------------------------------------------------ --- List of defined tokens ------------------------------------------------------------ - --- keywords -%token AND ("and"), DEL ("del"), FOR ("for"), IS ("is"), RAISE ("raise"), - ASSERT ("assert"), ELIF ("elif"), FROM ("from"), LAMBDA ("lambda"), - RETURN ("returns"), BREAK ("break"), ELSE ("else"), GLOBAL ("global"), - NOT ("not"), TRY ("try"), CLASS ("class"), EXCEPT ("except"), IF ("if"), - OR ("or"), WHILE ("while"), CONTINUE ("continue"), EXEC ("exec"), - IMPORT ("import"), PASS ("pass"), YIELD ("yield"), DEF ("def"), IN ("in"), - PRINT ("print"), FINALLY ("finally"), AS ("as") ;; - --- indentation which is important in python and linebreak -%token INDENT ("indent"), DEDENT ("dedent"), LINEBREAK ("linebreak") ;; - --- Identifiers, Strings and numbers -%token STRINGLITERAL ("stringliteral"), IDENTIFIER ("identifier"), - INTEGER ("integer"), FLOAT ("float"), IMAGNUM ("imagnum") ;; - --- separators -%token LPAREN ("lparen"), RPAREN ("rparen"), LBRACE ("lbrace"), RBRACE ("rbrace"), - LBRACKET ("lbracket"), RBRACKET ("rbracket"), COMMA ("comma"), AT ("at"), - SEMICOLON ("semicolon"), COLON ("colon"), DOT ("dot"), BACKTICK ("backtick") ;; - --- operators -%token ELLIPSIS ("ellipsis"), STAR ("star"), DOUBLESTAR ("doublestar"), EQUAL ("equal"), - PLUS ("plus"), MINUS ("minus"), TILDE ("tilde"), SLASH ("slash"), - DOUBLESLASH ("doubleslash"), MODULO ("modulo"), AND ("and"), LSHIFT ("lshift"), - RSHIFT ("rshift"), PLUSEQ ("pluseq"), MINUSEQ ("minuseq"), SLASHEQ ("slasheq"), - DOUBLESLASHEQ ("doubleslasheq"), MODULOEQ ("moduloeq"), ANDEQ ("andeq"), - STAREQ ("stareq"), DOUBLESTAREQ ("doublestareq"), LSHIFTEQ ("lshifteq"), - RSHIFTEQ ("rshifteq"), LESS ("less"), GREATER ("greater"), GREATEREQ ("greatereq"), - LESSEQ ("lesseq"), UNEQUAL ("unequal"), OR ("or"), BITXOR ("bitxor"), ISEQUAL ("isequal"), - TILDEEQ ("tildeeq"), OREQ ("oreq"), BITAND ("bitand") , BITOR ("bitor");; - - --- token that makes the parser fail in any case: -%token INVALID ("invalid token") ;; - --- The actual grammar starts here. - - ( #stmt = stmt )* --> project ;; - - AT decoratorName = dottedName ( LPAREN ( arguments=arglist | 0) RPAREN | 0 ) LINEBREAK --> decorator ;; - - (#decorator = decorator )+ --> decorators ;; - --- Function Definition: Can start with Decorators. --- varargslist defines the Function Variable Arguements - ( decorators = decorators | 0 ) - DEF funcName=IDENTIFIER LPAREN ( ?[: LA(1).kind != Token_RPAREN :] ( funArgs = varargslist ) - | 0 ) - RPAREN COLON funSuite=suite --> funcdecl ;; - --- Function variable Arguement List - ( funcDef=funcDef | 0 ) ( - ?[: yytoken != Token_RPAREN && LA(2).kind == Token_IDENTIFIER:] (funPosParam = funPosParam ) - | 0 - ) --> varargslist ;; - --- The Vararguement trailer, defines *args and **args - ( listParam=listParam ( COMMA dictParam=dictParam | 0 ) - | dictParam=dictParam ) --> funPosParam;; - - DOUBLESTAR doubleStarId=IDENTIFIER --> dictParam;; - - STAR starId=IDENTIFIER --> listParam;; - --- Function Definition - #fpDef=fpDef ( COMMA [:if(yytoken == Token_RPAREN || yytoken == Token_STAR || yytoken == Token_DOUBLESTAR ) { break; } :] #fpDef=fpDef )* --> funcDef ;; - - --- Function parameter Defintion - defparam=defparam ( EQUAL fpDefTest=test | 0 ) --> fpDef ;; - --- Function Parameter Definition - LPAREN (fplist = fplist) RPAREN - | paramname=IDENTIFIER --> defparam ;; - - --- Function parameter List - #fplistFpdef=defparam - ( COMMA [: if ( yytoken == Token_RPAREN ) - { break; } :] - #fplistFpdef=defparam )* --> fplist ;; - --- A statement could be simple statement, a compound statement OR just a Linebreak - simpleStmt = simpleStmt - | compoundStmt = compoundStmt - | LINEBREAK --> stmt ;; - --- simple statement, TODO this needs more work for simpleStmts at the enf of files - #smallStmt = smallStmt - ( SEMICOLON [: if( yytoken == Token_LINEBREAK || yytoken == Token_DEDENT) { break;} :] #smallStmt = smallStmt )* LINEBREAK --> simpleStmt ;; - --- a small statement could be of any such kinds - exprStmt = exprStmt - | printStmt = printStmt - | delStmt = delStmt - | passStmt = passStmt - | flowStmt = flowStmt - | importStmt = importStmt - | globalStmt= globalStmt - | execStmt = execStmt - | assertStmt = assertStmt --> smallStmt ;; - - (testlist = testlist) ( augassign = augassign ( anugassignTestlist = testlist | yield=yieldExpr ) - | ( EQUAL ( yield=yieldExpr | #equalTestlist = testlist ) )+ - | ?[: yytoken == Token_SEMICOLON || yytoken == Token_LINEBREAK :] 0 ) --> exprStmt ;; - - PLUSEQ [: (*yynode)->assignOp = PythonParser::PlusEqOp; :] - | MINUSEQ [: (*yynode)->assignOp = PythonParser::MinusEqOp; :] - | STAREQ [: (*yynode)->assignOp = PythonParser::StarEqOp; :] - | SLASHEQ [: (*yynode)->assignOp = PythonParser::SlashEqOp; :] - | MODULOEQ [: (*yynode)->assignOp = PythonParser::ModuloEqOp; :] - | ANDEQ [: (*yynode)->assignOp = PythonParser::AndEqOp; :] - | OREQ [: (*yynode)->assignOp = PythonParser::OrEqOp; :] - | TILDEEQ [: (*yynode)->assignOp = PythonParser::HatEqOp; :] - | LSHIFTEQ [: (*yynode)->assignOp = PythonParser::LeftShiftEqOp; :] - | RSHIFTEQ [: (*yynode)->assignOp = PythonParser::RightShiftEqOp; :] - | DOUBLESTAREQ [: (*yynode)->assignOp = PythonParser::DoublestarEqOp; :] - | DOUBLESLASHEQ [: (*yynode)->assignOp = PythonParser::DoubleslashEqOp;:] --> augassign [ - member variable assignOp : PythonParser::OperatorType; ];; - - PRINT - ( - (#printArgs=test ( COMMA [: if(yytoken == Token_SEMICOLON || yytoken == Token_LINEBREAK) {break; } :]#printArgs=test )*) - | RSHIFT #rshiftArgs=test ( ( COMMA [: if(yytoken == Token_SEMICOLON || yytoken == Token_LINEBREAK) {break; } :]#rshiftArgs=test )*) - | 0 - ) --> printStmt ;; - - DEL delList=exprlist --> delStmt ;; - - PASS --> passStmt ;; - - breakStmt=breakStmt - | continueStmt=continueStmt - | returnStmt=returnStmt - | raiseStmt=raiseStmt - | yieldStmt=yieldStmt --> flowStmt ;; - - BREAK --> breakStmt ;; - - CONTINUE --> continueStmt ;; - - RETURN ( returnExpr=testlist | 0 ) --> returnStmt ;; - - YIELD ( expr=testlist | 0 ) --> yieldExpr ;; - - yield=yieldExpr --> yieldStmt ;; - - RAISE ( type=test ( COMMA value=test ( COMMA traceback=test | 0 ) | 0 ) | 0 ) --> raiseStmt ;; - - importImport=importName - | importFrom=importFrom --> importStmt ;; - - IMPORT importName=dottedAsNames --> importName ;; - - FROM importFromName=dottedName IMPORT ( STAR | LPAREN importAsNames=importAsNames RPAREN | importAsNames=importAsNames ) --> importFrom ;; - - importedName=IDENTIFIER ( AS importedAs=IDENTIFIER | 0 ) --> importAsName ;; - - importDottedName=dottedName ( AS importedAs=IDENTIFIER | 0 ) --> dottedAsName ;; - - #importAsName=importAsName - ( COMMA [: if( yytoken == Token_RPAREN || yytoken == Token_LINEBREAK || yytoken == Token_SEMICOLON ) { break;} :] #importAsName=importAsName)* --> importAsNames ;; - - #dottedAsName=dottedAsName ( COMMA #dottedAsName=dottedAsName )* --> dottedAsNames ;; - - #dottedName=IDENTIFIER ( DOT #dottedName=IDENTIFIER )* --> dottedName ;; - - GLOBAL #globalName=IDENTIFIER ( COMMA #globalName=IDENTIFIER )* --> globalStmt ;; - - EXEC execCode=expr ( IN globalDictExec=test ( COMMA localDictExec=test | 0 ) | 0 ) --> execStmt ;; - - ASSERT assertNotTest=test ( COMMA assertRaiseTest=test | 0 ) --> assertStmt ;; - - ifStmt=ifStmt - | whileStmt=whileStmt - | forStmt=forStmt - | tryStmt=tryStmt - | funcdecl=funcdecl - | classdef=classdef --> compoundStmt ;; - - IF ifTest=test COLON ifSuite=suite ( ELIF #elifTest=test COLON #elifSuite=suite )* ( ELSE COLON ifElseSuite=suite | 0 ) --> ifStmt ;; - - WHILE whileTest=test COLON whileSuite=suite ( ELSE COLON whileElseSuite=suite | 0 ) --> whileStmt ;; - - FOR forExpr=exprlist IN forTestlist=testlist COLON forSuite=suite ( ELSE COLON forElseSuite=suite | 0 ) --> forStmt ;; - - TRY COLON trySuite=suite - ( ( #exceptClause=exceptClause COLON #exceptSuite=suite )+ ( ELSE COLON tryElseSuite=suite | 0 ) | FINALLY COLON finallySuite=suite ) --> tryStmt ;; - - EXCEPT ( exceptTest=test ( COMMA exceptTargetTest=test | 0 ) | 0 ) --> exceptClause ;; - - simpleStmt=simpleStmt | (LINEBREAK)+ INDENT (#stmt=stmt)+ DEDENT --> suite ;; - - #andTest=andTest ( OR #andTest=andTest )* | lambdaDef=lambdaDef --> test ;; - - #notTest=notTest ( AND #notTest=notTest )* --> andTest ;; - - NOT notTest=notTest | comparison=comparison --> notTest ;; - - compExpr=expr ( #compOp=compOp #compOpExpr=expr )* --> comparison ;; - - LESS [: (*yynode)->compOp = PythonParser::LessOp; :] - | GREATER [: (*yynode)->compOp = PythonParser::GreaterOp; :] - | ISEQUAL [: (*yynode)->compOp = PythonParser::IsEqualOp; :] - | GREATEREQ [: (*yynode)->compOp = PythonParser::GreaterEqOp; :] - | LESSEQ [: (*yynode)->compOp = PythonParser::LessEqOp; :] - | UNEQUAL [: (*yynode)->compOp = PythonParser::UnEqualOp; :] - | IN [: (*yynode)->compOp = PythonParser::InOp; :] - | NOT IN [: (*yynode)->compOp = PythonParser::NotInOp; :] - | IS (NOT [: (*yynode)->compOp = PythonParser::IsNotOp; :] - | 0 [: (*yynode)->compOp = PythonParser::IsOp; :] - ) --> compOp [ - member variable compOp : PythonParser::OperatorType; ];; - - expr=xorExpr ( BITOR #orrExpr=xorExpr )* --> expr ;; - - xorExpr=andExpr ( BITXOR #hatXorExpr=andExpr )* --> xorExpr ;; - - andExpr=shiftExpr ( BITAND #anddShifExpr=shiftExpr )* --> andExpr ;; - - arithExpr=arithExpr - ( #shiftOpList=shiftOp #arithExprList=arithExpr )* --> shiftExpr ;; - - LSHIFT [: (*yynode)->shiftOp = PythonParser::LeftShiftOp; :] - | RSHIFT [: (*yynode)->shiftOp = PythonParser::RightShiftOp; :] --> shiftOp [ - member variable shiftOp : PythonParser::OperatorType; ];; - - arithTerm=term - ((#arithOpList = arithOp #arithTermList=term )+ | 0) --> arithExpr ;; - - PLUS [: (*yynode)->arithOp = PythonParser::PlusOp; :] - | MINUS [: (*yynode)->arithOp = PythonParser::MinusOp; :] --> arithOp [ - member variable arithOp: PythonParser::OperatorType; ] ;; - - factor=factor - ((#termOp = termOp #factors=factor )+ | 0) --> term ;; - - STAR [: (*yynode)->op = PythonParser::StarOp; :] - | SLASH [: (*yynode)->op = PythonParser::SlashOp; :] - | MODULO [: (*yynode)->op = PythonParser::ModuloOp; :] - | DOUBLESLASH [: (*yynode)->op = PythonParser::DoubleSlashOp; :] --> termOp [ - member variable op : PythonParser::OperatorType; ];; - - ( factOp=factOp) factor=factor | power=power --> factor ;; - - PLUS [: (*yynode)->op = PythonParser::UnaryPlusOp; :] - | MINUS [: (*yynode)->op = PythonParser::UnaryMinusOp; :] - | TILDE [: (*yynode)->op = PythonParser::UnaryTildeOp ; :] --> factOp [ - member variable op : PythonParser::OperatorType; ];; - - ( atom=atom ) - (#trailer=trailer)* ( DOUBLESTAR factor=factor | 0 ) --> power ;; - - LPAREN ( yield=yieldExpr | - ( testlist=testlist ( genFor=genFor | 0 ) ) | 0 [: (*yynode)->listmaker = create(); :] ) RPAREN - | LBRACKET ( listmaker=listmaker | 0 [: (*yynode)->listmaker = create(); :] ) RBRACKET - | LBRACE dictmaker=dictmaker RBRACE - | BACKTICK codeexpr=codeexpr BACKTICK - | atomIdentifierName=IDENTIFIER - | number=number - | (#stringliteral=STRINGLITERAL)+ --> atom ;; - - value=INTEGER [: (*yynode)->numType = PythonParser::IntegerNumeric; :] - | value=FLOAT [: (*yynode)->numType = PythonParser::FloatNumeric; :] - | value=IMAGNUM [: (*yynode)->numType = PythonParser::ImaginaryNumeric; :] --> number [ - member variable numType: PythonParser::NumericType; ];; - - ( #listTest=test ( COMMA [: if (yytoken == Token_RBRACKET) { break; } :] #listTest=test )* | 0) --> listMakerTest ;; - - listMakerTest=listMakerTest (listFor=listFor | 0) --> listmaker ;; - - LAMBDA ( lambdaVarargslist=varargslist | 0 ) COLON lambdaTest=test --> lambdaDef ;; - - LPAREN ( trailerArglist=arglist | 0 ) RPAREN | LBRACKET subscriptlist=subscriptlist RBRACKET | DOT trailerDotName=IDENTIFIER --> trailer ;; - - #subscript=subscript ( COMMA [: (*yynode)->hasComma = true; if (yytoken == Token_RBRACKET) { break; } :] - #subscript=subscript )* --> subscriptlist [ - member variable hasComma: bool; ] ;; - --- Sub Scripts Check if the curent token is not a COLON it should be a test --- If a COLON it skips the 'test'. if the next token is not RBRACKET or COMMA after test it can be a COLON. --- Else it ends. - ELLIPSIS [: (*yynode)->isEllipsis = true; :] - | ( ?[: yytoken != Token_COLON :] begin=test | 0 ) - ( ?[: yytoken == Token_RBRACKET || yytoken == Token_COMMA :] 0 - | COLON [: (*yynode)->hasColon = true; :] ( end=test | 0 ) - ( COLON [: (*yynode)->hasColon = true; :] - ( step=test | 0 ) | 0 ) ) --> subscript - [: (*yynode)->isEllipsis = false; - (*yynode)->hasColon = false; :] - [ member variable isEllipsis: bool; - member variable hasColon: bool; ] ;; - - #expr=expr - ( COMMA [: if (yytoken == Token_IN || yytoken == Token_SEMICOLON || yytoken == Token_LINEBREAK ) { break; } :] - #expr=expr )* --> exprlist ;; - - #tests=test ( COMMA [: if( yytoken == Token_COLON || yytoken == Token_SEMICOLON || yytoken == Token_RPAREN || yytoken == Token_LINEBREAK) {break;} :] - #tests=test )* --> testlist ;; - - #test=test ( ( COMMA #test=test )+ ( COMMA | 0 ) | 0 ) --> testlistSafe ;; - - (#keyList=test COLON #valueList=test | 0) ( COMMA [: if (yytoken == Token_RBRACE) { break; } :] - #keyList=test COLON #valueList=test )* --> dictmaker ;; - - CLASS className=IDENTIFIER ( ( LPAREN (testlist=testlist | 0) RPAREN ) | 0 ) COLON classSuite=suite --> classdef ;; - - #arguments=argument - ( COMMA [: if(yytoken == Token_RPAREN || yytoken == Token_STAR || yytoken == Token_DOUBLESTAR) { break; } :] #arguments=argument)* --> plainArgumentsList ;; - - (argListBegin=plainArgumentsList | 0) - ( - ( STAR arglistStar=test (?[: LA(1).kind != Token_RPAREN :] COMMA DOUBLESTAR arglistDoublestar=test | 0) - | DOUBLESTAR arglistDoublestar=test) - | 0 ) --> arglist ;; - - argumentTest=test ( EQUAL argumentEqualTest=test - | ?[: yytoken == Token_FOR :] genFor=genFor - | ?[: yytoken == Token_RPAREN || yytoken == Token_STAR || yytoken == Token_DOUBLESTAR || yytoken == Token_COMMA :] 0 ) --> argument ;; - - listFor=listFor | listIf=listIf --> listIter ;; - - FOR exprlist=exprlist IN testlistSafe=testlistSafe ( listIter=listIter | 0 ) --> listFor ;; - - IF test=test ( listIter=listIter | 0 ) --> listIf ;; - - genFor=genFor - | genIf=genIf --> genIter ;; - - FOR exprlist=exprlist IN test=test ( genIter=genIter | 0 ) --> genFor ;; - - IF test=test ( genIter=genIter | 0 ) --> genIf ;; - - #test=test ( COMMA #test=test )* --> codeexpr ;; - ------------------------------------------------------------------ --- Code segments copied to the implementation (.cpp) file. --- If existent, kdevelop-pg's current syntax requires this block --- to occur at the end of the file. ------------------------------------------------------------------ - -[: -#include "pythonlexer.h" -#include -#include - -namespace PythonParser -{ - -void Parser::tokenize( const QString& contents ) -{ - mContents = contents; - kDebug() << mContents; - Lexer lexer( this, contents ); - int kind = Parser::Token_EOF; - - do - { - kind = lexer.nextTokenKind(); - if ( !kind ) // when the lexer returns 0, the end of file is reached - { - //Parser::Token &tt = tokenStream->next(); - //tt.kind = Parser::Token_LINEBREAK; - //tt.begin = lexer.tokenBegin(); - //tt.end = lexer.tokenEnd(); - kind = Parser::Token_EOF; - } - Parser::Token &t = tokenStream->next(); - t.begin = lexer.tokenBegin(); - t.end = lexer.tokenEnd(); - t.kind = kind; -// if( mDebug ) - kDebug() << kind << tokenText(t.begin,t.end) << t.begin << t.end; - } - while ( kind != Parser::Token_EOF ); - - yylex(); // produce the look ahead token -} - - -QString Parser::tokenText(qint64 begin, qint64 end) -{ - return mContents.mid(begin,end-begin+1); -} - - -void Parser::reportProblem( Parser::ProblemType type, const QString& message ) -{ - if (type == Error) - kDebug() << "** ERROR:" << message; - else if (type == Warning) - kDebug() << "** WARNING:" << message; - else if (type == Info) - kDebug() << "** Info:" << message; -} - - -// custom error recovery -void Parser::expectedToken(int /*expected*/, qint64 /*where*/, const QString& name) -{ - reportProblem( Parser::Error, QString("Expected token \"%1\"").arg(name)); -} - -void Parser::expectedSymbol(int /*expectedSymbol*/, const QString& name) -{ - qint64 line; - qint64 col; - qint64 index = tokenStream->index()-1; - Token &token = tokenStream->token(index); - kDebug() << "token starts at:" << token.begin; - kDebug() << "index is:" << index; - tokenStream->startPosition(index, &line, &col); - QString tokenValue = tokenText(token.begin, token.end); - reportProblem( Parser::Error, - QString("Expected symbol \"%1\" (current token: \"%2\" [%3] at line: %4 col: %5)") - .arg(name) - .arg(token.kind != 0 ? tokenValue : "EOF") - .arg(token.kind) - .arg(line) - .arg(col)); -} - -void Parser::setDebug( bool debug ) -{ - mDebug = debug; -} - - - -} // end of namespace cool - -:] - --- kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on - diff --git a/parser/pythonlexer.cpp b/parser/pythonlexer.cpp deleted file mode 100644 index c951aac..0000000 --- a/parser/pythonlexer.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/* KDevelop QMake Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "pythonlexer.h" - -#include -#include -#include -#include -#include "pythonparser.h" -#include -#include - -#include "kwcheck.h" -#include "numbercheck.h" - -namespace PythonParser -{ - -/* - * @TODO: COMMENT all the stuff, really needed - */ - -Lexer::Lexer( Parser* _parser, const QString& content ): - m_content( content ), m_parser( _parser ), - m_curpos( 0 ), m_contentSize( m_content.size() ), - m_tokenBegin( 0 ), m_tokenEnd( 0 ), m_openParenNum( 0 ) -{ - pushState( ErrorState ); - pushState( DefaultState ); - pushState( IndentState ); - pushIndentation( 0 ); -} - -int Lexer::state() const -{ - return m_state.top(); -} - -void Lexer::pushState( int state ) -{ - m_state.push( state ); -} - -void Lexer::popState() -{ - m_state.pop(); -} - -int Lexer::indentation() const -{ - return m_indentation.top(); -} - -void Lexer::pushIndentation( int indentation ) -{ - m_indentation.push( indentation ); -} - -void Lexer::popIndentation() -{ - m_indentation.pop(); -} - -int Lexer::nextTokenKind() -{ - kDebug() << "nextTokenKind called"; - int token = Parser::Token_INVALID; - if ( m_curpos >= m_contentSize ) - { - if( indentation() > 0 ) - { - popIndentation(); - m_tokenEnd = m_curpos; - return Parser::Token_DEDENT; - } - m_tokenBegin = -1; - m_tokenEnd = -1; - return 0; - } - QChar* it = m_content.data(); - it += m_curpos; - if( state() == IndentState ) - { - // Check wether we need to indent or dedent, this is quite complicated. - // Especially because it contains 3 exit points and one point that resets - // the current position and it and then lets the rest of the code run - if( !it->isSpace() && it->unicode() != '#' && indentation() > 0 ) - { - // No whitespace at the start of the line, so we need to create - // as many DEDENT tokens as we have indenations in the stack - token = Parser::Token_DEDENT; - m_tokenBegin = m_curpos; - m_tokenEnd = m_curpos; - popIndentation(); - return token; - }else if( it->isSpace() ) - { - // We've got indentation, lets see how much - m_tokenBegin = m_curpos; - int spacecount = 0; - while( it->isSpace() && it->unicode() != '\n' && m_curpos < m_contentSize ) - { - if( it->unicode() == '\t' ) - { - spacecount += 8-( spacecount % 8 ); - } else if( it->unicode() != '\f' && it->unicode() != '\n' ) - { - spacecount++; - }else if( it->unicode() == '#' ) - { - // find the next newline position and return a linebreak token for it - do - { - it++; - m_curpos++; - }while( it->unicode() != '\n' && m_curpos < m_contentSize ); - m_tokenBegin = m_curpos; - m_tokenEnd = m_curpos; - createNewline( m_curpos ); - m_curpos++; - return Parser::Token_LINEBREAK; - } - it++; - m_curpos++; - } - if( it->unicode() == '#' ) - { - // Ooops, whitespace and then a #, this is a plain comment line, only create - // a newline token for this - do - { - it++; - m_curpos++; - }while( it->unicode() != '\n' && m_curpos < m_contentSize ); - m_tokenBegin = m_curpos; - m_tokenEnd = m_curpos; - createNewline( m_curpos ); - m_curpos++; - return Parser::Token_LINEBREAK; - }else if( it->unicode() == '\n' ) - { - m_tokenBegin = m_curpos; - m_tokenEnd = m_curpos; - createNewline( m_curpos ); - m_curpos++; - return Parser::Token_LINEBREAK; - } - it--; - m_tokenEnd = m_curpos-1; - - if( spacecount > indentation() ) - { - // We have more indentation, so we need to create an INDENT token - pushIndentation( spacecount ); - popState(); - token = Parser::Token_INDENT; - return token; - }else if( spacecount == indentation() ) - { - // Don't do anything, same indentation level so we ignore the whitespace and move on with lexing the forthcoming text - popState(); - m_curpos = m_tokenBegin; - it = m_content.data() + m_curpos; - }else - { - // We've got a dedentation, so create a DEDENT token - // If the next indentation level is still larger than what we've - // counted we'll do another try on the next call, else we'll go into - // usual parsing next time we enter this function - popIndentation(); - token = Parser::Token_DEDENT; - if( spacecount < indentation() ) - { - m_curpos = m_tokenBegin; - }else - { - popState(); - } - return token; - } - }else - { - // Either we have a comment, which will be ignored in the next part - // or we have a non-whitespace character and no more indentation - // level to create a DEDENT token for. Thus get out of IndentState - // and do normal parsing - popState(); - } - } - switch ( state() ) - { - case DefaultState: - it = ignoreWhitespaceAndComments( it ); - if( it->unicode() == '\\' && (it+1)->unicode() == '\n' ) - { - createNewline(m_curpos+1); - m_curpos += 2; - it += 2; - } - m_tokenBegin = m_curpos; - if( isStringStart( it ) ) - { - if( it->toLower().unicode() == 'u' ) - { - it++; - m_curpos++; - } - if( it->toLower().unicode() == 'r' ) - { - it++; - m_curpos++; - } - QChar* quotestart = it++; - m_curpos++; - if( it->unicode() == quotestart->unicode() && (it+1)->unicode() == quotestart->unicode() ) - { - it += 2; - m_curpos += 2; - // read everything until we find 3 consecutive chars that are - // equal to quotestart - while( m_curpos < m_contentSize - 3 && !( it->unicode() == quotestart->unicode() - && (it+1)->unicode() == quotestart->unicode() - && (it+2)->unicode() == quotestart->unicode()) ) - { - if( it->unicode() == '\\' ) - { - it += 2; - m_curpos += 2; - }else - { - it++; - m_curpos++; - } - } - // We checked these 2 characters and they're either the last 2 chars - // or they're the closing '' or "" and thus we always consume them too - it += 2; - m_curpos += 2; - token = Parser::Token_STRINGLITERAL; - }else - { - // single quote so read until the end of line or closing quote - // if eol is found return invalid token - while( it->unicode() != quotestart->unicode() && it->unicode() != '\n' && m_curpos < m_contentSize ) - { - if( it->unicode() == '\\' ) - { - it += 2; - m_curpos += 2; - }else - { - it++; - m_curpos++; - } - } - if( it->unicode() == '\n' ) - { - // We've read to the newline, now return to the last string character - m_curpos--; - } - token = Parser::Token_STRINGLITERAL; - } - //Go to the next character, it still points to the end of the literal - it++; - if( it->isSpace() ) - { - // read more space until we find a non-space character - // if the non-space char is a quote again set the current position - // to the char before this non-space character, so next time - // we lex the next string. This allows for string concatenation - QChar* space = it; - int count = 0; - while( space->isSpace() && (m_curpos+count) < m_contentSize ) - { - space++; - count++; - } - // Now check wether this is a string begin, if so we immediately - // return the token and set its endPos, we also set the parsing - // position to the next quote and ignore the newline that might exist - // between the strings - if( space->unicode() == '\'' || space->unicode() == '"' ) - { - m_tokenEnd = m_curpos; - m_curpos += count; - return token; - } - } - }else if( it->isLetter() || it->unicode() == '_' ) - { - QChar* start = it; - do{ - it++; - m_curpos++; - }while( m_curpos < m_contentSize - && ( it->isLetterOrNumber() || it->unicode() == '_' ) ); - //Adjust current position to the last character that belongs to the identifier/keyword - m_curpos--; - token = checkForKeyword( start, m_curpos-m_tokenBegin+1 ); - }else if( it->isNumber() || ( it->unicode() == '.' && (it+1)->isNumber() ) ) - { - // all numeric literals start with a number or a . followed by a number - do{ - it++; - m_curpos++; - }while( m_curpos < m_contentSize - && ( it->isNumber() || it->unicode() == 'e' - || it->unicode() == 'E' || it->unicode() == 'j' - || it->unicode() == 'J' || it->unicode() == '.' - || it->unicode() == 'A' || it->unicode() == 'B' - || it->unicode() == 'C' || it->unicode() == 'D' - || it->unicode() == 'F' || it->unicode() == 'a' - || it->unicode() == 'b' || it->unicode() == 'c' - || it->unicode() == 'd' || it->unicode() == 'f' - || it->unicode() == 'l' || it->unicode() == 'L' - || it->unicode() == 'X' || it->unicode() == 'x' ) ); - //Adjust position to last character that belongs to the number - m_curpos--; - token = getTokenForNumberString( m_content.mid( m_tokenBegin, m_curpos-m_tokenBegin+1 ) ); - }else - { - QChar* ch2 = m_curpos < m_contentSize ? it + 1 : 0; - QChar* ch3 = m_curpos < m_contentSize ? it + 2 : 0; - kDebug() << "it: " << it->toAscii(); - switch ( it->unicode() ) - { - case '\n': - pushState( IndentState ); - createNewline( m_curpos ); - token = Parser::Token_LINEBREAK; - break; - case '(': - m_openParenNum++; - token = Parser::Token_LPAREN; - break; - case ')': - m_openParenNum--; - token = Parser::Token_RPAREN; - break; - case '{': - m_openParenNum++; - token = Parser::Token_LBRACE; - break; - case '}': - m_openParenNum--; - token = Parser::Token_RBRACE; - break; - case '[': - m_openParenNum++; - token = Parser::Token_LBRACKET; - break; - case ']': - m_openParenNum--; - token = Parser::Token_RBRACKET; - break; - case ',': - token = Parser::Token_COMMA; - break; - case ';': - token = Parser::Token_SEMICOLON; - break; - case ':': - token = Parser::Token_COLON; - break; - case '.': - if( ch2 && ch3 && ch2->unicode() == '.' && ch3->unicode() == '.' ) - { - m_curpos += 2; - token = Parser::Token_ELLIPSIS; - }else - { - token = Parser::Token_DOT; - } - break; - case '`': - token = Parser::Token_BACKTICK; - break; - case '@': - token = Parser::Token_AT; - break; - case '*': - if( ch2 && ch3 && ch2->unicode() == '*' && ch3->unicode() == '=') - { - m_curpos += 2; - token = Parser::Token_DOUBLESTAREQ; - }else if( ch2 && ch2->unicode() == '*' ) - { - m_curpos++; - token = Parser::Token_DOUBLESTAR; - }else if( ch2 && ch2->unicode() == '=') - { - m_curpos++; - token = Parser::Token_STAREQ; - }else - { - token = Parser::Token_STAR; - } - break; - case '=': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_ISEQUAL; - }else - { - token = Parser::Token_EQUAL; - } - break; - case '+': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_PLUSEQ; - }else - { - token = Parser::Token_PLUS; - } - break; - case '-': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_MINUSEQ; - }else - { - token = Parser::Token_MINUS; - } - break; - case '~': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_TILDEEQ; - }else - { - token = Parser::Token_TILDE; - } - break; - case '/': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_SLASHEQ; - }else if( ch2 && ch3 && ch2->unicode() == '/' && ch3->unicode() == '=' ) - { - m_curpos += 2; - token = Parser::Token_DOUBLESLASHEQ; - }else if( ch2 && ch2->unicode() == '/' ) - { - m_curpos++; - token = Parser::Token_DOUBLESLASH; - }else - { - token = Parser::Token_SLASH; - } - break; - case '%': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_MODULOEQ; - }else - { - token = Parser::Token_MODULO; - } - break; - case '&': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_ANDEQ; - }else - { - token = Parser::Token_BITAND; - } - break; - case '<': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_LESSEQ; - }else if( ch2 && ch3 && ch2->unicode() == '<' && ch3->unicode() == '=' ) - { - m_curpos += 2; - token = Parser::Token_LSHIFTEQ; - }else if( ch2 && ch2->unicode() == '<' ) - { - m_curpos++; - token = Parser::Token_LSHIFT; - }else if( ch2 && ch2->unicode() == '>' ) - { - m_curpos++; - token = Parser::Token_UNEQUAL; - }else - { - token = Parser::Token_LESS; - } - break; - case '>': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_GREATEREQ; - }else if( ch2 && ch3 && ch2->unicode() == '>' && ch3->unicode() == '=' ) - { - m_curpos += 2; - token = Parser::Token_RSHIFTEQ; - }else if( ch2 && ch2->unicode() == '>' ) - { - m_curpos++; - token = Parser::Token_RSHIFT; - }else - { - token = Parser::Token_GREATER; - } - break; - case '|': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_OREQ; - }else - { - token = Parser::Token_BITOR; - }; - break; - case '^': - token = Parser::Token_BITXOR; - break; - case '!': - if( ch2 && ch2->unicode() == '=' ) - { - m_curpos++; - token = Parser::Token_UNEQUAL; - } - break; - default: - break; - } - } - m_tokenEnd = m_curpos; - break; - default: - token = Parser::Token_INVALID; - break; - } - if ( m_curpos >= m_contentSize ) - { - if( indentation() > 0 ) - { - popIndentation(); - m_tokenEnd = m_curpos; - return Parser::Token_DEDENT; - } - m_tokenBegin = -1; - m_tokenEnd = -1; - return 0; - } - m_tokenEnd = m_curpos; - m_curpos++; - return token; -} - -qint64 Lexer::tokenBegin() const -{ - return m_tokenBegin; -} - -qint64 Lexer::tokenEnd() const -{ - return m_tokenEnd; -} - -QChar* Lexer::ignoreWhitespaceAndComments( QChar* it ) -{ - // Ignore whitespace and comments, but preserve the newline if we're not inside a parenthesis - bool isComment = false; - while ( m_curpos < m_contentSize - && ( it->isSpace() || isComment || it->unicode() == '#' || - ( it->unicode() == '\\' && m_openParenNum && (it+1)->unicode() == '\n' ) - ) - && ( it->unicode() != '\n' || m_openParenNum > 0 ) ) - { - if( it->unicode() == '#' ) - { - isComment = true; - }else if( it->unicode() == '\n' && m_openParenNum > 0 ) - { - isComment = false; - createNewline( m_curpos ); - } - ++it; - ++m_curpos; - } - return it; -} - -void Lexer::createNewline( int curpos ) -{ - if( m_parser ) - m_parser->tokenStream->locationTable()->newline( curpos ); -} - -bool Lexer::isStringStart( QChar* it ) -{ - if( it->unicode() == '\'' || it->unicode() == '"' ) - { - return true; - } - if( it->toLower().unicode() == 'u' && m_curpos < m_contentSize - 1 ) - { - if( (it+1)->unicode() == '\'' || (it+1)->unicode() == '"' ) - { - return true; - }else if( (it+1)->toLower().unicode() == 'r' && m_curpos < m_contentSize - 2 ) - { - if( (it+2)->unicode() == '\'' || (it+2)->unicode() == '"' ) - { - return true; - } - } - } - if( it->toLower().unicode() == 'r' && m_curpos < m_contentSize - 1 ) - { - if( (it+1)->unicode() == '\'' || (it+1)->unicode() == '"' ) - { - return true; - } - } - return false; -} - -} diff --git a/parser/pythonlexer.h b/parser/pythonlexer.h deleted file mode 100644 index d3a7b27..0000000 --- a/parser/pythonlexer.h +++ /dev/null @@ -1,81 +0,0 @@ -/* KDevelop Python Support - * - * Copyright 2007 Andreas Pakulat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef PYTHONLEXER_H -#define PYTHONLEXER_H - -#include -#include - -#include "parserexport.h" - -class QString; - -namespace PythonParser -{ - -class Parser; - -class KDEVPYTHONPARSER_EXPORT Lexer { -public: - Lexer(Parser* _parser, const QString& contents); - - int nextTokenKind(); - qint64 tokenBegin() const; - qint64 tokenEnd() const; - -private: - QString m_content; - Parser* m_parser; - int m_curpos; - int m_contentSize; - qint64 m_tokenBegin; - qint64 m_tokenEnd; - unsigned int m_openParenNum; - - int state() const; - void pushState(int state); - void popState(); - - int indentation() const; - void pushIndentation( int indentation ); - void popIndentation(); - - QChar* ignoreWhitespaceAndComments( QChar* it ); - void createNewline( int curpos ); - bool isStringStart( QChar* ); - - QStack m_state; - QStack m_indentation; - enum State - { - ErrorState = -1, - DefaultState = 0, - IndentState = 1 - }; - - -}; - -} - -#endif - -// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on From 45d1dc0a618e60c5037dbddee11d1f45c985f70f Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 2 Nov 2010 23:29:18 +0100 Subject: [PATCH 059/118] Fixed document encoding --- pythonpythonparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index b302526..b0e9b0b 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -72,4 +72,4 @@ def generic_visit(self, node): except Exception as e: sys.stderr.write(str(e.lineno) + ':' + str(e.offset)) else: - sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True)) + sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True, encoding='UTF-8')) From 46ee45475e8671d6a4fe800a35f329041bcdae1e Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 3 Nov 2010 01:18:09 +0100 Subject: [PATCH 060/118] Some completioncontext skeleton, and hopefully fixed parser loop problem --- .../pythoncodecompletioncontext.cpp | 12 +++++++++-- codecompletion/pythoncodecompletioncontext.h | 8 +++++++ parser/astbuilder.cpp | 6 ++++++ pythonparsejob.cpp | 21 ++++++++++--------- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 10fee9c..20b8e59 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -15,6 +15,7 @@ #include #include #include +#include using namespace KDevelop; @@ -53,8 +54,15 @@ QList PythonCodeCompletionContext::completionItems(bo PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth): CodeCompletionContext(context, text, position, depth) { - + kDebug() << text; + QRegExp importfile("(.*)[\\s]*import[\\s]$"); + importfile.setMinimal(true); + QRegExp memberaccess(""); + bool is_importfile = importfile.exactMatch(text); + + kDebug() << "Is import file: " << is_importfile; +// Q_ASSERT(false); } -} \ No newline at end of file +} diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index fa6c8be..8a35074 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -12,8 +12,16 @@ namespace Python { class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop::CodeCompletionContext { public: + enum CompletionContextType { + ImportFileCompletion, + MemberAccessCompletion, + DefaultCompletion + }; + PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); + + CompletionContextType m_operation; }; } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 362ffd7..98babf3 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -174,6 +174,11 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok // Everything else (stuff between tags, comments...) is ignored else continue; } + if ( xmlast->hasError() ) { + kWarning() << "Invalid XML file: " << xmlast->errorString(); + kWarning() << "Aborting!"; + Q_ASSERT(false); + } } bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes) @@ -833,6 +838,7 @@ void AstBuilder::populateAst() case Ast::AliasAstType: currentAbstractNode = populateAliasAst(currentAbstractNode, currentAttributes); break; case Ast::ExpressionAstType: break; // ok case Ast::StatementAstType: break; // ok + default: kWarning() << "Unsupported AST type: " << currentAbstractNode->astType; break; } } } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 3cf01fb..5e367cd 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -128,19 +128,21 @@ void ParseJob::run() IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); - ParsingEnvironmentFile* file = 0; { DUChainWriteLocker lock(DUChain::lock()); - file = new ParsingEnvironmentFile(document()); - file->setModificationRevision(contents().modification); - IndexedString langstring("python"); - file->setLanguage(langstring); - m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); - m_duContext->setType(KDevelop::DUContext::Global); - DUChain::self()->addDocumentChain(m_duContext); + m_duContext = DUChain::self()->chainForDocument(document()); + if ( ! m_duContext ) { + IndexedString langstring("python"); + ParsingEnvironmentFile* file = new ParsingEnvironmentFile(document()); + m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); + m_duContext->setType(KDevelop::DUContext::Global); + DUChain::self()->addDocumentChain(m_duContext); + } m_duContext->clearProblems(); - lock.unlock(); + + ParsingEnvironmentFilePointer file = m_duContext->parsingEnvironmentFile(); + file->setModificationRevision(contents().modification); } // 2) parse @@ -184,7 +186,6 @@ void ParseJob::run() } { DUChainWriteLocker lock(DUChain::lock()); - file->setModificationRevision(contents().modification); } } else From ac3033658213c1df6a04682e095c6043f11bf59d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 3 Nov 2010 23:04:22 +0100 Subject: [PATCH 061/118] Basic and screwy import autocompletion --- codecompletion/importfileitem.cpp | 10 +++ codecompletion/importfileitem.h | 10 ++- .../pythoncodecompletioncontext.cpp | 79 +++++++++++++++---- codecompletion/pythoncodecompletioncontext.h | 12 +++ 4 files changed, 90 insertions(+), 21 deletions(-) diff --git a/codecompletion/importfileitem.cpp b/codecompletion/importfileitem.cpp index 4e17478..1614a3c 100644 --- a/codecompletion/importfileitem.cpp +++ b/codecompletion/importfileitem.cpp @@ -1,6 +1,15 @@ #include "importfileitem.h" +#include +#include + +using namespace KDevelop; namespace Python { + +ImportFileItem::ImportFileItem(const KDevelop::IncludeItem& include): AbstractIncludeFileCompletionItem< NavigationWidget >(include) +{ + +} ImportFileItem::~ImportFileItem() { @@ -10,6 +19,7 @@ ImportFileItem::~ImportFileItem() void ImportFileItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) { kDebug() << "ImportFileItem executed"; + document->replaceText(word, moduleName); } diff --git a/codecompletion/importfileitem.h b/codecompletion/importfileitem.h index 31b8300..567a2d8 100644 --- a/codecompletion/importfileitem.h +++ b/codecompletion/importfileitem.h @@ -3,6 +3,7 @@ #include #include "navigationwidget.h" +#include namespace Python { @@ -12,13 +13,14 @@ class ImportFileItem : public IncludeFileItemBase { public: - ImportFileItem(const KDevelop::IncludeItem& include) - : IncludeFileItemBase(include) {}; + ImportFileItem(const KDevelop::IncludeItem& include); virtual ~ImportFileItem(); virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); + QString moduleName; + KDevelop::IProject* fromProject; }; -#endif // IMPORTFILEITEM_H +} -} \ No newline at end of file +#endif // IMPORTFILEITEM_H \ No newline at end of file diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 20b8e59..41f8a55 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -27,28 +27,73 @@ QList PythonCodeCompletionContext::completionItems(bo { QList items; - QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); - Declaration* currentDeclaration; - int count = declarations.length(); - for ( int i = 0; i < count; i++ ) { - currentDeclaration = declarations.at(i).first; - DeclarationPointer ptr(currentDeclaration); - items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(ptr) ); + if ( m_operation == PythonCodeCompletionContext::ImportFileCompletion ) { + m_maxFolderScanDepth = 1; + foreach ( ImportFileItem* item, includeFileItems() ) { + item->includeItem.name = QString(item->moduleName + " (from " + KUrl::relativeUrl(item->fromProject->folder(), item->includeItem.basePath) + ")"); + items << CompletionTreeItemPointer( item ); + } + } + else { + QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); + + Declaration* currentDeclaration; + int count = declarations.length(); + for ( int i = 0; i < count; i++ ) { + currentDeclaration = declarations.at(i).first; + DeclarationPointer ptr(currentDeclaration); + items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(ptr) ); + } } - kDebug() << "Adding testing item to completion list"; - + return items; +} + +QList PythonCodeCompletionContext::includeFileItems() { + QList items; foreach (IProject* project, ICore::self()->projectController()->projects() ) { - foreach ( ProjectFolderItem* folder, project->foldersForUrl( KUrl(project->folder().url()) ) ) { - foreach ( ProjectFileItem* file, folder->fileList() ) { - IncludeItem item; - item.name = file->fileName(); - items << CompletionTreeItemPointer( new ImportFileItem(item) ); - } + foreach ( KDevelop::ProjectFolderItem* folder, project->foldersForUrl( KUrl(project->folder().url()) ) ) { + m_folderStack.push(folder); + items << fileItemsForFolder(folder, project); + m_folderStack.pop(); } } - + return items; +} + +QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop::ProjectFolderItem* folder, IProject* project) +{ + if ( ! folder ) return QList(); + if ( m_maxFolderScanDepth < m_folderStack.count() ) return QList(); + QList items; + foreach ( KDevelop::ProjectFolderItem* folder, folder->folderList() ) { + if ( ! folder ) continue; + m_folderStack.push(folder); + kDebug() << "Scanning for include items: " << folder->folderName(); + items << fileItemsForFolder(folder, project); + + // Add the folder + IncludeItem* folderItem = new IncludeItem(); + folderItem->basePath = m_folderStack.top()->url(); + folderItem->isDirectory = true; + ImportFileItem* importFolderItem = new ImportFileItem(*folderItem); + importFolderItem->fromProject = project; + importFolderItem->moduleName = folder->folderName(); + items << importFolderItem; + + // Add all sub-items and folders + foreach ( ProjectFileItem* file, folder->fileList() ) { + if ( ! file->fileName().endsWith(".py") || file->fileName() == "__init__.py" ) continue; + IncludeItem* item = new IncludeItem(); + item->basePath = m_folderStack.top()->url(); + ImportFileItem* importItem = new ImportFileItem(*item); + importItem->moduleName = file->fileName().replace(".py", ""); + importItem->fromProject = project; + items << importItem; + } + m_folderStack.pop(); + } return items; } @@ -59,7 +104,7 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex importfile.setMinimal(true); QRegExp memberaccess(""); bool is_importfile = importfile.exactMatch(text); - + if ( is_importfile ) m_operation = PythonCodeCompletionContext::ImportFileCompletion; kDebug() << "Is import file: " << is_importfile; // Q_ASSERT(false); } diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 8a35074..95aa874 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -4,9 +4,16 @@ #include #include "pythoncompletionexport.h" #include +#include +#include using namespace KDevelop; +namespace KDevelop { + class IProject; + class ProjectFolderItem; +} + namespace Python { class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop::CodeCompletionContext @@ -20,8 +27,13 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); + QList includeFileItems(); + QList fileItemsForFolder(KDevelop::ProjectFolderItem* folder, KDevelop::IProject* project); CompletionContextType m_operation; + QStack m_folderStack; + int m_maxFolderScanDepth; + QString m_searchingForModule; }; } From 6dd960fe868348a870d3af9404cb91845e6b65e6 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 4 Nov 2010 01:52:35 +0100 Subject: [PATCH 062/118] Screwy, but working (!) import file completion --- .../pythoncodecompletioncontext.cpp | 67 +++++++++++++++++-- codecompletion/pythoncodecompletioncontext.h | 7 +- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 41f8a55..7e394de 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -27,7 +27,6 @@ QList PythonCodeCompletionContext::completionItems(bo { QList items; - if ( m_operation == PythonCodeCompletionContext::ImportFileCompletion ) { m_maxFolderScanDepth = 1; foreach ( ImportFileItem* item, includeFileItems() ) { @@ -35,6 +34,13 @@ QList PythonCodeCompletionContext::completionItems(bo items << CompletionTreeItemPointer( item ); } } + else if ( m_operation == PythonCodeCompletionContext::ImportSubCompletion ) { + kDebug() << "Stuff found for completion: " << findFilesForName(m_subForModule); + foreach ( ImportFileItem* item, findFilesForName(m_subForModule) ) { + item->includeItem.name = QString(item->moduleName + " (from " + KUrl::relativeUrl(item->fromProject->folder(), item->includeItem.basePath) + ")"); + items << CompletionTreeItemPointer( item ); + } + } else { QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); @@ -47,9 +53,21 @@ QList PythonCodeCompletionContext::completionItems(bo } } + m_searchingForModule.clear(); + m_subForModule.clear(); + return items; } +QList< ImportFileItem* > PythonCodeCompletionContext::findFilesForName(const QString& name) +{ + kDebug() << "Name: " << name; + QStringList resolvedName = name.split("."); + m_maxFolderScanDepth = resolvedName.length() + 1; + m_searchingForModule = resolvedName; + return includeFileItems(); +} + QList PythonCodeCompletionContext::includeFileItems() { QList items; foreach (IProject* project, ICore::self()->projectController()->projects() ) { @@ -65,7 +83,19 @@ QList PythonCodeCompletionContext::includeFileItems() { QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop::ProjectFolderItem* folder, IProject* project) { if ( ! folder ) return QList(); + + kDebug() << m_maxFolderScanDepth << m_folderStack.count() << m_searchingForModule; + if ( m_maxFolderScanDepth < m_folderStack.count() ) return QList(); + + if ( m_searchingForModule.length() > 0 && folder->url() != project->folder().url() ) { + if ( m_searchingForModule.length() >= m_folderStack.count() && m_searchingForModule.at(m_folderStack.count() - 2) != folder->folderName() ) { + kDebug() << "Skip: " << m_searchingForModule.at(m_folderStack.count() - 2) << m_searchingForModule << m_folderStack.count() - 2 << folder->folderName(); + return QList(); + } + kDebug() << "USE: " << m_searchingForModule.at(m_folderStack.count() - 2) << m_searchingForModule << m_folderStack << folder->folderName(); + } + QList items; foreach ( KDevelop::ProjectFolderItem* folder, folder->folderList() ) { if ( ! folder ) continue; @@ -73,6 +103,15 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: kDebug() << "Scanning for include items: " << folder->folderName(); items << fileItemsForFolder(folder, project); + // only add items when at right level + if ( m_searchingForModule.length() != 0 && m_maxFolderScanDepth != m_folderStack.count() ) { + kDebug() << "CONTINUE: " << m_maxFolderScanDepth << m_folderStack.count(); + m_folderStack.pop(); + continue; + } + kDebug() << "ADD: " << m_maxFolderScanDepth << m_folderStack.count(); + kDebug() << "adding files and folders from directory " << folder->folderName(); + // Add the folder IncludeItem* folderItem = new IncludeItem(); folderItem->basePath = m_folderStack.top()->url(); @@ -100,11 +139,31 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth): CodeCompletionContext(context, text, position, depth) { kDebug() << text; - QRegExp importfile("(.*)[\\s]*import[\\s]$"); + + QRegExp importsub("(.*)\n[\\s]*from(.*)import[\\s]*$"); + importsub.setMinimal(true); + bool is_importSub = importsub.exactMatch(text); + if ( is_importSub ) { + QStringList for_module_match = importsub.capturedTexts(); + QString for_module = for_module_match.last().replace(" ", ""); + kDebug() << for_module_match; + m_operation = PythonCodeCompletionContext::ImportSubCompletion; + m_subForModule = for_module; + return; + } + + QRegExp importfile("(.*)\n[\\s]*import[\\s]*$"); importfile.setMinimal(true); - QRegExp memberaccess(""); bool is_importfile = importfile.exactMatch(text); - if ( is_importfile ) m_operation = PythonCodeCompletionContext::ImportFileCompletion; + QRegExp fromimport("(.*)\n[\\s]*from[\\s]*$"); + fromimport.setMinimal(true); + bool is_fromimport = fromimport.exactMatch(text); + if ( is_importfile || is_fromimport ) { + m_operation = PythonCodeCompletionContext::ImportFileCompletion; + return; + } + + QRegExp memberaccess(""); kDebug() << "Is import file: " << is_importfile; // Q_ASSERT(false); } diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 95aa874..8a0f1e3 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -22,18 +22,21 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: enum CompletionContextType { ImportFileCompletion, MemberAccessCompletion, - DefaultCompletion + DefaultCompletion, + ImportSubCompletion }; PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); virtual QList< KDevelop::CompletionTreeItemPointer > completionItems(bool& abort, bool fullCompletion = true); QList includeFileItems(); QList fileItemsForFolder(KDevelop::ProjectFolderItem* folder, KDevelop::IProject* project); + QList findFilesForName(const QString& name); CompletionContextType m_operation; QStack m_folderStack; int m_maxFolderScanDepth; - QString m_searchingForModule; + QStringList m_searchingForModule; + QString m_subForModule; }; } From 50bebb6270fc09b31b103abe8075eeb7d8aa3938 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 5 Nov 2010 01:37:11 +0100 Subject: [PATCH 063/118] Restructured parsejob.cpp, fixing several stupid bugs --- .../pythoncodecompletioncontext.cpp | 85 +++++++++++----- codecompletion/pythoncodecompletioncontext.h | 3 +- duchain/declarationbuilder.cpp | 2 + parser/astbuilder.cpp | 11 +-- parser/astbuilder.h | 1 + parser/parsesession.cpp | 1 + parser/parsesession.h | 4 + parser/pythondriver.cpp | 2 + parser/pythondriver.h | 7 ++ pythonparsejob.cpp | 96 +++++++++++-------- 10 files changed, 136 insertions(+), 76 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 7e394de..b3f10b2 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -26,8 +26,12 @@ namespace Python { QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { QList items; + DUChainReadLocker lock(DUChain::lock()); - if ( m_operation == PythonCodeCompletionContext::ImportFileCompletion ) { + if ( m_operation == PythonCodeCompletionContext::NoCompletion ) { + + } + else if ( m_operation == PythonCodeCompletionContext::ImportFileCompletion ) { m_maxFolderScanDepth = 1; foreach ( ImportFileItem* item, includeFileItems() ) { item->includeItem.name = QString(item->moduleName + " (from " + KUrl::relativeUrl(item->fromProject->folder(), item->includeItem.basePath) + ")"); @@ -48,8 +52,11 @@ QList PythonCodeCompletionContext::completionItems(bo int count = declarations.length(); for ( int i = 0; i < count; i++ ) { currentDeclaration = declarations.at(i).first; + kDebug() << "Adding item: " << currentDeclaration->identifier().identifier().str(); DeclarationPointer ptr(currentDeclaration); - items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(ptr) ); + NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(ptr, KDevelop::CodeCompletionContext::Ptr(this)); + kDebug() << item->declaration().data()->identifier().identifier().str(); + items << CompletionTreeItemPointer(item); } } @@ -83,10 +90,12 @@ QList PythonCodeCompletionContext::includeFileItems() { QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop::ProjectFolderItem* folder, IProject* project) { if ( ! folder ) return QList(); + bool continue_recursion = true; + bool do_recursion = true; kDebug() << m_maxFolderScanDepth << m_folderStack.count() << m_searchingForModule; - if ( m_maxFolderScanDepth < m_folderStack.count() ) return QList(); + if ( m_maxFolderScanDepth - 1 < m_folderStack.count() ) continue_recursion = false; // we dont offer foo.bar.baz.bang.bar if there's only one dot in the address by now if ( m_searchingForModule.length() > 0 && folder->url() != project->folder().url() ) { if ( m_searchingForModule.length() >= m_folderStack.count() && m_searchingForModule.at(m_folderStack.count() - 2) != folder->folderName() ) { @@ -100,17 +109,25 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: foreach ( KDevelop::ProjectFolderItem* folder, folder->folderList() ) { if ( ! folder ) continue; m_folderStack.push(folder); - kDebug() << "Scanning for include items: " << folder->folderName(); - items << fileItemsForFolder(folder, project); + if ( continue_recursion ) { + kDebug() << "Scanning for include items: " << folder->folderName(); + items << fileItemsForFolder(folder, project); + } // only add items when at right level if ( m_searchingForModule.length() != 0 && m_maxFolderScanDepth != m_folderStack.count() ) { kDebug() << "CONTINUE: " << m_maxFolderScanDepth << m_folderStack.count(); - m_folderStack.pop(); - continue; + if ( m_searchingForModule.length() < m_folderStack.count() ) do_recursion = false; // don't add items from here, we're too deep + else { + // we're not yet deep enough, so don't even add the folder + m_folderStack.pop(); + continue; + } + } + else { + kDebug() << "ADD: " << m_maxFolderScanDepth << m_folderStack.count(); + kDebug() << "adding files and folders from directory " << folder->folderName(); } - kDebug() << "ADD: " << m_maxFolderScanDepth << m_folderStack.count(); - kDebug() << "adding files and folders from directory " << folder->folderName(); // Add the folder IncludeItem* folderItem = new IncludeItem(); @@ -121,30 +138,40 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: importFolderItem->moduleName = folder->folderName(); items << importFolderItem; - // Add all sub-items and folders - foreach ( ProjectFileItem* file, folder->fileList() ) { - if ( ! file->fileName().endsWith(".py") || file->fileName() == "__init__.py" ) continue; - IncludeItem* item = new IncludeItem(); - item->basePath = m_folderStack.top()->url(); - ImportFileItem* importItem = new ImportFileItem(*item); - importItem->moduleName = file->fileName().replace(".py", ""); - importItem->fromProject = project; - items << importItem; + if ( continue_recursion && do_recursion ) { + // Add all sub-items and folders + foreach ( ProjectFileItem* file, folder->fileList() ) { + if ( ! file->fileName().endsWith(".py") || file->fileName() == "__init__.py" ) continue; + IncludeItem* item = new IncludeItem(); + item->basePath = m_folderStack.top()->url(); + ImportFileItem* importItem = new ImportFileItem(*item); + importItem->moduleName = file->fileName().replace(".py", ""); + importItem->fromProject = project; + items << importItem; + } } m_folderStack.pop(); } return items; } -PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth): CodeCompletionContext(context, text, position, depth) +PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, + int depth): CodeCompletionContext(context, text, position, depth) { - kDebug() << text; + QString currentLine = "\n" + text.split("\n").last(); // we'll only look at the last line, as 99% of python statements are limited to one line + kDebug() << "Doing auto-completion context scan for: " << currentLine; QRegExp importsub("(.*)\n[\\s]*from(.*)import[\\s]*$"); importsub.setMinimal(true); - bool is_importSub = importsub.exactMatch(text); - if ( is_importSub ) { - QStringList for_module_match = importsub.capturedTexts(); + bool is_importSub = importsub.exactMatch(currentLine); + QRegExp importsub2("(.*)\n[\\s]*(from(.*)|import(.*))\\.$"); + importsub2.setMinimal(true); + bool is_importSub2 = importsub2.exactMatch(currentLine); + if ( is_importSub || is_importSub2 ) { + QStringList for_module_match; + if ( is_importSub ) for_module_match = importsub.capturedTexts(); + else for_module_match = importsub2.capturedTexts(); + QString for_module = for_module_match.last().replace(" ", ""); kDebug() << for_module_match; m_operation = PythonCodeCompletionContext::ImportSubCompletion; @@ -154,15 +181,23 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex QRegExp importfile("(.*)\n[\\s]*import[\\s]*$"); importfile.setMinimal(true); - bool is_importfile = importfile.exactMatch(text); + bool is_importfile = importfile.exactMatch(currentLine); QRegExp fromimport("(.*)\n[\\s]*from[\\s]*$"); fromimport.setMinimal(true); - bool is_fromimport = fromimport.exactMatch(text); + bool is_fromimport = fromimport.exactMatch(currentLine); if ( is_importfile || is_fromimport ) { m_operation = PythonCodeCompletionContext::ImportFileCompletion; return; } + QRegExp noCompletionPossible("(.*)\n[\\s]*(class|def)[\\s]*$"); + noCompletionPossible.setMinimal(true); + bool is_noCompletionPossible = noCompletionPossible.exactMatch(currentLine); + if ( is_noCompletionPossible ) { + m_operation = PythonCodeCompletionContext::NoCompletion; + return; + } + QRegExp memberaccess(""); kDebug() << "Is import file: " << is_importfile; // Q_ASSERT(false); diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 8a0f1e3..19755fc 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -23,7 +23,8 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: ImportFileCompletion, MemberAccessCompletion, DefaultCompletion, - ImportSubCompletion + ImportSubCompletion, + NoCompletion }; PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index b1b9b30..5264f9d 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -92,12 +92,14 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Ast* node) return 0; } Identifier* id = currentVariableDefinition->identifier; + Q_ASSERT(id); return visitVariableDeclaration(id, currentVariableDefinition); } Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* originalAst) { DUChainWriteLocker lock(DUChain::lock()); + Q_ASSERT(node); QList existingDeclarations; CursorInRevision until = editorFindRange(node, node).end; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 98babf3..bd6fd24 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -46,11 +46,6 @@ namespace Python CodeAst* AstBuilder::parse(KUrl filename, const QString& contents) { - { - DUChainWriteLocker lock(DUChain::lock()); - m_topContext = DUChain::self()->chainForDocument(filename); - Q_ASSERT(m_topContext); - } CodeAst* ast = parseXmlAst(getXmlForFile(filename, contents)); return ast; } @@ -96,10 +91,8 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) p->setSeverity(KDevelop::ProblemData::Error); { DUChainWriteLocker lock(DUChain::lock()); - m_topContext->clearProblems(); - m_topContext->addProblem(p); - DUChain::self()->updateContextForUrl(IndexedString(filename), m_topContext->features()); - kDebug() << "Added problem: " << m_topContext->problems(); + m_problems.clear(); + m_problems.append(p); } kWarning() << "Parse Error: " << result; return "0"; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index dc682e8..44378e7 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -48,6 +48,7 @@ class AstBuilder public: CodeAst* parse(KUrl filename, const QString& contents); + QList m_problems; private: CodeAst* parseXmlAst(QString xml); QString getXmlForFile(KUrl filename, const QString& contents); diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index d8d5aa5..1f669c6 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -67,6 +67,7 @@ QPair ParseSession::parse( Python::CodeAst* ast ) driver.setCurrentDocument(m_currentDocument.toUrl()); driver.setContent(m_contents); QPair result = driver.parse(ast); + m_problems = driver.m_problems; return result; } diff --git a/parser/parsesession.h b/parser/parsesession.h index a6cfc23..09cd022 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -33,6 +33,8 @@ #include "ast.h" #include "kurl.h" +#include + using namespace KDevelop; typedef QPair SimpleUse; @@ -56,6 +58,8 @@ class KDEVPYTHONPARSER_EXPORT ParseSession QPair parse( Python::CodeAst* ast ); + QList m_problems; + void mapAstUse(Ast* node, const SimpleUse& use) { Q_UNUSED(node); diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index ef98020..6f4ac3f 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -78,6 +78,8 @@ QPair Driver::parse( Python::CodeAst* ast ) matched.first = pythonparser.parse(m_currentDocument, m_content); matched.second = matched.first ? true : false; // check wether an AST was returned and react accordingly + m_problems = pythonparser.m_problems; + if( matched.second ) { kDebug() << "Sucessfully parsed"; diff --git a/parser/pythondriver.h b/parser/pythondriver.h index 405c285..af463f2 100644 --- a/parser/pythondriver.h +++ b/parser/pythondriver.h @@ -24,6 +24,10 @@ #include #include "parserexport.h" #include + +#include + + namespace KDevPG { class MemoryPool; @@ -50,6 +54,9 @@ class KDEVPYTHONPARSER_EXPORT Driver void setTokenStream( KDevPG::TokenStream* ); void setMemoryPool( KDevPG::MemoryPool* ); void setCurrentDocument(KUrl url); + + QList m_problems; + private: QString m_content; bool m_debug; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 5e367cd..d565905 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -107,17 +107,17 @@ void ParseJob::run() { kDebug(); + LanguageSupport* lang = python(); + ILanguage* ilang = lang->language(); + QReadLocker parselock(ilang->parseLock()); + UrlParseLock urlLock(document()); + if ( m_url != *internalFunctionsFile ) checkInternalFunctionsParsed(); if (abortRequested() || !python() || !python()->language()) { kWarning() << "Language support is NULL"; return abortJob(); } - - LanguageSupport* lang = python(); - ILanguage* ilang = lang->language(); - QReadLocker parselock(ilang->parseLock()); - UrlParseLock urlLock(document()); readContents(); m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); @@ -128,22 +128,22 @@ void ParseJob::run() IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); - { - DUChainWriteLocker lock(DUChain::lock()); - - m_duContext = DUChain::self()->chainForDocument(document()); - if ( ! m_duContext ) { - IndexedString langstring("python"); - ParsingEnvironmentFile* file = new ParsingEnvironmentFile(document()); - m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); - m_duContext->setType(KDevelop::DUContext::Global); - DUChain::self()->addDocumentChain(m_duContext); - } - m_duContext->clearProblems(); - - ParsingEnvironmentFilePointer file = m_duContext->parsingEnvironmentFile(); - file->setModificationRevision(contents().modification); - } +// { +// DUChainWriteLocker lock(DUChain::lock()); +// +// m_duContext = DUChain::self()->chainForDocument(document()); +// if ( ! m_duContext ) { +// IndexedString langstring("python"); +// ParsingEnvironmentFile* file = new ParsingEnvironmentFile(document()); +// m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); +// m_duContext->setType(KDevelop::DUContext::Global); +// DUChain::self()->addDocumentChain(m_duContext); +// } +// m_duContext->clearProblems(); +// +// ParsingEnvironmentFilePointer file = m_duContext->parsingEnvironmentFile(); +// file.data()->setModificationRevision(contents().modification); +// } // 2) parse QPair parserResults = m_session->parse(m_ast); @@ -162,7 +162,7 @@ void ParseJob::run() editor.setParseSession(m_session); - m_duContext = builder.build(filename, m_ast, m_duContext); + m_duContext = builder.build(filename, m_ast); setDuChain(m_duContext); UseBuilder usebuilder( &editor ); @@ -170,32 +170,46 @@ void ParseJob::run() kDebug() << "----Parsing Succeded---***"; -// { -// DUChainReadLocker lock( DUChain::lock() ); -// DumpChain dump; -// dump.dump( m_duContext ); -// } - - { - if ( m_parent && m_parent->codeHighlighting() ) { - kDebug() << m_duContext.data(); - DUChainReadLocker rlock(DUChain::lock()); - KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); - hl->highlightDUChain(m_duContext); - } - } - { - DUChainWriteLocker lock(DUChain::lock()); + if ( m_parent && m_parent->codeHighlighting() ) { + kDebug() << m_duContext.data(); + DUChainReadLocker lock(DUChain::lock()); + KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); + hl->highlightDUChain(m_duContext); } + + DUChainWriteLocker lock(DUChain::lock()); + ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); + parsingEnvironmentFile->setModificationRevision(contents().modification); + DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); } else { kWarning() << "===Failed==="; -// cleanupSmartRevision(); + { + DUChainReadLocker lock(DUChain::lock()); + m_duContext = DUChain::self()->chainForDocument(document()); + } + if ( m_duContext ) { + DUChainWriteLocker lock(DUChain::lock()); + m_duContext->clearProblems(); + m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); + } + else { + DUChainWriteLocker lock(DUChain::lock()); + ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); + static const IndexedString langString("python"); + file->setModificationRevision(contents().modification); + file->setLanguage(langString); + m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); + DUChain::self()->addDocumentChain(m_duContext); + } + DUChainWriteLocker lock(DUChain::lock()); + foreach ( ProblemPointer p, m_session->m_problems ) { + kDebug() << "Added problem to context"; + m_duContext->addProblem(p); + } setDuChain(m_duContext); - return abortJob(); } -// cleanupSmartRevision(); } ParseSession *ParseJob::parseSession() const From c92b0790d331de5a6221f41658bedbae9f6dbf9b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 5 Nov 2010 20:50:15 +0100 Subject: [PATCH 064/118] Fixed the folder auto completion --- .../pythoncodecompletioncontext.cpp | 23 ++++++++++++++++--- codecompletion/pythoncodecompletioncontext.h | 3 +++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index b3f10b2..bf3dd0e 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -89,7 +89,12 @@ QList PythonCodeCompletionContext::includeFileItems() { QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop::ProjectFolderItem* folder, IProject* project) { - if ( ! folder ) return QList(); + kDebug() << " +++++ Processing folder: " << folder->folderName(); + kDebug() << "current folder stack count " << m_folderStack.count(); + if ( ! folder ) { + m_dontAddMe = true; + return QList(); + } bool continue_recursion = true; bool do_recursion = true; @@ -100,11 +105,18 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: if ( m_searchingForModule.length() > 0 && folder->url() != project->folder().url() ) { if ( m_searchingForModule.length() >= m_folderStack.count() && m_searchingForModule.at(m_folderStack.count() - 2) != folder->folderName() ) { kDebug() << "Skip: " << m_searchingForModule.at(m_folderStack.count() - 2) << m_searchingForModule << m_folderStack.count() - 2 << folder->folderName(); + m_dontAddMe = true; + return QList(); + } + else if ( m_searchingForModule.at(m_folderStack.count() - 2) != folder->folderName() ) { + m_dontAddMe = true; return QList(); } kDebug() << "USE: " << m_searchingForModule.at(m_folderStack.count() - 2) << m_searchingForModule << m_folderStack << folder->folderName(); } + kDebug() << " >>>>> For directory " << folder->folderName() << " : " << "doing recursion: " << do_recursion << "; continuing downwards: " << continue_recursion; + QList items; foreach ( KDevelop::ProjectFolderItem* folder, folder->folderList() ) { if ( ! folder ) continue; @@ -112,6 +124,11 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: if ( continue_recursion ) { kDebug() << "Scanning for include items: " << folder->folderName(); items << fileItemsForFolder(folder, project); + if ( m_dontAddMe ) { + m_dontAddMe = false; + m_folderStack.pop(); + continue; + } } // only add items when at right level @@ -131,7 +148,7 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: // Add the folder IncludeItem* folderItem = new IncludeItem(); - folderItem->basePath = m_folderStack.top()->url(); + folderItem->basePath = folder->url(); folderItem->isDirectory = true; ImportFileItem* importFolderItem = new ImportFileItem(*folderItem); importFolderItem->fromProject = project; @@ -143,7 +160,7 @@ QList PythonCodeCompletionContext::fileItemsForFolder(KDevelop: foreach ( ProjectFileItem* file, folder->fileList() ) { if ( ! file->fileName().endsWith(".py") || file->fileName() == "__init__.py" ) continue; IncludeItem* item = new IncludeItem(); - item->basePath = m_folderStack.top()->url(); + item->basePath = folder->url(); ImportFileItem* importItem = new ImportFileItem(*item); importItem->moduleName = file->fileName().replace(".py", ""); importItem->fromProject = project; diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 19755fc..5af62a3 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -38,6 +38,9 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: int m_maxFolderScanDepth; QStringList m_searchingForModule; QString m_subForModule; + +private: + bool m_dontAddMe; }; } From 73c1d2acdbaed6ab64c900198ab0abfe39f617a5 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 5 Nov 2010 20:54:32 +0100 Subject: [PATCH 065/118] Fixed import regex matching; now just context importing is missing --- codecompletion/pythoncodecompletioncontext.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index bf3dd0e..5fb1232 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -189,8 +189,13 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex if ( is_importSub ) for_module_match = importsub.capturedTexts(); else for_module_match = importsub2.capturedTexts(); - QString for_module = for_module_match.last().replace(" ", ""); kDebug() << for_module_match; + + QString for_module; + if ( is_importSub ) for_module = for_module_match.last().replace(" ", ""); + else for_module = for_module_match[3].replace(" ", ""); + + kDebug() << "Matching against module name: " << for_module_match; m_operation = PythonCodeCompletionContext::ImportSubCompletion; m_subForModule = for_module; return; From 2515844f500a2bbf739fad8d39812884ef181b54 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 6 Nov 2010 01:22:21 +0100 Subject: [PATCH 066/118] First part of "import " context importing --- duchain/CMakeLists.txt | 1 + duchain/contextbuilder.cpp | 46 +++++++++++++++++++++++++++++++++++++- duchain/contextbuilder.h | 4 ++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index e970cd3..bfa403a 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -18,6 +18,7 @@ kde4_add_library( kdev4pythonduchain SHARED ${duchain_SRCS} ) target_link_libraries( kdev4pythonduchain ${KDE4_KDECORE_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} + ${KDEVPLATFORM_PROJECT_LIBRARIES} ${KDE4_KTEXTEDITOR_LIBS} ${KDEVPLATFORM_INTERFACES_LIBRARIES} kdev4pythonparser diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index b7e91c3..5c0d4d8 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -34,6 +34,11 @@ #include #include #include +#include +#include +#include +#include +#include using namespace KDevelop; @@ -147,7 +152,46 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) void ContextBuilder::visitCode(CodeAst* node) { AstDefaultVisitor::visitCode(node); DUChainWriteLocker lock(DUChain::lock()); - currentContext()->addImportedParentContext(DUChain::self()->chainForDocument(KUrl("/home/sven/projects/kde4/python/documentation/test.py"))); + TopDUContext* internal = DUChain::self()->chainForDocument(KUrl("/home/sven/projects/kde4/python/documentation/test.py")); + if ( internal ) { + currentContext()->addImportedParentContext(internal); + } +} + +KUrl ContextBuilder::findModulePath(const QString& name) +{ + KUrl currentPath = currentContext()->url().toUrl(); + Q_ASSERT(currentPath.url().length()); + kDebug() << "Got URL: " << currentPath.url(); + IProject* currentProject = ICore::self()->projectController()->findProjectForUrl(currentPath); + if ( ! currentProject ) { + kError() << "Cannot import module contexts without a project opened."; + return KUrl(); + } + foreach ( ProjectFileItem* file, currentProject->filesForUrl(currentPath) ) { + kDebug() << "File: " << file->fileName(); + } + QStringList modulePath = name.split("."); + return KUrl(); +} + +void ContextBuilder::visitImportFrom(ImportFromAst* node) +{ + Python::AstDefaultVisitor::visitImportFrom(node); +} + +void ContextBuilder::visitImport(ImportAst* node) +{ + foreach ( AliasAst* name, node->names ) { + // for "import ... as", use the as thingy, use the module name otherwise + Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; + + KUrl moduleFilePath = findModulePath(name->name->value); + continue; + TopDUContext* moduleChain = DUChain::self()->chainForDocument(KUrl(moduleFilePath)); + currentContext()->addImportedParentContext(moduleChain); + } + Python::AstDefaultVisitor::visitImport(node); } void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 5c5a8b6..a073f24 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -47,6 +47,8 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public public: void setEditor(PythonEditorIntegrator* editor); void setEditor(ParseSession* session); + + KUrl findModulePath(const QString& name); protected: PythonEditorIntegrator* editor() const; @@ -67,6 +69,8 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public // virtual void visitIf( IfAst* node ); virtual void visitArguments(ArgumentsAst* node); virtual void visitCode(CodeAst* node); + virtual void visitImport(ImportAst* node); + virtual void visitImportFrom(ImportFromAst* node); static PythonEditorIntegrator* m_editor; From f2c6dc96d05112dadaf6b611cdfdce7191e437ef Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 7 Nov 2010 01:45:39 +0100 Subject: [PATCH 067/118] Importing contexts from the current directory now works (simplest case) --- duchain/contextbuilder.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 5c0d4d8..bd581d4 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -160,18 +160,27 @@ void ContextBuilder::visitCode(CodeAst* node) { KUrl ContextBuilder::findModulePath(const QString& name) { + QStringList modulePath = name.split("."); + KUrl currentPath = currentContext()->url().toUrl(); Q_ASSERT(currentPath.url().length()); - kDebug() << "Got URL: " << currentPath.url(); + kDebug() << " >>>>>>>>> Got URL: " << currentPath.upUrl().url(KUrl::RemoveTrailingSlash); + IProject* currentProject = ICore::self()->projectController()->findProjectForUrl(currentPath); if ( ! currentProject ) { kError() << "Cannot import module contexts without a project opened."; return KUrl(); } - foreach ( ProjectFileItem* file, currentProject->filesForUrl(currentPath) ) { - kDebug() << "File: " << file->fileName(); + + // easiest case: current directory + KUrl filename(currentPath.directory(KUrl::AppendTrailingSlash) + modulePath.first() + ".py"); + kDebug() << "filename url: " << filename; + if ( currentProject->filesForUrl(filename).length() > 0 ) { + ProjectFileItem* result = currentProject->filesForUrl(filename).first(); + kDebug() << "Found! " << result->url(); + return result->url(); } - QStringList modulePath = name.split("."); + return KUrl(); } @@ -187,9 +196,12 @@ void ContextBuilder::visitImport(ImportAst* node) Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; KUrl moduleFilePath = findModulePath(name->name->value); - continue; - TopDUContext* moduleChain = DUChain::self()->chainForDocument(KUrl(moduleFilePath)); - currentContext()->addImportedParentContext(moduleChain); + if ( ! moduleFilePath.isValid() ) continue; + else { + DUChainWriteLocker lock(DUChain::lock()); + TopDUContext* moduleChain = DUChain::self()->chainForDocument(KUrl(moduleFilePath)); + currentContext()->addImportedParentContext(moduleChain); + } } Python::AstDefaultVisitor::visitImport(node); } From d348b221248290a3f077122a250daa592e813dd6 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 7 Nov 2010 15:46:09 +0100 Subject: [PATCH 068/118] Fixed problem with "raw" statements, and many small adjustments --- .../pythoncodecompletioncontext.cpp | 6 ++++ codecompletion/pythoncodecompletionmodel.cpp | 6 ++++ codecompletion/pythoncodecompletionworker.cpp | 6 ++++ duchain/contextbuilder.cpp | 4 ++- duchain/contextbuilder.h | 4 +++ duchain/declarationbuilder.cpp | 29 +++++++++++++++++-- duchain/declarationbuilder.h | 6 ++++ parser/ast.h | 2 +- parser/astbuilder.cpp | 11 +++++-- parser/astbuilder.h | 1 + parser/astdefaultvisitor.cpp | 9 +++++- parser/astdefaultvisitor.h | 1 + parser/astvisitor.cpp | 2 +- parser/parsesession.cpp | 1 + pythonpythonparser.py | 7 +++++ 15 files changed, 87 insertions(+), 8 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 5fb1232..15b0672 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -1,3 +1,9 @@ +/* + * This file is part of KDevelop + * Copyright 2010 Sven Brauch + * Licensed under the GNU GPL + * */ + #include "pythoncodecompletioncontext.h" #include diff --git a/codecompletion/pythoncodecompletionmodel.cpp b/codecompletion/pythoncodecompletionmodel.cpp index acb2c98..278a21c 100644 --- a/codecompletion/pythoncodecompletionmodel.cpp +++ b/codecompletion/pythoncodecompletionmodel.cpp @@ -1,3 +1,9 @@ +/* + * This file is part of KDevelop + * Copyright 2010 Sven Brauch + * Licensed under the GNU GPL + * */ + #include "pythoncodecompletionmodel.h" #include "pythoncodecompletionworker.h" #include "ktexteditor/view.h" diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp index 80ade49..e367eb9 100644 --- a/codecompletion/pythoncodecompletionworker.cpp +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -1,3 +1,9 @@ +/* + * This file is part of KDevelop + * Copyright 2010 Sven Brauch + * Licensed under the GNU GPL + * */ + #include "pythoncodecompletionworker.h" #include "pythoncodecompletionmodel.h" #include "pythoncodecompletioncontext.h" diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index bd581d4..1cbf3dd 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -200,7 +200,9 @@ void ContextBuilder::visitImport(ImportAst* node) else { DUChainWriteLocker lock(DUChain::lock()); TopDUContext* moduleChain = DUChain::self()->chainForDocument(KUrl(moduleFilePath)); - currentContext()->addImportedParentContext(moduleChain); + contextsForModules.insert(name->name->value, TopDUContextPointer(moduleChain)); + kDebug() << "Added " << name->name->value << " to the module chain map"; +// currentContext()->addImportedParentContext(moduleChain); } } Python::AstDefaultVisitor::visitImport(node); diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index a073f24..fc6a152 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -36,6 +36,8 @@ using namespace KDevelop; namespace Python { + +typedef QPair moduleContextTuple; class PythonEditorIntegrator; class ParseSession; @@ -71,6 +73,8 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitCode(CodeAst* node); virtual void visitImport(ImportAst* node); virtual void visitImportFrom(ImportFromAst* node); + + QMap contextsForModules; static PythonEditorIntegrator* m_editor; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 5264f9d..756fba4 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -1,6 +1,7 @@ /***************************************************************************** * Copyright (c) 2007 Piyush verma * - * Copyright 2007 Andreas Pakulat * + * Copyright 2007 Andreas Pakulat * + * Copyright 2010 Sven Brauch * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * @@ -39,6 +40,8 @@ #include #include +#include "contextbuilder.h" + #include "pythoneditorintegrator.h" #include "QtGlobal" @@ -115,9 +118,16 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); } else kDebug() << "Not updating existing declaration for " << node->value; +// dec->setType<>(); return dec; } +void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) +{ + if ( node->name ) visitVariableDeclaration(node->name); // except Error as + Python::AstDefaultVisitor::visitExceptionHandler(node); +} + void DeclarationBuilder::visitFor(ForAst* node) { if ( node->target->astType == Ast::NameAstType ) visitVariableDeclaration(node->target); @@ -131,10 +141,14 @@ void DeclarationBuilder::visitFor(ForAst* node) void DeclarationBuilder::visitImport(ImportAst* node) { - Python::AstDefaultVisitor::visitImport(node); + Python::ContextBuilder::visitImport(node); foreach ( AliasAst* name, node->names ) { + TopDUContextPointer contextptr = contextsForModules.value(name->asName ? name->asName->identifier->value : name->name->value); + kDebug() << "Chain for document: " << contextptr; + m_importContextsForImportStatement.push(contextptr); if ( name->asName ) visitVariableDeclaration(name->asName); else visitVariableDeclaration(name->name); + m_importContextsForImportStatement.clear(); } } @@ -230,6 +244,17 @@ void DeclarationBuilder::visitLambda( LambdaAst* node ) // closeDeclaration(); } +void DeclarationBuilder::visitCall(CallAst* node) +{ + foreach ( ExpressionAst* currentArgument, node->arguments ) { + NameAst* realArgument = dynamic_cast(currentArgument); + if ( realArgument ) { + visitVariableDeclaration(realArgument); // some_func(, ) + } + } + Python::AstDefaultVisitor::visitCall(node); +} + void DeclarationBuilder::visitArguments( ArgumentsAst* node ) { AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index acecb49..ecd0bff 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -32,6 +32,8 @@ namespace Python { + +typedef QPair moduleContextTuple; typedef KDevelop::AbstractDeclarationBuilder DeclarationBuilderBase; @@ -53,10 +55,14 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitImport(ImportAst* node); virtual void visitImportFrom(ImportFromAst* node); virtual void visitArguments(ArgumentsAst* node); + virtual void visitExceptionHandler(ExceptionHandlerAst* node); + virtual void visitCall(CallAst* node); Declaration* visitVariableDeclaration(Ast* node); Declaration* visitVariableDeclaration(Identifier* node, Ast* originalAst = 0); + QStack m_importContextsForImportStatement; + // virtual void visitIdentifierTarget( IdentifierTargetAst * node ); private: diff --git a/parser/ast.h b/parser/ast.h index 0bd780b..a4da656 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -200,7 +200,7 @@ class KDEVPYTHONPARSER_EXPORT Identifier : public Ast { class KDEVPYTHONPARSER_EXPORT CodeAst : public Ast { public: CodeAst(); - QList body; + QList body; }; /** Statement classes **/ diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index bd6fd24..9f802b4 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -431,7 +431,7 @@ AssignmentAst* AstBuilder::populateAssignmentAst(Ast* ast, const Python::stringD CodeAst* AstBuilder::populateCodeAst(Ast* ast, const Python::stringDictionary& currentAttributes) { CodeAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); return currentNode; } @@ -745,6 +745,13 @@ KeywordAst* AstBuilder::populateKeywordAst(Ast* ast, const Python::stringDiction return currentNode; } +ExpressionAst* AstBuilder::populateExpressionAst(Ast* ast, const stringDictionary& currentAttributes) +{ + ExpressionAst* currentNode = dynamic_cast(ast); + currentNode->value = resolveNode(currentAttributes.value("NR_value")); + return currentNode; +} + void AstBuilder::populateAst() { Ast* currentAbstractNode; @@ -829,7 +836,7 @@ void AstBuilder::populateAst() case Ast::ComprehensionAstType: currentAbstractNode = populateComprehensionAst(currentAbstractNode, currentAttributes); break; case Ast::ExceptionHandlerAstType: currentAbstractNode = populateExceptionHandlerAst(currentAbstractNode, currentAttributes); break; case Ast::AliasAstType: currentAbstractNode = populateAliasAst(currentAbstractNode, currentAttributes); break; - case Ast::ExpressionAstType: break; // ok + case Ast::ExpressionAstType: currentAbstractNode = populateExpressionAst(currentAbstractNode, currentAttributes); break; case Ast::StatementAstType: break; // ok default: kWarning() << "Unsupported AST type: " << currentAbstractNode->astType; break; } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 44378e7..e797a5e 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -134,6 +134,7 @@ class AstBuilder ArgumentsAst* populateArgumentsAst(Ast* ast, const stringDictionary& currentAttributes); IndexAst* populateIndexAst(Ast* ast, const stringDictionary& currentAttributes); ExceptionHandlerAst* populateExceptionHandlerAst(Ast* ast, const stringDictionary& currentAttributes); + ExpressionAst* populateExpressionAst(Ast* ast, const stringDictionary& currentAttributes); }; } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index ec28fc4..521f845 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * + * Copyright 2010 Sven Brauch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * @@ -43,11 +44,17 @@ void AstDefaultVisitor::visitString(StringAst* node) { Q_UNUSED(node); } void AstDefaultVisitor::visitCode(CodeAst* node) { kDebug() << "Visiting code"; - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { + kDebug() << statement->astType << Ast::ExpressionAstType; visitNode(statement); } } +void AstDefaultVisitor::visitExpression(ExpressionAst* node) +{ + visitNode(node->value); +} + void AstDefaultVisitor::visitAssertion(AssertionAst* node) { visitNode(node->condition); diff --git a/parser/astdefaultvisitor.h b/parser/astdefaultvisitor.h index af9c851..891c285 100644 --- a/parser/astdefaultvisitor.h +++ b/parser/astdefaultvisitor.h @@ -92,6 +92,7 @@ class KDEVPYTHONPARSER_EXPORT AstDefaultVisitor : public AstVisitor virtual void visitComprehension(ComprehensionAst* node); virtual void visitExceptionHandler(ExceptionHandlerAst* node); virtual void visitAlias(AliasAst* node); + virtual void visitExpression(ExpressionAst* node); }; } diff --git a/parser/astvisitor.cpp b/parser/astvisitor.cpp index 6f0abee..a108723 100644 --- a/parser/astvisitor.cpp +++ b/parser/astvisitor.cpp @@ -90,7 +90,7 @@ void AstVisitor::visitNode(Ast* node) case Ast::ComprehensionAstType: this->visitComprehension(dynamic_cast(node)); break; case Ast::ExceptionHandlerAstType: this->visitExceptionHandler(dynamic_cast(node)); break; case Ast::AliasAstType: this->visitAlias(dynamic_cast(node)); break; - case Ast::ExpressionAstType: break; + case Ast::ExpressionAstType: this->visitExpression(dynamic_cast(node)); break; case Ast::StatementAstType: break; } } diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index 1f669c6..afc00d4 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -1,6 +1,7 @@ /***************************************************************************** * Copyright (c) 2007 Andreas Pakulat * * Copyright (c) 2007 Piyush verma * + * Copyright 2010 Sven Brauch * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * diff --git a/pythonpythonparser.py b/pythonpythonparser.py index b0e9b0b..0d2f59d 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -1,4 +1,11 @@ #!/usr/bin/env python2.6 +# -*- coding: utf-8 -*- + +# +# This file is part of KDevelop +# Copyright 2010 Sven Brauch +# Licensed under the GNU GPL +# import ast from xml.dom.minidom import Document From 353b0904e5c8b2d73d7ac6aef1b026af023a0bf6 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 7 Nov 2010 23:24:14 +0100 Subject: [PATCH 069/118] Changed all body-lists from StatementAst to Ast, fixing bugs --- duchain/contextbuilder.cpp | 2 +- duchain/contextbuilder.h | 2 +- duchain/declarationbuilder.cpp | 66 ---------------------------------- parser/ast.h | 28 +++++++-------- parser/astbuilder.cpp | 28 +++++++-------- parser/astdefaultvisitor.cpp | 26 +++++++------- 6 files changed, 43 insertions(+), 109 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 1cbf3dd..fdbf14f 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -121,7 +121,7 @@ void ContextBuilder::addImportedContexts() } } -void ContextBuilder::openContextForStatementList( const QList& l ) +void ContextBuilder::openContextForStatementList( const QList& l ) { if ( l.count() > 0 ) { diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index fc6a152..3ad4513 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -94,7 +94,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public ReferencedTopDUContext m_topContext; private: - void openContextForStatementList( const QList& ); + void openContextForStatementList( const QList& ); QList m_importedParentContexts; }; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 756fba4..0f7c4d6 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -171,34 +171,6 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) visitNode(node->value); } -// void DeclarationBuilder::visitIdentifierTarget(IdentifierTargetAst* node) -// { -// Python::AstDefaultVisitor::visitIdentifierTarget(node); -// -// QList existingLocalDeclarations; -// -// { -// DUChainWriteLocker lock( DUChain::lock() ); -// RangeInRevision range = editorFindRange(node, node); -// CursorInRevision stopSearching = range.start; -// QualifiedIdentifier id = identifierForNode(node->identifier); -// existingLocalDeclarations = currentContext()->findLocalDeclarations(id.last(), stopSearching); -// } -// -// if ( ! existingLocalDeclarations.length() ) { -// Declaration *dec = openDeclaration( node->identifier, node); -// closeDeclaration(); -// { -// DUChainWriteLocker lock(DUChain::lock()); -// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); -// } -// } -// else { -// kDebug() << "Declaration does already exist, not updating" << node->identifier->identifier.toAscii(); -// } -// } - - void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; @@ -274,44 +246,6 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) } AstDefaultVisitor::visitArguments(node); - -// ContextBuilder::visitDefaultParameter( node ); -// // AbstractFunctionDeclaration* function = currentDeclaration(); -// AbstractFunctionDeclaration* function = dynamic_cast(currentDeclaration()); -// -// if( function ) -// { -// if( node->value ) -// { -// //Not sure what to do here, C++ simply adds the source code as default parameter, but that doesn't sound sane... -// } -// //simple case, we have an identifier parameter -// if( node->name->astType == Ast::IdentifierParameterPartAst ) -// { -// function->addDefaultParameter(IndexedString("foo")); -// kDebug() << function->defaultParametersSize(); -// -// Q_ASSERT(hasCurrentType()); -// FunctionType::Ptr type = currentType(); -// Q_ASSERT(type); -// -// kDebug() << type->toString(); -// -// // create a variable definition -// IdentifierParameterPartAst* identifierNode = dynamic_cast(node->name); -// Declaration* dec = openDeclaration( identifierNode->name, node); -// { -// DUChainWriteLocker lock(DUChain::lock()); -// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); -// type->addArgument(dec->abstractType()); -// } -// closeDeclaration(); -// -// } else if( node->name->astType == Ast::ListParameterPartAst ) -// { -// //complex case, a sublist, what to do?? -// } -// } } } diff --git a/parser/ast.h b/parser/ast.h index a4da656..b71d9e4 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -215,7 +215,7 @@ class KDEVPYTHONPARSER_EXPORT FunctionDefinitionAst : public StatementAst { Identifier* name; ArgumentsAst* arguments; QList decorators; - QList body; + QList body; }; class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { @@ -223,7 +223,7 @@ class KDEVPYTHONPARSER_EXPORT ClassDefinitionAst : public StatementAst { ClassDefinitionAst(Ast* parent); Identifier* name; QList baseClasses; - QList body; + QList body; QList decorators; }; @@ -259,24 +259,24 @@ class KDEVPYTHONPARSER_EXPORT ForAst : public StatementAst { ForAst(Ast* parent); ExpressionAst* target; ExpressionAst* iterator; - QList body; - QList orelse; + QList body; + QList orelse; }; class KDEVPYTHONPARSER_EXPORT WhileAst : public StatementAst { public: WhileAst(Ast* parent); ExpressionAst* condition; - QList body; - QList orelse; + QList body; + QList orelse; }; class KDEVPYTHONPARSER_EXPORT IfAst : public StatementAst { public: IfAst(Ast* parent); ExpressionAst* condition; - QList body; - QList orelse; + QList body; + QList orelse; }; class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { @@ -284,7 +284,7 @@ class KDEVPYTHONPARSER_EXPORT WithAst : public StatementAst { WithAst(Ast* parent); ExpressionAst* contextExpression; ExpressionAst* optionalVars; - QList body; + QList body; }; class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst { @@ -297,16 +297,16 @@ class KDEVPYTHONPARSER_EXPORT RaiseAst : public StatementAst { class KDEVPYTHONPARSER_EXPORT TryExceptAst : public StatementAst { public: TryExceptAst(Ast* parent); - QList body; + QList body; QList handlers; - QList orelse; + QList orelse; }; class KDEVPYTHONPARSER_EXPORT TryFinallyAst : public StatementAst { public: TryFinallyAst(Ast* parent); - QList body; - QList finalbody; + QList body; + QList finalbody; }; class KDEVPYTHONPARSER_EXPORT AssertionAst : public StatementAst { @@ -605,7 +605,7 @@ class KDEVPYTHONPARSER_EXPORT ExceptionHandlerAst : public Ast { ExceptionHandlerAst(Ast* parent); ExpressionAst* type; ExpressionAst* name; - QList body; + QList body; }; class KDEVPYTHONPARSER_EXPORT AliasAst : public Ast { diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 9f802b4..2f0d254 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -400,7 +400,7 @@ ClassDefinitionAst* AstBuilder::populateClassDefinitonAst(Ast* ast, const Python { ClassDefinitionAst* currentNode = dynamic_cast(ast); currentNode->baseClasses = resolveNodeList(currentAttributes.value("NRLST_bases")); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode); currentNode->name->startCol += 6; // TODO fix this! ;D @@ -412,7 +412,7 @@ FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const { FunctionDefinitionAst* currentNode = dynamic_cast(ast); currentNode->arguments = resolveNode(currentAttributes.value("NR_args")); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list")); currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode); currentNode->name->startCol += 4; // TODO fix this! ;D @@ -445,8 +445,8 @@ DeleteAst* AstBuilder::populateDeleteAst(Ast* ast, const Python::stringDictionar ForAst* AstBuilder::populateForAst(Ast* ast, const Python::stringDictionary& currentAttributes) { ForAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); - currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); currentNode->iterator = resolveNode(currentAttributes.value("NR_iter")); currentNode->target = resolveNode(currentAttributes.value("NR_target")); return currentNode; @@ -471,9 +471,9 @@ ReturnAst* AstBuilder::populateReturnAst(Ast* ast, const Python::stringDictionar IfAst* AstBuilder::populateIfAst(Ast* ast, const Python::stringDictionary& currentAttributes) { IfAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->condition = resolveNode(currentAttributes.value("NR_test")); - currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); return currentNode; } @@ -507,8 +507,8 @@ LambdaAst* AstBuilder::populateLambdaAst(Ast* ast, const Python::stringDictionar WhileAst* AstBuilder::populateWhileAst(Ast* ast, const Python::stringDictionary& currentAttributes) { WhileAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); - currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); currentNode->condition = resolveNode(currentAttributes.value("NR_test")); return currentNode; } @@ -556,17 +556,17 @@ RaiseAst* AstBuilder::populateRaiseAst(Ast* ast, const Python::stringDictionary& TryExceptAst* AstBuilder::populateTryExceptAst(Ast* ast, const Python::stringDictionary& currentAttributes) { TryExceptAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->handlers = resolveNodeList(currentAttributes.value("NRLST_handlers")); - currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); + currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse")); return currentNode; } TryFinallyAst* AstBuilder::populateTryFinallyAst(Ast* ast, const Python::stringDictionary& currentAttributes) { TryFinallyAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); - currentNode->finalbody = resolveNodeList(currentAttributes.value("NRLST_finalbody")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->finalbody = resolveNodeList(currentAttributes.value("NRLST_finalbody")); return currentNode; } @@ -646,7 +646,7 @@ ListComprehensionAst* AstBuilder::populateListComprehensionAst(Ast* ast, const P WithAst* AstBuilder::populateWithAst(Ast* ast, const Python::stringDictionary& currentAttributes) { WithAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->contextExpression = resolveNode(currentAttributes.value("NR_context_expr")); currentNode->optionalVars = resolveNode(currentAttributes.value("NR_optional_vars")); return currentNode; @@ -724,7 +724,7 @@ ArgumentsAst* AstBuilder::populateArgumentsAst(Ast* ast, const Python::stringDic ExceptionHandlerAst* AstBuilder::populateExceptionHandlerAst(Ast* ast, const Python::stringDictionary& currentAttributes) { ExceptionHandlerAst* currentNode = dynamic_cast(ast); - currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); + currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body")); currentNode->name = resolveNode(currentAttributes.value("NR_name")); currentNode->type = resolveNode(currentAttributes.value("NR_type")); return currentNode; diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 521f845..887f0ce 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -86,10 +86,10 @@ void AstDefaultVisitor::visitFor(ForAst* node) { visitNode(node->target); visitNode(node->iterator); - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } - foreach (StatementAst* statement, node->orelse) { + foreach (Ast* statement, node->orelse) { visitNode(statement); } } @@ -105,10 +105,10 @@ void AstDefaultVisitor::visitGeneratorExpression(GeneratorExpressionAst* node) void AstDefaultVisitor::visitIf(IfAst* node) { visitNode(node->condition); - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } - foreach (StatementAst* statement, node->orelse) { + foreach (Ast* statement, node->orelse) { visitNode(statement); } } @@ -190,23 +190,23 @@ void AstDefaultVisitor::visitSubscript(SubscriptAst* node) void AstDefaultVisitor::visitTryExcept(TryExceptAst* node) { - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } foreach (ExceptionHandlerAst* handler, node->handlers) { visitNode(handler); } - foreach (StatementAst* statement, node->orelse) { + foreach (Ast* statement, node->orelse) { visitNode(statement); } } void AstDefaultVisitor::visitTryFinally(TryFinallyAst* node) { - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } - foreach (StatementAst* statement, node->finalbody) { + foreach (Ast* statement, node->finalbody) { visitNode(statement); } } @@ -226,10 +226,10 @@ void AstDefaultVisitor::visitUnaryOperation(UnaryOperationAst* node) void AstDefaultVisitor::visitWhile(WhileAst* node) { visitNode(node->condition); - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } - foreach (StatementAst* statement, node->orelse) { + foreach (Ast* statement, node->orelse) { visitNode(statement); } } @@ -238,7 +238,7 @@ void AstDefaultVisitor::visitWith(WithAst* node) { visitNode(node->contextExpression); visitNode(node->optionalVars); - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } } @@ -267,7 +267,7 @@ void AstDefaultVisitor::visitExceptionHandler(ExceptionHandlerAst* node) { visitNode(node->type); visitNode(node->name); - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } } @@ -315,7 +315,7 @@ void AstDefaultVisitor::visitClassDefinition(ClassDefinitionAst* node) foreach (ExpressionAst* expression, node->baseClasses) { visitNode(expression); } - foreach (StatementAst* statement, node->body) { + foreach (Ast* statement, node->body) { visitNode(statement); } foreach (ExpressionAst* expression, node->decorators) { From db723eecdd947e4f06e52c76e2a132b94299877c Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 8 Nov 2010 00:09:24 +0100 Subject: [PATCH 070/118] Improved error reporting from parser --- duchain/contextbuilder.cpp | 47 +++----------------------------------- duchain/usebuilder.cpp | 38 ------------------------------ parser/astbuilder.cpp | 19 +++++++++++---- pythonpythonparser.py | 3 ++- 4 files changed, 19 insertions(+), 88 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index fdbf14f..3c80814 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -139,8 +139,7 @@ void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { openContext( node, DUContext::Class, identifierForNode( node->name ) ); addImportedContexts(); - visitNodeList( node->baseClasses ); - visitNodeList( node->body ); + Python::AstDefaultVisitor::visitClassDefinition(node); closeContext(); } @@ -228,29 +227,9 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) openContextForStatementList( node->body ); m_importedParentContexts.clear(); +// Python::AstDefaultVisitor::visitFunctionDefinition(node); } -// void ContextBuilder::visitFor( ForAst* node ) -// { -// DUContext* forctx = openContext( node, KDevelop::DUContext::Other ); -// visitNode(node->target); -// closeContext(); -// -// visitNode(node->iterator); -// -// m_importedParentContexts = QList() << forctx; -// openContextForStatementList( node->body ); -// openContextForStatementList( node->orelse ); -// m_importedParentContexts.clear(); -// } - -// void ContextBuilder::visitWhile( WhileAst* node ) -// { -// visitNode( node->condition ); -// openContextForStatementList( node->body ); -// openContextForStatementList( node->orelse ); -// } - void ContextBuilder::visitWith( WithAst * node ) { m_importedParentContexts = QList() << openContext( node->contextExpression, DUContext::Other ); @@ -259,27 +238,7 @@ void ContextBuilder::visitWith( WithAst * node ) openContextForStatementList( node->body ); m_importedParentContexts.clear(); + Python::AstDefaultVisitor::visitWith(node); } -// void ContextBuilder::visitTry( TryAst* node ) -// { -// kDebug() << "creating contexts for try"; -// openContextForStatementList( node->tryBody ); -// visitNodeList( node->exceptions ); -// openContextForStatementList( node->elseBody ); -// openContextForStatementList( node->finallyBody ); -// } - -// void ContextBuilder::visitIf( IfAst* node ) -// { -// visitNode( node->condition ); -// openContextForStatementList( node->body ); -// -// foreach ( StatementAst* current, node->body) { -// visitNode(current); -// } -// -// openContextForStatementList( node->orelse ); -// } - } diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 0e18ea0..3cc4891 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -66,44 +66,6 @@ void UseBuilder::visitName(NameAst* node) UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), declaration); // +1 for whatever reason } -// void UseBuilder::visitIdentifier(Identifier* node) -// { -// DUChainWriteLocker lock( DUChain::lock() ); -// QualifiedIdentifier id = identifierForNode(node); -// RangeInRevision range = editorFindRange(node, node); -// CursorInRevision until = range.start; -// QList allDeclarations = currentContext()->findDeclarations(id, until); -// -// kDebug() << " >> scanning " << node->value; -// kDebug() << " > searching for declaration until" << until.line << ":" << until.column << "; " << allDeclarations.length() << "Declarations found"; -// -// Declaration *globalDeclaration = 0; -// foreach ( Declaration* dec, allDeclarations ) { -// if ( dec->context() == dec->topContext() ) { -// kDebug() << "There's already a global declaration for" << node->value; -// globalDeclaration = dec; -// } -// } -// -// // if there's a local declaration, use the last one of those -// if ( allDeclarations.length() && allDeclarations.last()->context() != allDeclarations.last()->topContext() ) { -// kDebug() << " ++ Created a use of local declaration for node" << node->value; -// UseBuilderBase::newUse(node, allDeclarations.last()); -// } -// // otherwise, use the global one. -// // Note that the following is not allowed by python: a=3; def foo(): print a; a=7 -// else if ( globalDeclaration ) { -// kDebug() << " ++ Created a use of global declaration for node" << node->value; -// UseBuilderBase::newUse(node, globalDeclaration); -// } -// } - -// void UseBuilder::visitIdentifierTarget(IdentifierTargetAst* node) -// { -// kDebug() << "Target variable identifier: " << node->identifier->identifier.toAscii(); -// UseBuilderBase::visitIdentifierTarget(node); -// } - void UseBuilder::openContext(DUContext * newContext) { diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 2f0d254..25dcb32 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -78,16 +78,25 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) if ( ! result.length() ) { result = parser->readAllStandardError(); - QStringList position = result.split(":"); + QStringList position = result.split(":::"); qint64 lineno = position.at(0).toInt() - 1; - qint64 colno = position.at(0).toInt() - 1; + qint64 colno = position.at(1).toInt() - 1; kDebug() << lineno << colno; + QString additionalExplanation = ""; + if ( position.at(2) == "SyntaxError" ) { + additionalExplanation = "Something's wrong with your syntax. Check for missing brackets, commas, and colons."; + } + else if ( position.at(2) == "IndentationError" ) { + additionalExplanation = "You indented your code incorrectly. Also check that you didn't mix tabs and spaces in an incorrect way!"; + } + KDevelop::ProblemPointer p(new KDevelop::Problem()); - p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno - 1, lineno, colno + 1))); - p->setSource(KDevelop::ProblemData::Disk); - p->setDescription(result); + p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno - 5 < 0 ? 0 : colno - 5, lineno, colno + 5))); + p->setSource(KDevelop::ProblemData::Parser); + p->setDescription(position.at(2)); + p->setExplanation(position.at(3) + "

" + additionalExplanation); p->setSeverity(KDevelop::ProblemData::Error); { DUChainWriteLocker lock(DUChain::lock()); diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 0d2f59d..0d60672 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -77,6 +77,7 @@ def generic_visit(self, node): try: v.visit(ast.parse(f)) except Exception as e: - sys.stderr.write(str(e.lineno) + ':' + str(e.offset)) + sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) + sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") else: sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True, encoding='UTF-8')) From 540fa8abb0e5205607fef99a2966eb8c1d229fb7 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 8 Nov 2010 22:49:08 +0100 Subject: [PATCH 071/118] Hack-Fix for the colors --- duchain/contextbuilder.cpp | 5 ++--- duchain/declarationbuilder.cpp | 9 ++++----- duchain/usebuilder.cpp | 12 ++++-------- duchain/usebuilder.h | 3 ++- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 3c80814..7b495ac 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -39,6 +39,7 @@ #include #include #include +#include "usebuilder.h" using namespace KDevelop; @@ -149,12 +150,12 @@ void ContextBuilder::visitArguments(ArgumentsAst* node) } void ContextBuilder::visitCode(CodeAst* node) { - AstDefaultVisitor::visitCode(node); DUChainWriteLocker lock(DUChain::lock()); TopDUContext* internal = DUChain::self()->chainForDocument(KUrl("/home/sven/projects/kde4/python/documentation/test.py")); if ( internal ) { currentContext()->addImportedParentContext(internal); } + AstDefaultVisitor::visitCode(node); } KUrl ContextBuilder::findModulePath(const QString& name) @@ -227,7 +228,6 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) openContextForStatementList( node->body ); m_importedParentContexts.clear(); -// Python::AstDefaultVisitor::visitFunctionDefinition(node); } void ContextBuilder::visitWith( WithAst * node ) @@ -238,7 +238,6 @@ void ContextBuilder::visitWith( WithAst * node ) openContextForStatementList( node->body ); m_importedParentContexts.clear(); - Python::AstDefaultVisitor::visitWith(node); } } diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 0f7c4d6..534a508 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -125,7 +125,6 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) { if ( node->name ) visitVariableDeclaration(node->name); // except Error as - Python::AstDefaultVisitor::visitExceptionHandler(node); } void DeclarationBuilder::visitFor(ForAst* node) @@ -174,7 +173,7 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; - ContextBuilder::visitClassDefinition( node ); + DeclarationBuilderBase::visitClassDefinition( node ); openDeclaration( node->name, node ); eventuallyAssignInternalContext(); closeDeclaration(); @@ -241,11 +240,11 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) FunctionType::Ptr type = currentType(); if ( type && paramDeclaration ) type->addArgument(paramDeclaration->abstractType()); } - visitNode(expression); + else { + DeclarationBuilderBase::visitArguments(node); + } } } - - AstDefaultVisitor::visitArguments(node); } } diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 3cc4891..147bde9 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -44,22 +44,18 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) : m_editor(editor) { } -// void UseBuilder::buildUses(Ast *node) -// { -// supportBuild(node); -// // if (TopDUContext* top = dynamic_cast(m_session->getNode(node))) -// // top->setHasUses(true); -// } - void UseBuilder::visitName(NameAst* node) { DUChainWriteLocker lock(DUChain::lock()); DUContext* current = currentContext(); - QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); + QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).start); + QList isDecl = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); // TODO not so elegant ;D Declaration* declaration; if ( declarations.length() ) declaration = declarations.last(); else declaration = 0; + if ( ! declarations.length() && isDecl.length() ) return; + Q_ASSERT(node->identifier); Q_ASSERT(node->hasUsefulRangeInformation); // TODO remove this! kDebug() << " Registeriung use for " << node->identifier->value << " at " << node->identifier->startLine << ":" << node->identifier->endCol << "->" << node->identifier->endLine << ":" << node->identifier->endCol + 1 << "with dec" << declaration; diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 1109ccc..1aedc5e 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -46,7 +46,8 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase // void buildUses(Python::Ast* node); virtual void openContext(KDevelop::DUContext* newContext); virtual void closeContext(); - + +protected: // virtual void visitIdentifier(Identifier* node); virtual void visitName(NameAst* node); private: From d8f4575e86503eba47ab554c5952eee10cbf4f4b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 9 Nov 2010 18:30:06 +0100 Subject: [PATCH 072/118] Some DUChain fixes --- duchain/contextbuilder.cpp | 5 +---- duchain/usebuilder.cpp | 6 ++++++ duchain/usebuilder.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 7b495ac..a44ed12 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -211,10 +211,7 @@ void ContextBuilder::visitImport(ImportAst* node) void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << " Building function definition context: " << node->name->value; - ClassDefinitionAst* classast = dynamic_cast( node->parent ); - - if ( classast ) m_importedParentContexts.append( currentContext() ); - + visitNodeList( node->decorators ); if ( node->arguments ) diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 147bde9..af95360 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -44,6 +44,12 @@ UseBuilder::UseBuilder (PythonEditorIntegrator* editor) : m_editor(editor) { } +void UseBuilder::buildUses(Ast* node) +{ + UseBuilderBase::buildUses(node); +} + + void UseBuilder::visitName(NameAst* node) { DUChainWriteLocker lock(DUChain::lock()); diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 1aedc5e..56a823f 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -43,7 +43,7 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase // UseBuilder(PythonEditorIntegrator* editor, const KUrl &url); UseBuilder(PythonEditorIntegrator *editor); ParseSession* parseSession() const; -// void buildUses(Python::Ast* node); + void buildUses(Python::Ast* node); virtual void openContext(KDevelop::DUContext* newContext); virtual void closeContext(); From 4cfcd39bd246212fcc37492a70cc3960b53b8fa1 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 11 Nov 2010 23:54:36 +0100 Subject: [PATCH 073/118] Code structures (class, function) now have proper range information --- duchain/contextbuilder.cpp | 22 +++++++++++++++------- duchain/contextbuilder.h | 4 +++- parser/astbuilder.cpp | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index a44ed12..b8b7fc9 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -122,23 +122,28 @@ void ContextBuilder::addImportedContexts() } } -void ContextBuilder::openContextForStatementList( const QList& l ) +void ContextBuilder::openContextForStatementList( const QList& l, DUContext::ContextType type) { if ( l.count() > 0 ) { Ast* first = l.first(); Ast* last = l.last(); - openContext(first, RangeInRevision(first->startLine - 1, first->startCol, last->endLine + 1, 10000), DUContext::Other ); - kDebug() << " +++ opening context: " << first->startLine - 1 << ":" << first->startCol << " -- " << last->endLine + 1 << "inf"; + Q_ASSERT(first->hasUsefulRangeInformation); // TODO remove this + RangeInRevision range(RangeInRevision(first->startLine - 1, first->startCol, last->endLine + 1, 10000)); + DUContext* rangectx = openContext(first, range, DUContext::Other ); + kDebug() << " +++ opening context (stmlist): " << range.castToSimpleRange(); addImportedContexts(); visitNodeList( l ); closeContext(); + kDebug() << " --- closed context (stmlist): line " << rangectx->range().castToSimpleRange(); } } void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { - openContext( node, DUContext::Class, identifierForNode( node->name ) ); + RangeInRevision range(node->body.first()->startLine, node->body.first()->startCol, node->body.first()->endLine, node->body.last()->endCol); + openContext( node, range, DUContext::Class, identifierForNode( node->name ) ); + kDebug() << " +++ opening CLASS context: " << range.castToSimpleRange(); addImportedContexts(); Python::AstDefaultVisitor::visitClassDefinition(node); closeContext(); @@ -216,20 +221,23 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) if ( node->arguments ) { - DUContext* funcctx = openContext( node->arguments, node->arguments, DUContext::Function, identifierForNode( node->name ) ); - addImportedContexts(); + RangeInRevision range(node->startLine, node->startCol, node->startLine, 10000); + DUContext* funcctx = openContext( node->arguments, range, DUContext::Other, identifierForNode( node->name ) ); + kDebug() << " +++ opening FUNCTION ARGUMENTS context: " << node->arguments->startLine - 1 << ":" << node->arguments->startCol << " -- " << node->arguments->endLine + 1 << "inf"; +// addImportedContexts(); visitNode( node->arguments ); closeContext(); m_importedParentContexts.append( funcctx ); } - openContextForStatementList( node->body ); + openContextForStatementList( node->body, DUContext::Function); m_importedParentContexts.clear(); } void ContextBuilder::visitWith( WithAst * node ) { m_importedParentContexts = QList() << openContext( node->contextExpression, DUContext::Other ); + kDebug() << " +++ opening context: " << node->startLine - 1 << ":" << node->startCol << " -- " << node->endLine + 1 << "inf"; visitNode( node->contextExpression ); closeContext(); diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 3ad4513..4cf6a74 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -74,6 +74,8 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitImport(ImportAst* node); virtual void visitImportFrom(ImportFromAst* node); + DUContext* openSafeContext( Python::Ast* node, RangeInRevision& range, DUContext::ContextType type, Python::Identifier* identifier = 0 ); + QMap contextsForModules; static PythonEditorIntegrator* m_editor; @@ -94,7 +96,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public ReferencedTopDUContext m_topContext; private: - void openContextForStatementList( const QList& ); + void openContextForStatementList( const QList&, DUContext::ContextType type = DUContext::Other); QList m_importedParentContexts; }; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 25dcb32..3b92ca2 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -849,6 +849,20 @@ void AstBuilder::populateAst() case Ast::StatementAstType: break; // ok default: kWarning() << "Unsupported AST type: " << currentAbstractNode->astType; break; } + + // Walk throguh the tree and set proper end columns and lines, as the python parser sadly does not do this for us + if ( currentAbstractNode->hasUsefulRangeInformation ) { + Ast* parent = currentAbstractNode->parent; + while ( parent ) { + if ( parent->endLine < currentAbstractNode->endLine ) { + kWarning() << "Adjusting parent range information"; + parent->endLine = currentAbstractNode->endLine; + parent->endCol = currentAbstractNode->endCol; + } + parent = parent->parent; + } + } + } } From 1251f6594f767c67003e42ce7f79cd8e7938acc5 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 12 Nov 2010 23:43:09 +0100 Subject: [PATCH 074/118] Fixed serveral nasty range bugs --- duchain/contextbuilder.cpp | 36 ++++++++++++++++++++++++++---------- parser/astbuilder.cpp | 31 ++++++++++++++++++++++++++----- parser/astbuilder.h | 2 ++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index b8b7fc9..54a0acb 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -141,7 +141,7 @@ void ContextBuilder::openContextForStatementList( const QList& l, DUContex void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { - RangeInRevision range(node->body.first()->startLine, node->body.first()->startCol, node->body.first()->endLine, node->body.last()->endCol); + RangeInRevision range(node->body.first()->startLine, node->body.first()->startCol, node->body.last()->endLine, node->body.last()->endCol + 100000); openContext( node, range, DUContext::Class, identifierForNode( node->name ) ); kDebug() << " +++ opening CLASS context: " << range.castToSimpleRange(); addImportedContexts(); @@ -218,20 +218,36 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) kDebug() << " Building function definition context: " << node->name->value; visitNodeList( node->decorators ); - - if ( node->arguments ) + + Ast* first = node->body.first(); + Ast* last = node->body.last(); + Q_ASSERT(first->hasUsefulRangeInformation); // TODO remove this + RangeInRevision range(RangeInRevision(first->startLine, first->startCol, last->endLine, last->endCol + 100000)); + + if ( node->arguments && node->arguments->arguments.length() ) { - RangeInRevision range(node->startLine, node->startCol, node->startLine, 10000); - DUContext* funcctx = openContext( node->arguments, range, DUContext::Other, identifierForNode( node->name ) ); - kDebug() << " +++ opening FUNCTION ARGUMENTS context: " << node->arguments->startLine - 1 << ":" << node->arguments->startCol << " -- " << node->arguments->endLine + 1 << "inf"; -// addImportedContexts(); + int sline, eline, scol, ecol; + sline = node->arguments->arguments.first()->startLine; + eline = node->arguments->arguments.last()->endLine; + scol = node->arguments->arguments.first()->startCol; + ecol = node->arguments->arguments.last()->endCol; + + RangeInRevision range(sline, scol, eline, ecol+100000); + DUContext* funcctx = openContext( node->arguments, range, DUContext::Other); + kDebug() << " +++ opening FUNCTION ARGUMENTS context: " << funcctx->range().castToSimpleRange(); visitNode( node->arguments ); closeContext(); m_importedParentContexts.append( funcctx ); } - - openContextForStatementList( node->body, DUContext::Function); - m_importedParentContexts.clear(); + + DUContext* ctx = openContext(first, range, DUContext::Other, identifierForNode( node->name ) ); + kDebug() << " +++ opening context (function definition): " << range.castToSimpleRange(); + addImportedContexts(); + + visitNodeList(node->body); + + closeContext(); + kDebug() << " --- closed context (function definition): " << ctx->range().castToSimpleRange(); } void ContextBuilder::visitWith( WithAst * node ) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 3b92ca2..1dc617a 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -152,6 +152,8 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok else if ( token == QXmlStreamReader::StartElement ) { // Here we can now assemble an actual node with the attributes extracted above + kDebug() << "PRocessing: " << currentElementName; + // Skip the document root element if ( currentElementName == "pythonast" ) { parseXmlAstNode(xmlast, token); @@ -165,13 +167,31 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok // this will push a parent onto the stack nodeAdded = parseAstNode(currentElementName, currentElementText, currentElementAttributes); - if ( ! nodeAdded ) continue; + if ( ! nodeAdded ) { + m_isRealNodeMap.append(false); + kDebug() << "ADD (false) " << xmlast->name() << "; new length: " << m_nodeStack.length(); + continue; + } + kDebug() << "ADD (true) " << xmlast->name() << "; new length: " << m_nodeStack.length(); + m_isRealNodeMap.append(true); + + m_currentNode = m_nodeStack.last(); parseXmlAstNode(xmlast, token); + } + else if ( token == QXmlStreamReader::EndElement ) { + if ( currentElementName == "pythonast" ) continue; - // now we pop this parent off - m_currentNode = m_nodeStack.last(); - m_nodeStack.removeLast(); + // now we pop the parent off + bool isreal = m_isRealNodeMap.last(); + m_isRealNodeMap.removeLast(); + + kDebug() << "real: " << isreal << "; cnt: " << m_nodeStack.length() << currentElementName; + if ( isreal ) { + kDebug() << "REM " << m_nodeStack.last(); + m_currentNode = m_nodeStack.last(); + m_nodeStack.removeLast(); + } } // Everything else (stuff between tags, comments...) is ignored else continue; @@ -855,13 +875,14 @@ void AstBuilder::populateAst() Ast* parent = currentAbstractNode->parent; while ( parent ) { if ( parent->endLine < currentAbstractNode->endLine ) { - kWarning() << "Adjusting parent range information"; + kWarning() << "Adjusting parent end range information to" << currentAbstractNode->endLine << currentAbstractNode->endCol; parent->endLine = currentAbstractNode->endLine; parent->endCol = currentAbstractNode->endCol; } parent = parent->parent; } } + kDebug() << "Done adjusting ranges."; } } diff --git a/parser/astbuilder.h b/parser/astbuilder.h index e797a5e..4441405 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -61,6 +61,8 @@ class AstBuilder // one map for regular ast nodes, and the others for primitive nodes of different types QMap m_nodeMap; + QList m_isRealNodeMap; + QMap m_contextNodeMap; QMap m_boolOpNodeMap; QMap m_compOpNodeMap; From 0bd9cb06b1b7b41344d312ed4312912855d3df32 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 13 Nov 2010 00:03:33 +0100 Subject: [PATCH 075/118] Removed most verbose debugging, and corrected context types --- duchain/contextbuilder.cpp | 4 ++-- parser/astbuilder.cpp | 14 -------------- parser/astdefaultvisitor.cpp | 1 - 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 54a0acb..e661c38 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -233,14 +233,14 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) ecol = node->arguments->arguments.last()->endCol; RangeInRevision range(sline, scol, eline, ecol+100000); - DUContext* funcctx = openContext( node->arguments, range, DUContext::Other); + DUContext* funcctx = openContext( node->arguments, range, DUContext::Function); kDebug() << " +++ opening FUNCTION ARGUMENTS context: " << funcctx->range().castToSimpleRange(); visitNode( node->arguments ); closeContext(); m_importedParentContexts.append( funcctx ); } - DUContext* ctx = openContext(first, range, DUContext::Other, identifierForNode( node->name ) ); + DUContext* ctx = openContext(first, range, DUContext::Function, identifierForNode( node->name ) ); kDebug() << " +++ opening context (function definition): " << range.castToSimpleRange(); addImportedContexts(); diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 1dc617a..613abb0 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -152,27 +152,18 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok else if ( token == QXmlStreamReader::StartElement ) { // Here we can now assemble an actual node with the attributes extracted above - kDebug() << "PRocessing: " << currentElementName; - // Skip the document root element if ( currentElementName == "pythonast" ) { parseXmlAstNode(xmlast, token); continue; } -// kDebug() << "Token: " << token << "; " << "Name: " << currentElementName << "; Text: " << currentElementText; -// for ( int i=0; iname() << "; new length: " << m_nodeStack.length(); continue; } - kDebug() << "ADD (true) " << xmlast->name() << "; new length: " << m_nodeStack.length(); m_isRealNodeMap.append(true); m_currentNode = m_nodeStack.last(); @@ -186,9 +177,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok bool isreal = m_isRealNodeMap.last(); m_isRealNodeMap.removeLast(); - kDebug() << "real: " << isreal << "; cnt: " << m_nodeStack.length() << currentElementName; if ( isreal ) { - kDebug() << "REM " << m_nodeStack.last(); m_currentNode = m_nodeStack.last(); m_nodeStack.removeLast(); } @@ -875,15 +864,12 @@ void AstBuilder::populateAst() Ast* parent = currentAbstractNode->parent; while ( parent ) { if ( parent->endLine < currentAbstractNode->endLine ) { - kWarning() << "Adjusting parent end range information to" << currentAbstractNode->endLine << currentAbstractNode->endCol; parent->endLine = currentAbstractNode->endLine; parent->endCol = currentAbstractNode->endCol; } parent = parent->parent; } } - kDebug() << "Done adjusting ranges."; - } } diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 887f0ce..97bba97 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -45,7 +45,6 @@ void AstDefaultVisitor::visitCode(CodeAst* node) { kDebug() << "Visiting code"; foreach (Ast* statement, node->body) { - kDebug() << statement->astType << Ast::ExpressionAstType; visitNode(statement); } } From b32831abc69999cb92edbaff4b967731d6fcd5ee Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 13 Nov 2010 01:37:34 +0100 Subject: [PATCH 076/118] Fixed a crash for exception handlers, and improved error reporting. --- duchain/contextbuilder.cpp | 3 +++ duchain/declarationbuilder.cpp | 1 + duchain/usebuilder.cpp | 22 +++++++++++----------- duchain/usebuilder.h | 4 ++-- parser/astbuilder.cpp | 9 ++++++++- pythonpythonparser.py | 7 +++++-- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index e661c38..a634b6a 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -216,6 +216,7 @@ void ContextBuilder::visitImport(ImportAst* node) void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) { kDebug() << " Building function definition context: " << node->name->value; + DUChainWriteLocker lock(DUChain::lock()); visitNodeList( node->decorators ); @@ -233,7 +234,9 @@ void ContextBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) ecol = node->arguments->arguments.last()->endCol; RangeInRevision range(sline, scol, eline, ecol+100000); + Q_ASSERT(range.isValid()); DUContext* funcctx = openContext( node->arguments, range, DUContext::Function); + kDebug() << funcctx; kDebug() << " +++ opening FUNCTION ARGUMENTS context: " << funcctx->range().castToSimpleRange(); visitNode( node->arguments ); closeContext(); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 534a508..35e3a59 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -125,6 +125,7 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) { if ( node->name ) visitVariableDeclaration(node->name); // except Error as + DeclarationBuilderBase::visitExceptionHandler(node); } void DeclarationBuilder::visitFor(ForAst* node) diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index af95360..797c561 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -69,17 +69,17 @@ void UseBuilder::visitName(NameAst* node) } -void UseBuilder::openContext(DUContext * newContext) -{ - UseBuilderBase::openContext(newContext); - m_nextUseStack.push(0); -} - -void UseBuilder::closeContext() -{ - UseBuilderBase::closeContext(); - m_nextUseStack.pop(); -} +// void UseBuilder::openContext(DUContext * newContext) +// { +// UseBuilderBase::openContext(newContext); +// m_nextUseStack.push(0); +// } +// +// void UseBuilder::closeContext() +// { +// UseBuilderBase::closeContext(); +// m_nextUseStack.pop(); +// } ParseSession *UseBuilder::parseSession() const diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index 56a823f..ca51c9c 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -44,8 +44,8 @@ class KDEVPYTHONDUCHAIN_EXPORT UseBuilder: public UseBuilderBase UseBuilder(PythonEditorIntegrator *editor); ParseSession* parseSession() const; void buildUses(Python::Ast* node); - virtual void openContext(KDevelop::DUContext* newContext); - virtual void closeContext(); +// virtual void openContext(KDevelop::DUContext* newContext); +// virtual void closeContext(); protected: // virtual void visitIdentifier(Identifier* node); diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 613abb0..6d974ec 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -79,12 +79,19 @@ QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents) if ( ! result.length() ) { result = parser->readAllStandardError(); QStringList position = result.split(":::"); + + QString additionalExplanation = ""; + if ( position.length() < 4 ) { + kError() << "Could not parse error message! This should not happen."; + kError() << "Raw data was: " << result; + return "0"; + } + qint64 lineno = position.at(0).toInt() - 1; qint64 colno = position.at(1).toInt() - 1; kDebug() << lineno << colno; - QString additionalExplanation = ""; if ( position.at(2) == "SyntaxError" ) { additionalExplanation = "Something's wrong with your syntax. Check for missing brackets, commas, and colons."; } diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 0d60672..c2816e9 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -77,7 +77,10 @@ def generic_visit(self, node): try: v.visit(ast.parse(f)) except Exception as e: - sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) - sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") + try: + sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) + sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") + except: + sys.stderr.write(str(e) + ':::?:::?:::') else: sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True, encoding='UTF-8')) From 3f584cd8f199aff47d1e83df5b59cd3014c28a49 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 13 Nov 2010 01:55:27 +0100 Subject: [PATCH 077/118] Added hack fix for escape sequences in code --- pythonpythonparser.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index c2816e9..6dc8db6 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -12,6 +12,7 @@ from lxml import etree import types import sys +import re class KDevelopNodeVisitor(ast.NodeVisitor): basenode = etree.Element("pythonast") @@ -44,7 +45,12 @@ def generic_visit(self, node): value = getattr(node, field) if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: continue - node_xmlrepr.set(field.lower(), str(value)) + try: + node_xmlrepr.set(field.lower(), str(value)) + except: + sys.stderr.write("Warning: Invalid string literal replaced by empty string!\n") + node_xmlrepr.set(field.lower(), "") + super(KDevelopNodeVisitor, self).generic_visit(node) @@ -75,12 +81,13 @@ def generic_visit(self, node): f = sys.stdin.read() v = KDevelopNodeVisitor() try: - v.visit(ast.parse(f)) + parsetree = ast.parse(f) except Exception as e: try: sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") except: - sys.stderr.write(str(e) + ':::?:::?:::') + sys.stderr.write('?:::?:::'+str(e)+':::?') else: + v.visit(parsetree) sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True, encoding='UTF-8')) From f85a90cf061e880daa7ec00ccf2d6cfa2dcfd49d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 14 Nov 2010 10:38:37 +0100 Subject: [PATCH 078/118] Fixed Qt4.7 build problems --- parser/ast.cpp | 4 ++-- pythonparsejob.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 9a6087e..8a2fc94 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -221,7 +221,7 @@ NameAst::NameAst(Ast* parent): ExpressionAst(parent, Ast::NameAstType), identifi } -NumberAst::NumberAst(Ast* parent): ExpressionAst(parent, Ast::NumberAstType), value(0) +NumberAst::NumberAst(Ast* parent): ExpressionAst(parent, Ast::NumberAstType), value("0") { } @@ -271,7 +271,7 @@ StatementAst::StatementAst(Ast* parent, AstType type): Ast(parent, type) } -StringAst::StringAst(Ast* parent): ExpressionAst(parent, Ast::StringAstType), value(0) +StringAst::StringAst(Ast* parent): ExpressionAst(parent, Ast::StringAstType), value("") { } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index d565905..6520c68 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -171,7 +171,7 @@ void ParseJob::run() kDebug() << "----Parsing Succeded---***"; if ( m_parent && m_parent->codeHighlighting() ) { - kDebug() << m_duContext.data(); + kDebug() << "Starting highlighter..."; DUChainReadLocker lock(DUChain::lock()); KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); hl->highlightDUChain(m_duContext); From 83c416ca57d3a1b4bc5484a74375b2dcb14eef99 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 14 Nov 2010 10:45:47 +0100 Subject: [PATCH 079/118] Clear problems when they're not there any more --- pythonparsejob.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 6520c68..96c9762 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -181,6 +181,7 @@ void ParseJob::run() ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); + m_duContext->clearProblems(); } else { From 88cf2a80a4d572b7ea8f91657d2d968729008fe4 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 14 Nov 2010 10:57:20 +0100 Subject: [PATCH 080/118] Fixed invalid ranges problem --- pythonparsejob.cpp | 14 ++++++++------ pythonpythonparser.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 96c9762..32ea428 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -190,12 +190,7 @@ void ParseJob::run() DUChainReadLocker lock(DUChain::lock()); m_duContext = DUChain::self()->chainForDocument(document()); } - if ( m_duContext ) { - DUChainWriteLocker lock(DUChain::lock()); - m_duContext->clearProblems(); - m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); - } - else { + if ( ! m_duContext ) { DUChainWriteLocker lock(DUChain::lock()); ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); static const IndexedString langString("python"); @@ -204,6 +199,13 @@ void ParseJob::run() m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); DUChain::self()->addDocumentChain(m_duContext); } + { + DUChainWriteLocker lock(DUChain::lock()); + DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); + m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); + m_duContext->clearProblems(); + } + DUChainWriteLocker lock(DUChain::lock()); foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; diff --git a/pythonpythonparser.py b/pythonpythonparser.py index 6dc8db6..e4b1199 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -23,7 +23,7 @@ class KDevelopNodeVisitor(ast.NodeVisitor): def __init__(self, *arg, **args): super(KDevelopNodeVisitor, self).__init__(*arg, **args) self.currentnode = self.basenode - + def generic_visit(self, node): self.nodecnt += 1 From a346d231052456f62024d03808d7ff584f1f8dba Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 15 Nov 2010 00:40:26 +0100 Subject: [PATCH 081/118] Empty tooltips! Yeah! ;D --- codecompletion/importfileitem.cpp | 1 + codecompletion/importfileitem.h | 2 +- .../pythoncodecompletioncontext.cpp | 2 +- duchain/CMakeLists.txt | 5 ++++- duchain/contextbuilder.cpp | 8 +++++++- duchain/contextbuilder.h | 2 ++ duchain/navigationwidget.cpp | 20 ------------------- duchain/navigationwidget.h | 20 ------------------- 8 files changed, 16 insertions(+), 44 deletions(-) delete mode 100644 duchain/navigationwidget.cpp delete mode 100644 duchain/navigationwidget.h diff --git a/codecompletion/importfileitem.cpp b/codecompletion/importfileitem.cpp index 1614a3c..34965cc 100644 --- a/codecompletion/importfileitem.cpp +++ b/codecompletion/importfileitem.cpp @@ -1,6 +1,7 @@ #include "importfileitem.h" #include #include +#include "navigation/navigationwidget.h" using namespace KDevelop; diff --git a/codecompletion/importfileitem.h b/codecompletion/importfileitem.h index 567a2d8..edce9a1 100644 --- a/codecompletion/importfileitem.h +++ b/codecompletion/importfileitem.h @@ -2,7 +2,7 @@ #define IMPORTFILEITEM_H #include -#include "navigationwidget.h" +#include "navigation/navigationwidget.h" #include namespace Python { diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 15b0672..3336495 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -14,7 +14,7 @@ #include #include -#include "navigationwidget.h" +#include "navigation/navigationwidget.h" #include "importfileitem.h" #include #include diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index bfa403a..0e53c5b 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -4,7 +4,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ) set(duchain_SRCS - navigationwidget.cpp + pythonducontext.cpp + navigation/navigationwidget.cpp contextbuilder.cpp pythoneditorintegrator.cpp declarationbuilder.cpp @@ -26,3 +27,5 @@ target_link_libraries( kdev4pythonduchain install(TARGETS kdev4pythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) + +add_subdirectory(navigation) \ No newline at end of file diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index a634b6a..5760877 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -40,6 +40,7 @@ #include #include #include "usebuilder.h" +#include "pythonducontext.h" using namespace KDevelop; @@ -66,12 +67,17 @@ TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, Parsin file = new ParsingEnvironmentFile(currentDocumentUrl); file->setLanguage(IndexedString("python")); } - TopDUContext* top = new TopDUContext(currentDocumentUrl, range, file); + TopDUContext* top = new PythonDUContext(currentDocumentUrl, range, file); ReferencedTopDUContext ref(top); m_topContext = ref; return top; } +DUContext* ContextBuilder::newContext(const RangeInRevision& range) +{ + return new PythonDUContext(range, currentContext()); +} + void ContextBuilder::setEditor(PythonEditorIntegrator* editor) { //m_identifierCompiler = new IdentifierCompiler(editor->parseSession()); diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 4cf6a74..bcf6a7c 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -31,6 +31,7 @@ #include #include "pythonduchainexport.h" +#include "pythonducontext.h" using namespace KDevelop; @@ -81,6 +82,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public static PythonEditorIntegrator* m_editor; TopDUContext* newTopContext(const RangeInRevision& range, ParsingEnvironmentFile* file); + virtual KDevelop::DUContext* newContext(const KDevelop::RangeInRevision& range); template void visitNodeList( const QList& l ) { diff --git a/duchain/navigationwidget.cpp b/duchain/navigationwidget.cpp deleted file mode 100644 index 1cb3c94..0000000 --- a/duchain/navigationwidget.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "navigationwidget.h" -#include -#include - -NavigationWidget::NavigationWidget() -{ - -} - -NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) -{ - kDebug() << "Navigation widget requested"; -} - -NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext) -{ - -} - -#include "navigationwidget.moc" diff --git a/duchain/navigationwidget.h b/duchain/navigationwidget.h deleted file mode 100644 index 34c31e5..0000000 --- a/duchain/navigationwidget.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NAVIGATIONWIDGET_H -#define NAVIGATIONWIDGET_H - -#include -#include "pythonduchainexport.h" -#include - -class KDEVPYTHONDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavigationWidget -{ -Q_OBJECT -public: - NavigationWidget(); - NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); - NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext); - - static QString shortDescription(KDevelop::Declaration* declaration) { return "Test"; }; - static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; -}; - -#endif // NAVIGATIONWIDGET_H From f166a21439f6ee182785902967455156bac1775d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 15 Nov 2010 20:36:24 +0100 Subject: [PATCH 082/118] Added missing navigationwidget source files --- duchain/navigation/CMakeLists.txt | 1 + duchain/navigation/navigationwidget.cpp | 18 ++++++++++++++++++ duchain/navigation/navigationwidget.h | 23 +++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 duchain/navigation/CMakeLists.txt create mode 100644 duchain/navigation/navigationwidget.cpp create mode 100644 duchain/navigation/navigationwidget.h diff --git a/duchain/navigation/CMakeLists.txt b/duchain/navigation/CMakeLists.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/duchain/navigation/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp new file mode 100644 index 0000000..e55f5a6 --- /dev/null +++ b/duchain/navigation/navigationwidget.cpp @@ -0,0 +1,18 @@ +#include "navigationwidget.h" + +namespace Python { + +NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) +{ + kDebug() << "Navigation widget for Declaration requested"; + m_topContext = topContext; + + initBrowser(400); +} + +NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) +{ + +} + +} \ No newline at end of file diff --git a/duchain/navigation/navigationwidget.h b/duchain/navigation/navigationwidget.h new file mode 100644 index 0000000..341ad43 --- /dev/null +++ b/duchain/navigation/navigationwidget.h @@ -0,0 +1,23 @@ +#ifndef NAVIGATIONWIDGET_H +#define NAVIGATIONWIDGET_H + +#include +#include +#include "pythonduchainexport.h" + +namespace Python { + +class KDEVPYTHONDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavigationWidget +{ + +public: + NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); + NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); + + static QString shortDescription(KDevelop::Declaration* declaration) { return "Test"; }; + static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; +}; + +} + +#endif // NAVIGATIONWIDGET_H \ No newline at end of file From ec1105551df9d72224789d13434b39f246beebd8 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 15 Nov 2010 22:12:08 +0100 Subject: [PATCH 083/118] trivial tooltip implementation --- duchain/CMakeLists.txt | 4 +- .../declarationnavigationcontext.cpp | 60 +++++++++++++++++++ .../navigation/declarationnavigationcontext.h | 45 ++++++++++++++ duchain/navigation/navigationwidget.cpp | 6 +- duchain/pythonducontext.cpp | 32 ++++++++++ duchain/pythonducontext.h | 51 ++++++++++++++++ 6 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 duchain/navigation/declarationnavigationcontext.cpp create mode 100644 duchain/navigation/declarationnavigationcontext.h create mode 100644 duchain/pythonducontext.cpp create mode 100644 duchain/pythonducontext.h diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 0e53c5b..ca1832c 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -5,12 +5,14 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} set(duchain_SRCS pythonducontext.cpp - navigation/navigationwidget.cpp contextbuilder.cpp pythoneditorintegrator.cpp declarationbuilder.cpp usebuilder.cpp dumpchain.cpp + + navigation/navigationwidget.cpp + navigation/declarationnavigationcontext.cpp # typebuilder.cpp ) diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp new file mode 100644 index 0000000..a057694 --- /dev/null +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -0,0 +1,60 @@ +/* + Copyright 2007 David Nolden + Copyright 2008 Niko Sams + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "declarationnavigationcontext.h" + +#include + +#include +#include + +#include +#include +#include +#include + +namespace Python +{ +using namespace KDevelop; + +DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) + : AbstractDeclarationNavigationContext(decl, topContext, previousContext) +{ +} + +NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration) +{ + return AbstractDeclarationNavigationContext::registerChild(new DeclarationNavigationContext(declaration, m_topContext, this)); +} + +void DeclarationNavigationContext::makeLink(const QString& name, DeclarationPointer declaration, NavigationAction::Type actionType) +{ + AbstractDeclarationNavigationContext::makeLink(name, declaration, actionType); +} + +QString DeclarationNavigationContext::declarationKind(DeclarationPointer decl) +{ + if ( decl->kind() == Declaration::Instance && decl->abstractType() + && decl->abstractType()->modifiers() & AbstractType::ConstModifier ) { + return i18nc("kind of a php-constant, as shown in the declaration tooltip", "Constant"); + } + return AbstractDeclarationNavigationContext::declarationKind(decl); +} + +} diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h new file mode 100644 index 0000000..807c41c --- /dev/null +++ b/duchain/navigation/declarationnavigationcontext.h @@ -0,0 +1,45 @@ +/* + Copyright 2007 David Nolden + Copyright 2008 Niko Sams + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef DECLARATIONNAVIGATIONCONTEXT_H +#define DECLARATIONNAVIGATIONCONTEXT_H + +#include +#include + +namespace Python +{ + +class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigationContext +{ +public: + DeclarationNavigationContext(KDevelop::DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, KDevelop::AbstractNavigationContext* previousContext = 0); + +protected: + KDevelop::NavigationContextPointer registerChild(KDevelop::DeclarationPointer declaration); +// virtual KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const; +// virtual void htmlClass(); + + void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ); + + virtual QString declarationKind(KDevelop::DeclarationPointer decl); +}; + +} + +#endif diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index e55f5a6..b749696 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -1,4 +1,5 @@ #include "navigationwidget.h" +#include "declarationnavigationcontext.h" namespace Python { @@ -6,8 +7,11 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe { kDebug() << "Navigation widget for Declaration requested"; m_topContext = topContext; - + initBrowser(400); + + m_startContext = new DeclarationNavigationContext(declaration, m_topContext); + setContext(m_startContext); } NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) diff --git a/duchain/pythonducontext.cpp b/duchain/pythonducontext.cpp new file mode 100644 index 0000000..252af18 --- /dev/null +++ b/duchain/pythonducontext.cpp @@ -0,0 +1,32 @@ +#include "pythonducontext.h" + +#include +#include +#include +#include + +#include "navigation/navigationwidget.h" + +using namespace KDevelop; + +namespace Python { + +typedef PythonDUContext PythonTopDUContext; +REGISTER_DUCHAIN_ITEM_WITH_DATA(PythonTopDUContext, TopDUContextData); + +typedef PythonDUContext PythonNormalDUContext; +REGISTER_DUCHAIN_ITEM_WITH_DATA(PythonNormalDUContext, DUContextData); + +template<> +QWidget* PythonDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { + if ( ! decl ) return 0; + return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); +} + +template<> +QWidget* PythonDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { + if ( ! decl ) return 0; + return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); +} + +} \ No newline at end of file diff --git a/duchain/pythonducontext.h b/duchain/pythonducontext.h new file mode 100644 index 0000000..d010e3b --- /dev/null +++ b/duchain/pythonducontext.h @@ -0,0 +1,51 @@ +#ifndef PYTHONDUCONTEXT_H +#define PYTHONDUCONTEXT_H + +#include +#include +class QWidget; + +namespace KDevelop +{ + class Declaration; + class TopDUContext; +} + +namespace Python +{ + +template +class PythonDUContext : public BaseContext +{ +public: + template + PythonDUContext(Data& data) : BaseContext(data) { + } + + ///Parameters will be reached to the base-class + template + PythonDUContext(const Param1& p1, const Param2& p2, bool isInstantiationContext) : BaseContext(p1, p2, isInstantiationContext) { + static_cast(this)->d_func_dynamic()->setClassId(this); + } + + ///Both parameters will be reached to the base-class. This fits TopDUContext. + template + PythonDUContext(const Param1& p1, const Param2& p2, const Param3& p3) : BaseContext(p1, p2, p3) { + static_cast(this)->d_func_dynamic()->setClassId(this); + } + template + PythonDUContext(const Param1& p1, const Param2& p2) : BaseContext(p1, p2) { + static_cast(this)->d_func_dynamic()->setClassId(this); + } + + virtual QWidget* createNavigationWidget(KDevelop::Declaration* decl, KDevelop::TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const; + + enum { + Identity = BaseContext::Identity + 51 + }; +}; + +} + + +#endif // PYTHONDUCONTEXT_H From 013647f6bf83a5f963583ddb2e9e84a706a08ac7 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 16 Nov 2010 00:11:42 +0100 Subject: [PATCH 084/118] Comment hack, part 1 --- duchain/declarationbuilder.cpp | 13 +++++++++++-- duchain/navigation/declarationnavigationcontext.cpp | 9 +++++---- duchain/navigation/declarationnavigationcontext.h | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 35e3a59..a90ec6b 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -146,8 +146,17 @@ void DeclarationBuilder::visitImport(ImportAst* node) TopDUContextPointer contextptr = contextsForModules.value(name->asName ? name->asName->identifier->value : name->name->value); kDebug() << "Chain for document: " << contextptr; m_importContextsForImportStatement.push(contextptr); - if ( name->asName ) visitVariableDeclaration(name->asName); - else visitVariableDeclaration(name->name); + Declaration* dec; + if ( name->asName ) dec = visitVariableDeclaration(name->asName); + else dec = visitVariableDeclaration(name->name); + QString moduleName = name->name->value; + if ( name->asName && name->asName->identifier ) + moduleName += name->asName->identifier->value; + if ( dec ) { + DUChainWriteLocker lock(DUChain::lock()); + dec->setComment(";;module " + moduleName); + kDebug() << "Set comment to " << dec->comment(); + } m_importContextsForImportStatement.clear(); } } diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index a057694..2eb8801 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -36,6 +36,11 @@ using namespace KDevelop; DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) : AbstractDeclarationNavigationContext(decl, topContext, previousContext) { + +} + +void DeclarationNavigationContext::htmlFunction() { + modifyHtml() += "
random.randint = randint(self, a, b) method of random.Random instance
Return random integer in range [a, b], including both end points.
"; } NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration) @@ -50,10 +55,6 @@ void DeclarationNavigationContext::makeLink(const QString& name, DeclarationPoin QString DeclarationNavigationContext::declarationKind(DeclarationPointer decl) { - if ( decl->kind() == Declaration::Instance && decl->abstractType() - && decl->abstractType()->modifiers() & AbstractType::ConstModifier ) { - return i18nc("kind of a php-constant, as shown in the declaration tooltip", "Constant"); - } return AbstractDeclarationNavigationContext::declarationKind(decl); } diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h index 807c41c..cbb4c44 100644 --- a/duchain/navigation/declarationnavigationcontext.h +++ b/duchain/navigation/declarationnavigationcontext.h @@ -34,6 +34,7 @@ class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigat KDevelop::NavigationContextPointer registerChild(KDevelop::DeclarationPointer declaration); // virtual KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const; // virtual void htmlClass(); + virtual void htmlFunction(); void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ); From f415258476e43774e764fd2f67d4948fe5761280 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 16 Nov 2010 23:58:59 +0100 Subject: [PATCH 085/118] Added an extra class for module import declarations --- duchain/CMakeLists.txt | 5 +-- duchain/declarationbuilder.cpp | 34 +++++++++--------- duchain/declarationbuilder.h | 4 +-- .../.swp.importedmoduledeclaration.cpp | Bin 0 -> 144 bytes duchain/declarations/CMakeLists.txt | 1 + .../importedmoduledeclaration.cpp | 26 ++++++++++++++ .../declarations/importedmoduledeclaration.h | 23 ++++++++++++ duchain/usebuilder.cpp | 2 +- 8 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 duchain/declarations/.swp.importedmoduledeclaration.cpp create mode 100644 duchain/declarations/CMakeLists.txt create mode 100644 duchain/declarations/importedmoduledeclaration.cpp create mode 100644 duchain/declarations/importedmoduledeclaration.h diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index ca1832c..3db0cef 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) -set(duchain_SRCS +set(duchain_SRCS declarations/importedmoduledeclaration.cpp pythonducontext.cpp contextbuilder.cpp pythoneditorintegrator.cpp @@ -30,4 +30,5 @@ target_link_libraries( kdev4pythonduchain install(TARGETS kdev4pythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) -add_subdirectory(navigation) \ No newline at end of file +add_subdirectory(navigation) +add_subdirectory(declarations) \ No newline at end of file diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index a90ec6b..159b3bd 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -45,6 +45,8 @@ #include "pythoneditorintegrator.h" #include "QtGlobal" +#include + using namespace KTextEditor; @@ -84,7 +86,7 @@ void DeclarationBuilder::closeDeclaration() DeclarationBuilderBase::closeDeclaration(); } -Declaration* DeclarationBuilder::visitVariableDeclaration(Ast* node) +template T* DeclarationBuilder::visitVariableDeclaration(Ast* node) { NameAst* currentVariableDefinition = dynamic_cast(node); Q_ASSERT(currentVariableDefinition); @@ -96,10 +98,10 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Ast* node) } Identifier* id = currentVariableDefinition->identifier; Q_ASSERT(id); - return visitVariableDeclaration(id, currentVariableDefinition); + return visitVariableDeclaration(id, currentVariableDefinition); } -Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* originalAst) +template T* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* originalAst) { DUChainWriteLocker lock(DUChain::lock()); Q_ASSERT(node); @@ -109,11 +111,11 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* existingDeclarations = currentContext()->findDeclarations(identifierForNode(node), until); - Declaration* dec = 0; + T* dec = 0; if ( ! existingDeclarations.length() ) { kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; - dec = openDeclaration(node, originalAst ? originalAst : node); + dec = openDeclaration(node, originalAst ? originalAst : node); closeDeclaration(); dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); } @@ -124,16 +126,16 @@ Declaration* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) { - if ( node->name ) visitVariableDeclaration(node->name); // except Error as + if ( node->name ) visitVariableDeclaration(node->name); // except Error as DeclarationBuilderBase::visitExceptionHandler(node); } void DeclarationBuilder::visitFor(ForAst* node) { - if ( node->target->astType == Ast::NameAstType ) visitVariableDeclaration(node->target); + if ( node->target->astType == Ast::NameAstType ) visitVariableDeclaration(node->target); else if ( node->target->astType == Ast::TupleAstType ) { foreach ( ExpressionAst* tupleMember, dynamic_cast(node->target)->elements ) { - if ( tupleMember->astType == Ast::NameAstType ) visitVariableDeclaration(tupleMember); + if ( tupleMember->astType == Ast::NameAstType ) visitVariableDeclaration(tupleMember); } } Python::ContextBuilder::visitFor(node); @@ -146,9 +148,9 @@ void DeclarationBuilder::visitImport(ImportAst* node) TopDUContextPointer contextptr = contextsForModules.value(name->asName ? name->asName->identifier->value : name->name->value); kDebug() << "Chain for document: " << contextptr; m_importContextsForImportStatement.push(contextptr); - Declaration* dec; - if ( name->asName ) dec = visitVariableDeclaration(name->asName); - else dec = visitVariableDeclaration(name->name); + importedModuleDeclaration* dec; + if ( name->asName ) dec = visitVariableDeclaration(name->asName); + else dec = visitVariableDeclaration(name->name); QString moduleName = name->name->value; if ( name->asName && name->asName->identifier ) moduleName += name->asName->identifier->value; @@ -165,8 +167,8 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node) { Python::AstDefaultVisitor::visitImportFrom(node); foreach ( AliasAst* name, node->names ) { - if ( name->asName ) visitVariableDeclaration(name->asName); - else visitVariableDeclaration(name->name); + if ( name->asName ) visitVariableDeclaration(name->asName); + else visitVariableDeclaration(name->name); } } @@ -174,7 +176,7 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) { foreach ( ExpressionAst* target, node->targets ) { if ( target->astType == Ast::NameAstType ) { - visitVariableDeclaration(target); + visitVariableDeclaration(target); } } visitNode(node->value); @@ -230,7 +232,7 @@ void DeclarationBuilder::visitCall(CallAst* node) foreach ( ExpressionAst* currentArgument, node->arguments ) { NameAst* realArgument = dynamic_cast(currentArgument); if ( realArgument ) { - visitVariableDeclaration(realArgument); // some_func(, ) + visitVariableDeclaration(realArgument); // some_func(, ) } } Python::AstDefaultVisitor::visitCall(node); @@ -245,7 +247,7 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) foreach (ExpressionAst* expression, node->arguments) { realParam = dynamic_cast(expression); if ( realParam && realParam->context == ExpressionAst::Parameter ) { - Declaration* paramDeclaration = visitVariableDeclaration(realParam); + Declaration* paramDeclaration = visitVariableDeclaration(realParam); function->addDefaultParameter(IndexedString(realParam->identifier->value)); FunctionType::Ptr type = currentType(); if ( type && paramDeclaration ) type->addArgument(paramDeclaration->abstractType()); diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index ecd0bff..ce833cd 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -58,8 +58,8 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitExceptionHandler(ExceptionHandlerAst* node); virtual void visitCall(CallAst* node); - Declaration* visitVariableDeclaration(Ast* node); - Declaration* visitVariableDeclaration(Identifier* node, Ast* originalAst = 0); + template T* visitVariableDeclaration(Ast* node); + template T* visitVariableDeclaration(Identifier* node, Ast* originalAst = 0); QStack m_importContextsForImportStatement; diff --git a/duchain/declarations/.swp.importedmoduledeclaration.cpp b/duchain/declarations/.swp.importedmoduledeclaration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf74440f2ac52a46636ba772745b32c5a8e75d26 GIT binary patch literal 144 zcmZQzV36@nEJ;-eE>A2_aLdd|RnS!kOD!tS%+FIW)H4Y7WME)m17Z+hQ2+v0xDX3a mh%phtX9e+-5PXm}#$wmtARrB5gD^XS3sTO8;DStJbp-%uh7ni* literal 0 HcmV?d00001 diff --git a/duchain/declarations/CMakeLists.txt b/duchain/declarations/CMakeLists.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/duchain/declarations/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/duchain/declarations/importedmoduledeclaration.cpp b/duchain/declarations/importedmoduledeclaration.cpp new file mode 100644 index 0000000..96c6a32 --- /dev/null +++ b/duchain/declarations/importedmoduledeclaration.cpp @@ -0,0 +1,26 @@ +#include "importedmoduledeclaration.h" + +namespace Python { + +importedModuleDeclaration::importedModuleDeclaration(DeclarationData& dd): Declaration(dd) +{ + +} + +importedModuleDeclaration::importedModuleDeclaration(const KDevelop::RangeInRevision& range, DUContext* parentContext): Declaration(range, parentContext) +{ + +} + +importedModuleDeclaration::importedModuleDeclaration(const KDevelop::Declaration& rhs): Declaration(rhs) +{ + +} + +importedModuleDeclaration::importedModuleDeclaration(DeclarationData& dd, const KDevelop::RangeInRevision& range): Declaration(dd, range) +{ + +} + +} + diff --git a/duchain/declarations/importedmoduledeclaration.h b/duchain/declarations/importedmoduledeclaration.h new file mode 100644 index 0000000..b94216a --- /dev/null +++ b/duchain/declarations/importedmoduledeclaration.h @@ -0,0 +1,23 @@ +#ifndef IMPORTEDMODULEDECLARATION_H +#define IMPORTEDMODULEDECLARATION_H +#include +#include "pythonduchainexport.h" + +using namespace KDevelop; + +namespace Python { + +class KDEVPYTHONDUCHAIN_EXPORT importedModuleDeclaration : public Declaration +{ + +public: + importedModuleDeclaration(DeclarationData& dd); + importedModuleDeclaration(const KDevelop::RangeInRevision& range, DUContext* parentContext); + importedModuleDeclaration(DeclarationData& dd, const KDevelop::RangeInRevision& range); + importedModuleDeclaration(const KDevelop::Declaration& rhs); + QString m_moduleIdentifier; +}; + +} + +#endif // IMPORTEDMODULEDECLARATION_H diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 797c561..6c924c6 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -65,7 +65,7 @@ void UseBuilder::visitName(NameAst* node) Q_ASSERT(node->identifier); Q_ASSERT(node->hasUsefulRangeInformation); // TODO remove this! kDebug() << " Registeriung use for " << node->identifier->value << " at " << node->identifier->startLine << ":" << node->identifier->endCol << "->" << node->identifier->endLine << ":" << node->identifier->endCol + 1 << "with dec" << declaration; - UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), declaration); // +1 for whatever reason + UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), DeclarationPointer(declaration)); // +1 for whatever reason } From eab3b1c6268926fbfc29e7c8f85c8cf1bda9e76d Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 17 Nov 2010 00:37:36 +0100 Subject: [PATCH 086/118] First crappy code documentation implementation --- CMakeLists.txt | 1 + duchain/CMakeLists.txt | 2 +- duchain/declarationbuilder.cpp | 8 ++++-- .../.swp.importedmoduledeclaration.cpp | Bin 144 -> 0 bytes .../importedmoduledeclaration.cpp | 24 +++++++++++++++++- .../declarations/importedmoduledeclaration.h | 1 + .../declarationnavigationcontext.cpp | 17 ++++++++++--- .../navigation/declarationnavigationcontext.h | 6 ++++- 8 files changed, 51 insertions(+), 8 deletions(-) delete mode 100644 duchain/declarations/.swp.importedmoduledeclaration.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c45a236..83ee3e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,3 +58,4 @@ install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) install(FILES pythonpythonparser.py DESTINATION ${BIN_INSTALL_DIR}) +install(FILES documentation/pydoc.py DESTINATION ${BIN_INSTALL_DIR}) diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 3db0cef..a2cf8e4 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -31,4 +31,4 @@ install(TARGETS kdev4pythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(navigation) -add_subdirectory(declarations) \ No newline at end of file +add_subdirectory(declarations) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 159b3bd..822cfa4 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -156,8 +156,8 @@ void DeclarationBuilder::visitImport(ImportAst* node) moduleName += name->asName->identifier->value; if ( dec ) { DUChainWriteLocker lock(DUChain::lock()); - dec->setComment(";;module " + moduleName); - kDebug() << "Set comment to " << dec->comment(); + dec->m_moduleIdentifier = moduleName; + kDebug() << "Set comment to " << dec->m_moduleIdentifier; } m_importContextsForImportStatement.clear(); } @@ -167,8 +167,12 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node) { Python::AstDefaultVisitor::visitImportFrom(node); foreach ( AliasAst* name, node->names ) { + importedModuleDeclaration* dec = 0; if ( name->asName ) visitVariableDeclaration(name->asName); else visitVariableDeclaration(name->name); + if ( dec && name->name ) { + dec->m_moduleIdentifier = name->name->value; + } } } diff --git a/duchain/declarations/.swp.importedmoduledeclaration.cpp b/duchain/declarations/.swp.importedmoduledeclaration.cpp deleted file mode 100644 index bf74440f2ac52a46636ba772745b32c5a8e75d26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmZQzV36@nEJ;-eE>A2_aLdd|RnS!kOD!tS%+FIW)H4Y7WME)m17Z+hQ2+v0xDX3a mh%phtX9e+-5PXm}#$wmtARrB5gD^XS3sTO8;DStJbp-%uh7ni* diff --git a/duchain/declarations/importedmoduledeclaration.cpp b/duchain/declarations/importedmoduledeclaration.cpp index 96c6a32..d208cfc 100644 --- a/duchain/declarations/importedmoduledeclaration.cpp +++ b/duchain/declarations/importedmoduledeclaration.cpp @@ -1,10 +1,32 @@ #include "importedmoduledeclaration.h" +#include "parser/parserConfig.h" +#include namespace Python { +QString importedModuleDeclaration::generateDocumentationForModule() +{ + QProcess* parser = new QProcess(); + parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pydoc.py") << QString("-w") << QString(m_moduleIdentifier)); + parser->waitForFinished(); + kDebug() << " ** Reading results..."; + + // TODO this is not clean + if ( parser->exitStatus() != QProcess::NormalExit ) { + kError() << "Error parsing file: " << parser->errorString(); + return "0"; + } + + QString result = parser->readAllStandardOutput(); + + kDebug() << result; + + return result; +} + importedModuleDeclaration::importedModuleDeclaration(DeclarationData& dd): Declaration(dd) { - + } importedModuleDeclaration::importedModuleDeclaration(const KDevelop::RangeInRevision& range, DUContext* parentContext): Declaration(range, parentContext) diff --git a/duchain/declarations/importedmoduledeclaration.h b/duchain/declarations/importedmoduledeclaration.h index b94216a..ed579da 100644 --- a/duchain/declarations/importedmoduledeclaration.h +++ b/duchain/declarations/importedmoduledeclaration.h @@ -16,6 +16,7 @@ class KDEVPYTHONDUCHAIN_EXPORT importedModuleDeclaration : public Declaration importedModuleDeclaration(DeclarationData& dd, const KDevelop::RangeInRevision& range); importedModuleDeclaration(const KDevelop::Declaration& rhs); QString m_moduleIdentifier; + QString generateDocumentationForModule(); }; } diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 2eb8801..1547b43 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace Python { @@ -36,11 +37,21 @@ using namespace KDevelop; DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) : AbstractDeclarationNavigationContext(decl, topContext, previousContext) { - + kDebug() << "Generating declaration widget"; + importedModuleDeclaration* import_decl = dynamic_cast(decl.data()); + if ( import_decl ) { + kDebug() << " >> Module declaration found! Building documentation"; + kDebug() << " >> Identifier: " << import_decl->m_moduleIdentifier; + m_moduleDocumentation = import_decl->generateDocumentationForModule(); + } } -void DeclarationNavigationContext::htmlFunction() { - modifyHtml() += "
random.randint = randint(self, a, b) method of random.Random instance
Return random integer in range [a, b], including both end points.
"; +QString DeclarationNavigationContext::html(bool shorten) { + QString normalDoc = AbstractDeclarationNavigationContext::html(shorten); + if ( m_moduleDocumentation.length() ) { + normalDoc += "


" + m_moduleDocumentation; + } + return normalDoc; } NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration) diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h index cbb4c44..6c9cc1e 100644 --- a/duchain/navigation/declarationnavigationcontext.h +++ b/duchain/navigation/declarationnavigationcontext.h @@ -34,11 +34,15 @@ class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigat KDevelop::NavigationContextPointer registerChild(KDevelop::DeclarationPointer declaration); // virtual KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const; // virtual void htmlClass(); - virtual void htmlFunction(); +// virtual void htmlFunction(); + QString html(bool shorten = false); void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ); virtual QString declarationKind(KDevelop::DeclarationPointer decl); + +private: + QString m_moduleDocumentation; }; } From 75d45cc492ce919666d72a85155ed85c6e768129 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 18 Nov 2010 19:39:44 +0100 Subject: [PATCH 087/118] Added missing setModificationRevision() call on failed parse --- pythonparsejob.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 32ea428..9e5ece7 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -128,23 +128,6 @@ void ParseJob::run() IndexedString filename = KDevelop::IndexedString(m_url.pathOrUrl()); -// { -// DUChainWriteLocker lock(DUChain::lock()); -// -// m_duContext = DUChain::self()->chainForDocument(document()); -// if ( ! m_duContext ) { -// IndexedString langstring("python"); -// ParsingEnvironmentFile* file = new ParsingEnvironmentFile(document()); -// m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); -// m_duContext->setType(KDevelop::DUContext::Global); -// DUChain::self()->addDocumentChain(m_duContext); -// } -// m_duContext->clearProblems(); -// -// ParsingEnvironmentFilePointer file = m_duContext->parsingEnvironmentFile(); -// file.data()->setModificationRevision(contents().modification); -// } - // 2) parse QPair parserResults = m_session->parse(m_ast); m_ast = parserResults.first; @@ -203,6 +186,7 @@ void ParseJob::run() DUChainWriteLocker lock(DUChain::lock()); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); + m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); m_duContext->clearProblems(); } From 461f39790da972185b35d5e70344953c5fa84390 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 19 Nov 2010 20:22:37 +0100 Subject: [PATCH 088/118] Added not yet functional documentation thingy --- duchain/CMakeLists.txt | 1 + .../importedmoduledeclaration.cpp | 2 - .../declarationnavigationcontext.cpp | 4 +- duchain/navigation/navigationwidget.cpp | 41 +++++++++++++++++-- duchain/navigation/navigationwidget.h | 7 ++++ pythonparsejob.cpp | 1 + 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index a2cf8e4..b6e0d19 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -24,6 +24,7 @@ target_link_libraries( kdev4pythonduchain ${KDEVPLATFORM_PROJECT_LIBRARIES} ${KDE4_KTEXTEDITOR_LIBS} ${KDEVPLATFORM_INTERFACES_LIBRARIES} + ${QT_QTWEBKIT_LIBRARY} kdev4pythonparser ) diff --git a/duchain/declarations/importedmoduledeclaration.cpp b/duchain/declarations/importedmoduledeclaration.cpp index d208cfc..371e586 100644 --- a/duchain/declarations/importedmoduledeclaration.cpp +++ b/duchain/declarations/importedmoduledeclaration.cpp @@ -19,8 +19,6 @@ QString importedModuleDeclaration::generateDocumentationForModule() QString result = parser->readAllStandardOutput(); - kDebug() << result; - return result; } diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 1547b43..7718878 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -43,6 +43,7 @@ DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer de kDebug() << " >> Module declaration found! Building documentation"; kDebug() << " >> Identifier: " << import_decl->m_moduleIdentifier; m_moduleDocumentation = import_decl->generateDocumentationForModule(); + kDebug() << " << Done generating documentation"; } } @@ -51,7 +52,8 @@ QString DeclarationNavigationContext::html(bool shorten) { if ( m_moduleDocumentation.length() ) { normalDoc += "


" + m_moduleDocumentation; } - return normalDoc; +// return normalDoc; + return QString(); } NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration) diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index b749696..35e7d00 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -1,5 +1,13 @@ #include "navigationwidget.h" #include "declarationnavigationcontext.h" +#include +#include +#include +#include +#include +#include +#include +#include namespace Python { @@ -8,10 +16,35 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe kDebug() << "Navigation widget for Declaration requested"; m_topContext = topContext; - initBrowser(400); - m_startContext = new DeclarationNavigationContext(declaration, m_topContext); setContext(m_startContext); + + m_documentationWebView = new QWebView(this); + m_documentationWebView->load(QUrl("http://localhost:1050/")); + connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); + + delete layout(); + + QGridLayout* newLayout = new QGridLayout(); + newLayout->setRowMinimumHeight(0, 300); + newLayout->setColumnMinimumWidth(0, 400); + setLayout(newLayout); + layout()->addWidget(m_documentationWebView); + + initBrowser(400); +} + +void NavigationWidget::addDocumentationData(bool finished) +{ + kDebug() << "Done loading!"; + QWebElement document = m_documentationWebView->page()->mainFrame()->documentElement(); + if ( ! document.isNull() ) { + kDebug() << " >>> Trying to append documentation... "; + document.findFirst("body").appendInside("Hello World"); + } + else { + kError() << " !!! Could not append documentation to HTML page received!"; + } } NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) @@ -19,4 +52,6 @@ NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDe } -} \ No newline at end of file +} + +#include "navigationwidget.moc" \ No newline at end of file diff --git a/duchain/navigation/navigationwidget.h b/duchain/navigation/navigationwidget.h index 341ad43..401692a 100644 --- a/duchain/navigation/navigationwidget.h +++ b/duchain/navigation/navigationwidget.h @@ -4,11 +4,16 @@ #include #include #include "pythonduchainexport.h" +#include namespace Python { class KDEVPYTHONDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavigationWidget { +Q_OBJECT + +public slots: + void addDocumentationData(bool finished); public: NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); @@ -16,6 +21,8 @@ class KDEVPYTHONDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavig static QString shortDescription(KDevelop::Declaration* declaration) { return "Test"; }; static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; + + QWebView* m_documentationWebView; }; } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 9e5ece7..e042c0f 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -162,6 +162,7 @@ void ParseJob::run() DUChainWriteLocker lock(DUChain::lock()); ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); + parsingEnvironmentFile->clearModificationRevisions(); parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); m_duContext->clearProblems(); From db390a4cbaf8cc434d64e5c95bdcd32f0f16f4e0 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 19 Nov 2010 20:34:21 +0100 Subject: [PATCH 089/118] HTML display engine is ready for features now --- .../navigation/declarationnavigationcontext.cpp | 16 ++++++++-------- .../navigation/declarationnavigationcontext.h | 2 +- duchain/navigation/navigationwidget.cpp | 5 ++++- duchain/navigation/navigationwidget.h | 1 + 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 7718878..28ca31c 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -47,14 +47,14 @@ DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer de } } -QString DeclarationNavigationContext::html(bool shorten) { - QString normalDoc = AbstractDeclarationNavigationContext::html(shorten); - if ( m_moduleDocumentation.length() ) { - normalDoc += "


" + m_moduleDocumentation; - } -// return normalDoc; - return QString(); -} +// QString DeclarationNavigationContext::html(bool shorten) { +// QString normalDoc = AbstractDeclarationNavigationContext::html(shorten); +// if ( m_moduleDocumentation.length() ) { +// normalDoc += "


" + m_moduleDocumentation; +// } +// // return normalDoc; +// return QString(); +// } NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration) { diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h index 6c9cc1e..8f0e292 100644 --- a/duchain/navigation/declarationnavigationcontext.h +++ b/duchain/navigation/declarationnavigationcontext.h @@ -35,7 +35,7 @@ class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigat // virtual KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const; // virtual void htmlClass(); // virtual void htmlFunction(); - QString html(bool shorten = false); +// QString html(bool shorten = false); void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ); diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index 35e7d00..a4134ca 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -19,6 +19,8 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe m_startContext = new DeclarationNavigationContext(declaration, m_topContext); setContext(m_startContext); + m_originalHtml = m_startContext->html(); + m_documentationWebView = new QWebView(this); m_documentationWebView->load(QUrl("http://localhost:1050/")); connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); @@ -40,7 +42,8 @@ void NavigationWidget::addDocumentationData(bool finished) QWebElement document = m_documentationWebView->page()->mainFrame()->documentElement(); if ( ! document.isNull() ) { kDebug() << " >>> Trying to append documentation... "; - document.findFirst("body").appendInside("Hello World"); + kDebug() << document.findFirst("body").tagName(); + document.findFirst("body").findFirst("div").replace(m_originalHtml); } else { kError() << " !!! Could not append documentation to HTML page received!"; diff --git a/duchain/navigation/navigationwidget.h b/duchain/navigation/navigationwidget.h index 401692a..8234541 100644 --- a/duchain/navigation/navigationwidget.h +++ b/duchain/navigation/navigationwidget.h @@ -23,6 +23,7 @@ public slots: static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; QWebView* m_documentationWebView; + QString m_originalHtml; }; } From 3c95272565b1774665153bb2fb1b9be36869539c Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 19 Nov 2010 21:20:58 +0100 Subject: [PATCH 090/118] Removed python parser include --- parser/parsesession.h | 1 - 1 file changed, 1 deletion(-) diff --git a/parser/parsesession.h b/parser/parsesession.h index 09cd022..91f9b8f 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -25,7 +25,6 @@ #define PYTHON_PARSESESSION_H #include #include "parserexport.h" -#include "pythonparser.h" #include #include #include From a16ea65e2a911056ef8bac209a6666f9fb8db368 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 19 Nov 2010 21:24:19 +0100 Subject: [PATCH 091/118] Removed more orphaned dependencies --- parser/astbuilder.cpp | 1 - parser/pythondriver.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 6d974ec..d92718d 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -22,7 +22,6 @@ #include -#include "pythonparser.h" #include "ast.h" #include diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 6f4ac3f..15c4556 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -20,7 +20,6 @@ #include "pythondriver.h" -#include "pythonparser.h" #include #include From 6cedda140b303383a5246e2bdeb24da241d72363 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 19 Nov 2010 21:32:23 +0100 Subject: [PATCH 092/118] Reverted changes to documentation widget, links won't work in qwebview. --- duchain/navigation/navigationwidget.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index a4134ca..4e786c2 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -25,13 +25,11 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe m_documentationWebView->load(QUrl("http://localhost:1050/")); connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); - delete layout(); - QGridLayout* newLayout = new QGridLayout(); newLayout->setRowMinimumHeight(0, 300); newLayout->setColumnMinimumWidth(0, 400); - setLayout(newLayout); - layout()->addWidget(m_documentationWebView); + newLayout->addWidget(m_documentationWebView); + layout()->addItem(newLayout); initBrowser(400); } @@ -39,15 +37,15 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe void NavigationWidget::addDocumentationData(bool finished) { kDebug() << "Done loading!"; - QWebElement document = m_documentationWebView->page()->mainFrame()->documentElement(); - if ( ! document.isNull() ) { - kDebug() << " >>> Trying to append documentation... "; - kDebug() << document.findFirst("body").tagName(); - document.findFirst("body").findFirst("div").replace(m_originalHtml); - } - else { - kError() << " !!! Could not append documentation to HTML page received!"; - } +// QWebElement document = m_documentationWebView->page()->mainFrame()->documentElement(); +// if ( ! document.isNull() ) { +// kDebug() << " >>> Trying to append documentation... "; +// kDebug() << document.findFirst("body").tagName(); +// document.findFirst("body").findFirst("div").replace(m_originalHtml); +// } +// else { +// kError() << " !!! Could not append documentation to HTML page received!"; +// } } NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) From be3321dcbdf370d2bf5fc090310a119063a1e893 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 20 Nov 2010 02:27:39 +0100 Subject: [PATCH 093/118] Some bugfixes and pydoc adjustments --- documentation/pydoc.py | 2341 +++++++++++++++++ .../declarationnavigationcontext.cpp | 6 +- .../navigation/declarationnavigationcontext.h | 6 +- duchain/navigation/navigationwidget.cpp | 40 +- duchain/navigation/navigationwidget.h | 5 +- 5 files changed, 2375 insertions(+), 23 deletions(-) create mode 100755 documentation/pydoc.py diff --git a/documentation/pydoc.py b/documentation/pydoc.py new file mode 100755 index 0000000..a197c20 --- /dev/null +++ b/documentation/pydoc.py @@ -0,0 +1,2341 @@ +#!/usr/bin/env python +# -*- coding: latin-1 -*- +"""Generate Python documentation in HTML or text for interactive use. + +In the Python interpreter, do "from pydoc import help" to provide online +help. Calling help(thing) on a Python object documents the object. + +Or, at the shell command line outside of Python: + +Run "pydoc " to show documentation on something. may be +the name of a function, module, package, or a dotted reference to a +class or function within a module or module in a package. If the +argument contains a path segment delimiter (e.g. slash on Unix, +backslash on Windows) it is treated as the path to a Python source file. + +Run "pydoc -k " to search for a keyword in the synopsis lines +of all available modules. + +Run "pydoc -p " to start an HTTP server on a given port on the +local machine to generate documentation web pages. + +For platforms without a command line, "pydoc -g" starts the HTTP server +and also pops up a little window for controlling it. + +Run "pydoc -w " to write out the HTML documentation for a module +to a file named ".html". + +Module docs for core modules are assumed to be in + + http://docs.python.org/library/ + +This can be overridden by setting the PYTHONDOCS environment variable +to a different URL or to a local directory containing the Library +Reference Manual pages. +""" + +__author__ = "Ka-Ping Yee " +__date__ = "26 February 2001" + +__version__ = "$Revision: 79544 $" +__credits__ = """Guido van Rossum, for an excellent programming language. +Tommy Burnette, the original creator of manpy. +Paul Prescod, for all his work on onlinehelp. +Richard Chamberlain, for the first implementation of textdoc. +""" + +# Known bugs that can't be fixed here: +# - imp.load_module() cannot be prevented from clobbering existing +# loaded modules, so calling synopsis() on a binary module file +# changes the contents of any existing module with the same name. +# - If the __file__ attribute on a module is a relative path and +# the current directory is changed with os.chdir(), an incorrect +# path will be displayed. + +import sys, imp, os, re, types, inspect, __builtin__, pkgutil +from repr import Repr +from string import expandtabs, find, join, lower, split, strip, rfind, rstrip +from traceback import extract_tb +try: + from collections import deque +except ImportError: + # Python 2.3 compatibility + class deque(list): + def popleft(self): + return self.pop(0) + +# --------------------------------------------------------- common routines + +def pathdirs(): + """Convert sys.path into a list of absolute, existing, unique paths.""" + dirs = [] + normdirs = [] + for dir in sys.path: + dir = os.path.abspath(dir or '.') + normdir = os.path.normcase(dir) + if normdir not in normdirs and os.path.isdir(dir): + dirs.append(dir) + normdirs.append(normdir) + return dirs + +def getdoc(object): + """Get the doc string or comments for an object.""" + result = inspect.getdoc(object) or inspect.getcomments(object) + return result and re.sub('^ *\n', '', rstrip(result)) or '' + +def splitdoc(doc): + """Split a doc string into a synopsis line (if any) and the rest.""" + lines = split(strip(doc), '\n') + if len(lines) == 1: + return lines[0], '' + elif len(lines) >= 2 and not rstrip(lines[1]): + return lines[0], join(lines[2:], '\n') + return '', join(lines, '\n') + +def classname(object, modname): + """Get a class name and qualify it with a module name if necessary.""" + name = object.__name__ + if object.__module__ != modname: + name = object.__module__ + '.' + name + return name + +def isdata(object): + """Check if an object is of a type that probably means it's data.""" + return not (inspect.ismodule(object) or inspect.isclass(object) or + inspect.isroutine(object) or inspect.isframe(object) or + inspect.istraceback(object) or inspect.iscode(object)) + +def replace(text, *pairs): + """Do a series of global replacements on a string.""" + while pairs: + text = join(split(text, pairs[0]), pairs[1]) + pairs = pairs[2:] + return text + +def cram(text, maxlen): + """Omit part of a string if needed to make it fit in a maximum length.""" + if len(text) > maxlen: + pre = max(0, (maxlen-3)//2) + post = max(0, maxlen-3-pre) + return text[:pre] + '...' + text[len(text)-post:] + return text + +_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE) +def stripid(text): + """Remove the hexadecimal id from a Python object representation.""" + # The behaviour of %p is implementation-dependent in terms of case. + return _re_stripid.sub(r'\1', text) + +def _is_some_method(obj): + return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj) + +def allmethods(cl): + methods = {} + for key, value in inspect.getmembers(cl, _is_some_method): + methods[key] = 1 + for base in cl.__bases__: + methods.update(allmethods(base)) # all your base are belong to us + for key in methods.keys(): + methods[key] = getattr(cl, key) + return methods + +def _split_list(s, predicate): + """Split sequence s via predicate, and return pair ([true], [false]). + + The return value is a 2-tuple of lists, + ([x for x in s if predicate(x)], + [x for x in s if not predicate(x)]) + """ + + yes = [] + no = [] + for x in s: + if predicate(x): + yes.append(x) + else: + no.append(x) + return yes, no + +def visiblename(name, all=None): + """Decide whether to show documentation on a variable.""" + # Certain special names are redundant. + _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__', + '__module__', '__name__', '__slots__', '__package__') + if name in _hidden_names: return 0 + # Private names are hidden, but special names are displayed. + if name.startswith('__') and name.endswith('__'): return 1 + if all is not None: + # only document that which the programmer exported in __all__ + return name in all + else: + return not name.startswith('_') + +def classify_class_attrs(object): + """Wrap inspect.classify_class_attrs, with fixup for data descriptors.""" + def fixup(data): + name, kind, cls, value = data + if inspect.isdatadescriptor(value): + kind = 'data descriptor' + return name, kind, cls, value + return map(fixup, inspect.classify_class_attrs(object)) + +# ----------------------------------------------------- module manipulation + +def ispackage(path): + """Guess whether a path refers to a package directory.""" + if os.path.isdir(path): + for ext in ('.py', '.pyc', '.pyo'): + if os.path.isfile(os.path.join(path, '__init__' + ext)): + return True + return False + +def source_synopsis(file): + line = file.readline() + while line[:1] == '#' or not strip(line): + line = file.readline() + if not line: break + line = strip(line) + if line[:4] == 'r"""': line = line[1:] + if line[:3] == '"""': + line = line[3:] + if line[-1:] == '\\': line = line[:-1] + while not strip(line): + line = file.readline() + if not line: break + result = strip(split(line, '"""')[0]) + else: result = None + return result + +def synopsis(filename, cache={}): + """Get the one-line summary out of a module file.""" + mtime = os.stat(filename).st_mtime + lastupdate, result = cache.get(filename, (0, None)) + if lastupdate < mtime: + info = inspect.getmoduleinfo(filename) + try: + file = open(filename) + except IOError: + # module can't be opened, so skip it + return None + if info and 'b' in info[2]: # binary modules have to be imported + try: module = imp.load_module('__temp__', file, filename, info[1:]) + except: return None + result = (module.__doc__ or '').splitlines()[0] + del sys.modules['__temp__'] + else: # text modules can be directly examined + result = source_synopsis(file) + file.close() + cache[filename] = (mtime, result) + return result + +class ErrorDuringImport(Exception): + """Errors that occurred while trying to import something to document it.""" + def __init__(self, filename, exc_info): + exc, value, tb = exc_info + self.filename = filename + self.exc = exc + self.value = value + self.tb = tb + + def __str__(self): + exc = self.exc + if type(exc) is types.ClassType: + exc = exc.__name__ + return 'problem in %s - %s: %s' % (self.filename, exc, self.value) + +def importfile(path): + """Import a Python source file or compiled file given its path.""" + magic = imp.get_magic() + file = open(path, 'r') + if file.read(len(magic)) == magic: + kind = imp.PY_COMPILED + else: + kind = imp.PY_SOURCE + file.close() + filename = os.path.basename(path) + name, ext = os.path.splitext(filename) + file = open(path, 'r') + try: + module = imp.load_module(name, file, path, (ext, 'r', kind)) + except: + raise ErrorDuringImport(path, sys.exc_info()) + file.close() + return module + +def safeimport(path, forceload=0, cache={}): + """Import a module; handle errors; return None if the module isn't found. + + If the module *is* found but an exception occurs, it's wrapped in an + ErrorDuringImport exception and reraised. Unlike __import__, if a + package path is specified, the module at the end of the path is returned, + not the package at the beginning. If the optional 'forceload' argument + is 1, we reload the module from disk (unless it's a dynamic extension).""" + try: + # If forceload is 1 and the module has been previously loaded from + # disk, we always have to reload the module. Checking the file's + # mtime isn't good enough (e.g. the module could contain a class + # that inherits from another module that has changed). + if forceload and path in sys.modules: + if path not in sys.builtin_module_names: + # Avoid simply calling reload() because it leaves names in + # the currently loaded module lying around if they're not + # defined in the new source file. Instead, remove the + # module from sys.modules and re-import. Also remove any + # submodules because they won't appear in the newly loaded + # module's namespace if they're already in sys.modules. + subs = [m for m in sys.modules if m.startswith(path + '.')] + for key in [path] + subs: + # Prevent garbage collection. + cache[key] = sys.modules[key] + del sys.modules[key] + module = __import__(path) + except: + # Did the error occur before or after the module was found? + (exc, value, tb) = info = sys.exc_info() + if path in sys.modules: + # An error occurred while executing the imported module. + raise ErrorDuringImport(sys.modules[path].__file__, info) + elif exc is SyntaxError: + # A SyntaxError occurred before we could execute the module. + raise ErrorDuringImport(value.filename, info) + elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport': + # The import error occurred directly in this function, + # which means there is no such module in the path. + return None + else: + # Some other error occurred during the importing process. + raise ErrorDuringImport(path, sys.exc_info()) + for part in split(path, '.')[1:]: + try: module = getattr(module, part) + except AttributeError: return None + return module + +# ---------------------------------------------------- formatter base class + +class Doc: + def document(self, object, name=None, *args): + """Generate documentation for an object.""" + args = (object, name) + args + # 'try' clause is to attempt to handle the possibility that inspect + # identifies something in a way that pydoc itself has issues handling; + # think 'super' and how it is a descriptor (which raises the exception + # by lacking a __name__ attribute) and an instance. + if inspect.isgetsetdescriptor(object): return self.docdata(*args) + if inspect.ismemberdescriptor(object): return self.docdata(*args) + try: + if inspect.ismodule(object): return self.docmodule(*args) + if inspect.isclass(object): return self.docclass(*args) + if inspect.isroutine(object): return self.docroutine(*args) + except AttributeError: + pass + if isinstance(object, property): return self.docproperty(*args) + return self.docother(*args) + + def fail(self, object, name=None, *args): + """Raise an exception for unimplemented types.""" + message = "don't know how to document object%s of type %s" % ( + name and ' ' + repr(name), type(object).__name__) + raise TypeError, message + + docmodule = docclass = docroutine = docother = docproperty = docdata = fail + + def getdocloc(self, object): + """Return the location of module docs or None""" + + try: + file = inspect.getabsfile(object) + except TypeError: + file = '(built-in)' + + docloc = os.environ.get("PYTHONDOCS", + "http://docs.python.org/library") + basedir = os.path.join(sys.exec_prefix, "lib", + "python"+sys.version[0:3]) + if (isinstance(object, type(os)) and + (object.__name__ in ('errno', 'exceptions', 'gc', 'imp', + 'marshal', 'posix', 'signal', 'sys', + 'thread', 'zipimport') or + (file.startswith(basedir) and + not file.startswith(os.path.join(basedir, 'site-packages')))) and + object.__name__ not in ('xml.etree', 'test.pydoc_mod')): + if docloc.startswith("http://"): + docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__) + else: + docloc = os.path.join(docloc, object.__name__ + ".html") + else: + docloc = None + return docloc + +# -------------------------------------------- HTML documentation generator + +class HTMLRepr(Repr): + """Class for safely making an HTML representation of a Python object.""" + def __init__(self): + Repr.__init__(self) + self.maxlist = self.maxtuple = 20 + self.maxdict = 10 + self.maxstring = self.maxother = 100 + + def escape(self, text): + return replace(text, '&', '&', '<', '<', '>', '>') + + def repr(self, object): + return Repr.repr(self, object) + + def repr1(self, x, level): + if hasattr(type(x), '__name__'): + methodname = 'repr_' + join(split(type(x).__name__), '_') + if hasattr(self, methodname): + return getattr(self, methodname)(x, level) + return self.escape(cram(stripid(repr(x)), self.maxother)) + + def repr_string(self, x, level): + test = cram(x, self.maxstring) + testrepr = repr(test) + if '\\' in test and '\\' not in replace(testrepr, r'\\', ''): + # Backslashes are only literal in the string and are never + # needed to make any special characters, so show a raw string. + return 'r' + testrepr[0] + self.escape(test) + testrepr[0] + return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)', + r'\1', + self.escape(testrepr)) + + repr_str = repr_string + + def repr_instance(self, x, level): + try: + return self.escape(cram(stripid(repr(x)), self.maxstring)) + except: + return self.escape('<%s instance>' % x.__class__.__name__) + + repr_unicode = repr_string + +class HTMLDoc(Doc): + """Formatter class for HTML documentation.""" + + # ------------------------------------------- HTML formatting utilities + + _repr_instance = HTMLRepr() + repr = _repr_instance.repr + escape = _repr_instance.escape + + def page(self, title, contents): + """Format an HTML page.""" + return ''' + +Python: %s + + +%s +''' % (title, contents) + + def heading(self, title, fgcol, bgcol, extras=''): + """Format a page heading.""" + return '''

%s

%s''' % (fgcol, title, extras or ' ') + + def section(self, title, fgcol, bgcol, contents, width=6, + prelude='', marginalia=None, gap=' '): + """Format a section with a heading.""" + if marginalia is None: + marginalia = '' + ' ' * width + '' + result = '''

%s

''' % (bgcol, bgcol, title) + if prelude: + result = result + '''
%s
''' % (prelude) + + return result + '\n%s
' % contents + + def bigsection(self, title, *args): + """Format a section with a big heading.""" + title = '%s' % title + return self.section(title, *args) + + def preformat(self, text): + """Format literal preformatted text.""" + text = self.escape(expandtabs(text)) + return replace(text, '\n\n', '\n \n', '\n\n', '\n \n', + ' ', ' ', '\n', '
\n') + + def multicolumn(self, list, format, cols=3): + """Format a list of items into a multi-column list.""" + result = '' + rows = (len(list)+cols-1)/cols + for col in range(cols): + result = result + '' % (100/cols) + for i in range(rows*col, rows*col+rows): + if i < len(list): + result = result + format(list[i]) + '
\n' + result = result + '' + return '%s
' % result + + def grey(self, text): return '%s' % text + + def namelink(self, name, *dicts): + """Make a link for an identifier, given name-to-URL mappings.""" + for dict in dicts: + if name in dict: + return '%s' % (dict[name], name) + return name + + def classlink(self, object, modname): + """Make a link for a class.""" + name, module = object.__name__, sys.modules.get(object.__module__) + if hasattr(module, name) and getattr(module, name) is object: + return '%s' % ( + module.__name__, name, classname(object, modname)) + return classname(object, modname) + + def modulelink(self, object): + """Make a link for a module.""" + return '%s' % (object.__name__, object.__name__) + + def modpkglink(self, data): + """Make a link for a module or package to display in an index.""" + name, path, ispackage, shadowed = data + if shadowed: + return self.grey(name) + if path: + url = '%s.%s.html' % (path, name) + else: + url = '%s.html' % name + if ispackage: + text = '%s (package)' % name + else: + text = name + return '%s' % (url, text) + + def markup(self, text, escape=None, funcs={}, classes={}, methods={}): + """Mark up some plain text, given a context of symbols to look for. + Each context dictionary maps object names to anchor names.""" + escape = escape or self.escape + results = [] + here = 0 + pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|' + r'RFC[- ]?(\d+)|' + r'PEP[- ]?(\d+)|' + r'(self\.)?(\w+))') + while True: + match = pattern.search(text, here) + if not match: break + start, end = match.span() + results.append(escape(text[here:start])) + + all, scheme, rfc, pep, selfdot, name = match.groups() + if scheme: + url = escape(all).replace('"', '"') + results.append('%s' % (url, url)) + elif rfc: + url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc) + results.append('%s' % (url, escape(all))) + elif pep: + url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep) + results.append('%s' % (url, escape(all))) + elif text[end:end+1] == '(': + results.append(self.namelink(name, methods, funcs, classes)) + elif selfdot: + results.append('self.%s' % name) + else: + results.append(self.namelink(name, classes)) + here = end + results.append(escape(text[here:])) + return join(results, '') + + # ---------------------------------------------- type-specific routines + + def formattree(self, tree, modname, parent=None): + """Produce HTML for a class tree as given by inspect.getclasstree().""" + result = '' + for entry in tree: + if type(entry) is type(()): + c, bases = entry + result = result + '' + result = result + self.classlink(c, modname) + if bases and bases != (parent,): + parents = [] + for base in bases: + parents.append(self.classlink(base, modname)) + result = result + '(' + join(parents, ', ') + ')' + result = result + '\n' + elif type(entry) is type([]): + result = result + '
\n%s
\n' % self.formattree( + entry, modname, c) + return '
\n%s
\n' % result + + def docmodule(self, object, name=None, mod=None, *ignored): + """Produce HTML documentation for a module object.""" + name = object.__name__ # ignore the passed-in name + try: + all = object.__all__ + except AttributeError: + all = None + parts = split(name, '.') + links = [] + for i in range(len(parts)-1): + links.append( + '%s' % + (join(parts[:i+1], '.'), parts[i])) + linkedname = join(links + parts[-1:], '.') + head = '%s' % linkedname + try: + path = inspect.getabsfile(object) + url = path + if sys.platform == 'win32': + import nturl2path + url = nturl2path.pathname2url(path) + filelink = '%s' % (url, path) + except TypeError: + filelink = '(built-in)' + info = [] + if hasattr(object, '__version__'): + version = str(object.__version__) + if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': + version = strip(version[11:-1]) + info.append('version %s' % self.escape(version)) + if hasattr(object, '__date__'): + info.append(self.escape(str(object.__date__))) + if info: + head = head + ' (%s)' % join(info, ', ') + docloc = self.getdocloc(object) + if docloc is not None: + docloc = '
Module Docs' % locals() + else: + docloc = '' + result = self.heading( + head, '#ffffff', '#7799ee', + 'index
' + filelink + docloc) + + modules = inspect.getmembers(object, inspect.ismodule) + + classes, cdict = [], {} + for key, value in inspect.getmembers(object, inspect.isclass): + # if __all__ exists, believe it. Otherwise use old heuristic. + if (all is not None or + (inspect.getmodule(value) or object) is object): + if visiblename(key, all): + classes.append((key, value)) + cdict[key] = cdict[value] = '#' + key + for key, value in classes: + for base in value.__bases__: + key, modname = base.__name__, base.__module__ + module = sys.modules.get(modname) + if modname != name and module and hasattr(module, key): + if getattr(module, key) is base: + if not key in cdict: + cdict[key] = cdict[base] = modname + '.html#' + key + funcs, fdict = [], {} + for key, value in inspect.getmembers(object, inspect.isroutine): + # if __all__ exists, believe it. Otherwise use old heuristic. + if (all is not None or + inspect.isbuiltin(value) or inspect.getmodule(value) is object): + if visiblename(key, all): + funcs.append((key, value)) + fdict[key] = '#-' + key + if inspect.isfunction(value): fdict[value] = fdict[key] + data = [] + for key, value in inspect.getmembers(object, isdata): + if visiblename(key, all): + data.append((key, value)) + + doc = self.markup(getdoc(object), self.preformat, fdict, cdict) + doc = doc and '%s' % doc + result = result + '

%s

\n' % doc + + if hasattr(object, '__path__'): + modpkgs = [] + for importer, modname, ispkg in pkgutil.iter_modules(object.__path__): + modpkgs.append((modname, name, ispkg, 0)) + modpkgs.sort() + contents = self.multicolumn(modpkgs, self.modpkglink) + result = result + self.bigsection( + 'Package Contents', '#ffffff', '#aa55cc', contents) + elif modules: + contents = self.multicolumn( + modules, lambda key_value, s=self: s.modulelink(key_value[1])) + result = result + self.bigsection( + 'Modules', '#ffffff', '#aa55cc', contents) + + if classes: + classlist = map(lambda key_value: key_value[1], classes) + contents = [ + self.formattree(inspect.getclasstree(classlist, 1), name)] + for key, value in classes: + contents.append(self.document(value, key, name, fdict, cdict)) + result = result + self.bigsection( + 'Classes', '#ffffff', '#ee77aa', join(contents)) + if funcs: + contents = [] + for key, value in funcs: + contents.append(self.document(value, key, name, fdict, cdict)) + result = result + self.bigsection( + 'Functions', '#ffffff', '#eeaa77', join(contents)) + if data: + contents = [] + for key, value in data: + contents.append(self.document(value, key)) + result = result + self.bigsection( + 'Data', '#ffffff', '#55aa55', join(contents, '
\n')) + if hasattr(object, '__author__'): + contents = self.markup(str(object.__author__), self.preformat) + result = result + self.bigsection( + 'Author', '#ffffff', '#7799ee', contents) + if hasattr(object, '__credits__'): + contents = self.markup(str(object.__credits__), self.preformat) + result = result + self.bigsection( + 'Credits', '#ffffff', '#7799ee', contents) + + return result + + def docclass(self, object, name=None, mod=None, funcs={}, classes={}, + *ignored): + """Produce HTML documentation for a class object.""" + realname = object.__name__ + name = name or realname + bases = object.__bases__ + + contents = [] + push = contents.append + + # Cute little class to pump out a horizontal rule between sections. + class HorizontalRule: + def __init__(self): + self.needone = 0 + def maybe(self): + if self.needone: + push('
\n') + self.needone = 1 + hr = HorizontalRule() + + # List the mro, if non-trivial. + mro = deque(inspect.getmro(object)) + if len(mro) > 2: + hr.maybe() + push('
Method resolution order:
\n') + for base in mro: + push('
%s
\n' % self.classlink(base, + object.__module__)) + push('
\n') + + def spill(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + push(self.document(getattr(object, name), name, mod, + funcs, classes, mdict, object)) + push('\n') + return attrs + + def spilldescriptors(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + push(self._docdescriptor(name, value, mod)) + return attrs + + def spilldata(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + base = self.docother(getattr(object, name), name, mod) + if (hasattr(value, '__call__') or + inspect.isdatadescriptor(value)): + doc = getattr(value, "__doc__", None) + else: + doc = None + if doc is None: + push('
%s
\n' % base) + else: + doc = self.markup(getdoc(value), self.preformat, + funcs, classes, mdict) + doc = '
%s' % doc + push('
%s%s
\n' % (base, doc)) + push('\n') + return attrs + + attrs = filter(lambda data: visiblename(data[0]), + classify_class_attrs(object)) + mdict = {} + for key, kind, homecls, value in attrs: + mdict[key] = anchor = '#' + name + '-' + key + value = getattr(object, key) + try: + # The value may not be hashable (e.g., a data attr with + # a dict or list value). + mdict[value] = anchor + except TypeError: + pass + + while attrs: + if mro: + thisclass = mro.popleft() + else: + thisclass = attrs[0][2] + attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass) + + if thisclass is __builtin__.object: + attrs = inherited + continue + elif thisclass is object: + tag = 'defined here' + else: + tag = 'inherited from %s' % self.classlink(thisclass, + object.__module__) + tag += ':
\n' + + # Sort attrs by name. + try: + attrs.sort(key=lambda t: t[0]) + except TypeError: + attrs.sort(lambda t1, t2: cmp(t1[0], t2[0])) # 2.3 compat + + # Pump out the attrs, segregated by kind. + attrs = spill('Methods %s' % tag, attrs, + lambda t: t[1] == 'method') + attrs = spill('Class methods %s' % tag, attrs, + lambda t: t[1] == 'class method') + attrs = spill('Static methods %s' % tag, attrs, + lambda t: t[1] == 'static method') + attrs = spilldescriptors('Data descriptors %s' % tag, attrs, + lambda t: t[1] == 'data descriptor') + attrs = spilldata('Data and other attributes %s' % tag, attrs, + lambda t: t[1] == 'data') + assert attrs == [] + attrs = inherited + + contents = ''.join(contents) + + if name == realname: + title = 'class %s' % ( + name, realname) + else: + title = '%s = class %s' % ( + name, name, realname) + if bases: + parents = [] + for base in bases: + parents.append(self.classlink(base, object.__module__)) + title = title + '(%s)' % join(parents, ', ') + doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict) + doc = doc and '%s
 
' % doc + + return self.section(title, '#000000', '#ffc8d8', contents, 3, doc) + + def formatvalue(self, object): + """Format an argument default value as text.""" + return self.grey('=' + self.repr(object)) + + def docroutine(self, object, name=None, mod=None, + funcs={}, classes={}, methods={}, cl=None): + """Produce HTML documentation for a function or method object.""" + realname = object.__name__ + name = name or realname + anchor = (cl and cl.__name__ or '') + '-' + name + note = '' + skipdocs = 0 + if inspect.ismethod(object): + imclass = object.im_class + if cl: + if imclass is not cl: + note = ' from ' + self.classlink(imclass, mod) + else: + if object.im_self is not None: + note = ' method of %s instance' % self.classlink( + object.im_self.__class__, mod) + else: + note = ' unbound %s method' % self.classlink(imclass,mod) + object = object.im_func + + if name == realname: + title = '%s' % (anchor, realname) + else: + if (cl and realname in cl.__dict__ and + cl.__dict__[realname] is object): + reallink = '%s' % ( + cl.__name__ + '-' + realname, realname) + skipdocs = 1 + else: + reallink = realname + title = '%s = %s' % ( + anchor, name, reallink) + if inspect.isfunction(object): + args, varargs, varkw, defaults = inspect.getargspec(object) + argspec = inspect.formatargspec( + args, varargs, varkw, defaults, formatvalue=self.formatvalue) + if realname == '': + title = '%s lambda ' % name + argspec = argspec[1:-1] # remove parentheses + else: + argspec = '(...)' + + decl = title + argspec + (note and self.grey( + '%s' % note)) + + if skipdocs: + return '
%s
\n' % decl + else: + doc = self.markup( + getdoc(object), self.preformat, funcs, classes, methods) + doc = doc and '
%s
' % doc + return '
%s
%s
\n' % (decl, doc) + + def _docdescriptor(self, name, value, mod): + results = [] + push = results.append + + if name: + push('
%s
\n' % name) + if value.__doc__ is not None: + doc = self.markup(getdoc(value), self.preformat) + push('
%s
\n' % doc) + push('
\n') + + return ''.join(results) + + def docproperty(self, object, name=None, mod=None, cl=None): + """Produce html documentation for a property.""" + return self._docdescriptor(name, object, mod) + + def docother(self, object, name=None, mod=None, *ignored): + """Produce HTML documentation for a data object.""" + lhs = name and '%s = ' % name or '' + return lhs + self.repr(object) + + def docdata(self, object, name=None, mod=None, cl=None): + """Produce html documentation for a data descriptor.""" + return self._docdescriptor(name, object, mod) + + def index(self, dir, shadowed=None): + """Generate an HTML index for a directory of modules.""" + modpkgs = [] + if shadowed is None: shadowed = {} + for importer, name, ispkg in pkgutil.iter_modules([dir]): + modpkgs.append((name, '', ispkg, name in shadowed)) + shadowed[name] = 1 + + modpkgs.sort() + contents = self.multicolumn(modpkgs, self.modpkglink) + return self.bigsection(dir, '#ffffff', '#ee77aa', contents) + +# -------------------------------------------- text documentation generator + +class TextRepr(Repr): + """Class for safely making a text representation of a Python object.""" + def __init__(self): + Repr.__init__(self) + self.maxlist = self.maxtuple = 20 + self.maxdict = 10 + self.maxstring = self.maxother = 100 + + def repr1(self, x, level): + if hasattr(type(x), '__name__'): + methodname = 'repr_' + join(split(type(x).__name__), '_') + if hasattr(self, methodname): + return getattr(self, methodname)(x, level) + return cram(stripid(repr(x)), self.maxother) + + def repr_string(self, x, level): + test = cram(x, self.maxstring) + testrepr = repr(test) + if '\\' in test and '\\' not in replace(testrepr, r'\\', ''): + # Backslashes are only literal in the string and are never + # needed to make any special characters, so show a raw string. + return 'r' + testrepr[0] + test + testrepr[0] + return testrepr + + repr_str = repr_string + + def repr_instance(self, x, level): + try: + return cram(stripid(repr(x)), self.maxstring) + except: + return '<%s instance>' % x.__class__.__name__ + +class TextDoc(Doc): + """Formatter class for text documentation.""" + + # ------------------------------------------- text formatting utilities + + _repr_instance = TextRepr() + repr = _repr_instance.repr + + def bold(self, text): + """Format a string in bold by overstriking.""" + return join(map(lambda ch: ch + '\b' + ch, text), '') + + def indent(self, text, prefix=' '): + """Indent text by prepending a given prefix to each line.""" + if not text: return '' + lines = split(text, '\n') + lines = map(lambda line, prefix=prefix: prefix + line, lines) + if lines: lines[-1] = rstrip(lines[-1]) + return join(lines, '\n') + + def section(self, title, contents): + """Format a section with a given heading.""" + return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n' + + # ---------------------------------------------- type-specific routines + + def formattree(self, tree, modname, parent=None, prefix=''): + """Render in text a class tree as returned by inspect.getclasstree().""" + result = '' + for entry in tree: + if type(entry) is type(()): + c, bases = entry + result = result + prefix + classname(c, modname) + if bases and bases != (parent,): + parents = map(lambda c, m=modname: classname(c, m), bases) + result = result + '(%s)' % join(parents, ', ') + result = result + '\n' + elif type(entry) is type([]): + result = result + self.formattree( + entry, modname, c, prefix + ' ') + return result + + def docmodule(self, object, name=None, mod=None): + """Produce text documentation for a given module object.""" + name = object.__name__ # ignore the passed-in name + synop, desc = splitdoc(getdoc(object)) + result = self.section('NAME', name + (synop and ' - ' + synop)) + + try: + all = object.__all__ + except AttributeError: + all = None + + try: + file = inspect.getabsfile(object) + except TypeError: + file = '(built-in)' + result = result + self.section('FILE', file) + + docloc = self.getdocloc(object) + if docloc is not None: + result = result + self.section('MODULE DOCS', docloc) + + if desc: + result = result + self.section('DESCRIPTION', desc) + + classes = [] + for key, value in inspect.getmembers(object, inspect.isclass): + # if __all__ exists, believe it. Otherwise use old heuristic. + if (all is not None + or (inspect.getmodule(value) or object) is object): + if visiblename(key, all): + classes.append((key, value)) + funcs = [] + for key, value in inspect.getmembers(object, inspect.isroutine): + # if __all__ exists, believe it. Otherwise use old heuristic. + if (all is not None or + inspect.isbuiltin(value) or inspect.getmodule(value) is object): + if visiblename(key, all): + funcs.append((key, value)) + data = [] + for key, value in inspect.getmembers(object, isdata): + if visiblename(key, all): + data.append((key, value)) + + modpkgs = [] + modpkgs_names = set() + if hasattr(object, '__path__'): + for importer, modname, ispkg in pkgutil.iter_modules(object.__path__): + modpkgs_names.add(modname) + if ispkg: + modpkgs.append(modname + ' (package)') + else: + modpkgs.append(modname) + + modpkgs.sort() + result = result + self.section( + 'PACKAGE CONTENTS', join(modpkgs, '\n')) + + # Detect submodules as sometimes created by C extensions + submodules = [] + for key, value in inspect.getmembers(object, inspect.ismodule): + if value.__name__.startswith(name + '.') and key not in modpkgs_names: + submodules.append(key) + if submodules: + submodules.sort() + result = result + self.section( + 'SUBMODULES', join(submodules, '\n')) + + if classes: + classlist = map(lambda key_value: key_value[1], classes) + contents = [self.formattree( + inspect.getclasstree(classlist, 1), name)] + for key, value in classes: + contents.append(self.document(value, key, name)) + result = result + self.section('CLASSES', join(contents, '\n')) + + if funcs: + contents = [] + for key, value in funcs: + contents.append(self.document(value, key, name)) + result = result + self.section('FUNCTIONS', join(contents, '\n')) + + if data: + contents = [] + for key, value in data: + contents.append(self.docother(value, key, name, maxlen=70)) + result = result + self.section('DATA', join(contents, '\n')) + + if hasattr(object, '__version__'): + version = str(object.__version__) + if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': + version = strip(version[11:-1]) + result = result + self.section('VERSION', version) + if hasattr(object, '__date__'): + result = result + self.section('DATE', str(object.__date__)) + if hasattr(object, '__author__'): + result = result + self.section('AUTHOR', str(object.__author__)) + if hasattr(object, '__credits__'): + result = result + self.section('CREDITS', str(object.__credits__)) + return result + + def docclass(self, object, name=None, mod=None): + """Produce text documentation for a given class object.""" + realname = object.__name__ + name = name or realname + bases = object.__bases__ + + def makename(c, m=object.__module__): + return classname(c, m) + + if name == realname: + title = 'class ' + self.bold(realname) + else: + title = self.bold(name) + ' = class ' + realname + if bases: + parents = map(makename, bases) + title = title + '(%s)' % join(parents, ', ') + + doc = getdoc(object) + contents = doc and [doc + '\n'] or [] + push = contents.append + + # List the mro, if non-trivial. + mro = deque(inspect.getmro(object)) + if len(mro) > 2: + push("Method resolution order:") + for base in mro: + push(' ' + makename(base)) + push('') + + # Cute little class to pump out a horizontal rule between sections. + class HorizontalRule: + def __init__(self): + self.needone = 0 + def maybe(self): + if self.needone: + push('-' * 70) + self.needone = 1 + hr = HorizontalRule() + + def spill(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + push(self.document(getattr(object, name), + name, mod, object)) + return attrs + + def spilldescriptors(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + push(self._docdescriptor(name, value, mod)) + return attrs + + def spilldata(msg, attrs, predicate): + ok, attrs = _split_list(attrs, predicate) + if ok: + hr.maybe() + push(msg) + for name, kind, homecls, value in ok: + if (hasattr(value, '__call__') or + inspect.isdatadescriptor(value)): + doc = getdoc(value) + else: + doc = None + push(self.docother(getattr(object, name), + name, mod, maxlen=70, doc=doc) + '\n') + return attrs + + attrs = filter(lambda data: visiblename(data[0]), + classify_class_attrs(object)) + while attrs: + if mro: + thisclass = mro.popleft() + else: + thisclass = attrs[0][2] + attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass) + + if thisclass is __builtin__.object: + attrs = inherited + continue + elif thisclass is object: + tag = "defined here" + else: + tag = "inherited from %s" % classname(thisclass, + object.__module__) + + # Sort attrs by name. + attrs.sort() + + # Pump out the attrs, segregated by kind. + attrs = spill("Methods %s:\n" % tag, attrs, + lambda t: t[1] == 'method') + attrs = spill("Class methods %s:\n" % tag, attrs, + lambda t: t[1] == 'class method') + attrs = spill("Static methods %s:\n" % tag, attrs, + lambda t: t[1] == 'static method') + attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs, + lambda t: t[1] == 'data descriptor') + attrs = spilldata("Data and other attributes %s:\n" % tag, attrs, + lambda t: t[1] == 'data') + assert attrs == [] + attrs = inherited + + contents = '\n'.join(contents) + if not contents: + return title + '\n' + return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n' + + def formatvalue(self, object): + """Format an argument default value as text.""" + return '=' + self.repr(object) + + def docroutine(self, object, name=None, mod=None, cl=None): + """Produce text documentation for a function or method object.""" + realname = object.__name__ + name = name or realname + note = '' + skipdocs = 0 + if inspect.ismethod(object): + imclass = object.im_class + if cl: + if imclass is not cl: + note = ' from ' + classname(imclass, mod) + else: + if object.im_self is not None: + note = ' method of %s instance' % classname( + object.im_self.__class__, mod) + else: + note = ' unbound %s method' % classname(imclass,mod) + object = object.im_func + + if name == realname: + title = self.bold(realname) + else: + if (cl and realname in cl.__dict__ and + cl.__dict__[realname] is object): + skipdocs = 1 + title = self.bold(name) + ' = ' + realname + if inspect.isfunction(object): + args, varargs, varkw, defaults = inspect.getargspec(object) + argspec = inspect.formatargspec( + args, varargs, varkw, defaults, formatvalue=self.formatvalue) + if realname == '': + title = self.bold(name) + ' lambda ' + argspec = argspec[1:-1] # remove parentheses + else: + argspec = '(...)' + decl = title + argspec + note + + if skipdocs: + return decl + '\n' + else: + doc = getdoc(object) or '' + return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n') + + def _docdescriptor(self, name, value, mod): + results = [] + push = results.append + + if name: + push(self.bold(name)) + push('\n') + doc = getdoc(value) or '' + if doc: + push(self.indent(doc)) + push('\n') + return ''.join(results) + + def docproperty(self, object, name=None, mod=None, cl=None): + """Produce text documentation for a property.""" + return self._docdescriptor(name, object, mod) + + def docdata(self, object, name=None, mod=None, cl=None): + """Produce text documentation for a data descriptor.""" + return self._docdescriptor(name, object, mod) + + def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None): + """Produce text documentation for a data object.""" + repr = self.repr(object) + if maxlen: + line = (name and name + ' = ' or '') + repr + chop = maxlen - len(line) + if chop < 0: repr = repr[:chop] + '...' + line = (name and self.bold(name) + ' = ' or '') + repr + if doc is not None: + line += '\n' + self.indent(str(doc)) + return line + +# --------------------------------------------------------- user interfaces + +def pager(text): + """The first time this is called, determine what kind of pager to use.""" + global pager + pager = getpager() + pager(text) + +def getpager(): + """Decide what method to use for paging through text.""" + if type(sys.stdout) is not types.FileType: + return plainpager + if not sys.stdin.isatty() or not sys.stdout.isatty(): + return plainpager + if 'PAGER' in os.environ: + if sys.platform == 'win32': # pipes completely broken in Windows + return lambda text: tempfilepager(plain(text), os.environ['PAGER']) + elif os.environ.get('TERM') in ('dumb', 'emacs'): + return lambda text: pipepager(plain(text), os.environ['PAGER']) + else: + return lambda text: pipepager(text, os.environ['PAGER']) + if os.environ.get('TERM') in ('dumb', 'emacs'): + return plainpager + if sys.platform == 'win32' or sys.platform.startswith('os2'): + return lambda text: tempfilepager(plain(text), 'more <') + if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: + return lambda text: pipepager(text, 'less') + + import tempfile + (fd, filename) = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: + return lambda text: pipepager(text, 'more') + else: + return ttypager + finally: + os.unlink(filename) + +def plain(text): + """Remove boldface formatting from text.""" + return re.sub('.\b', '', text) + +def pipepager(text, cmd): + """Page through text by feeding it to another program.""" + pipe = os.popen(cmd, 'w') + try: + pipe.write(text) + pipe.close() + except IOError: + pass # Ignore broken pipes caused by quitting the pager program. + +def tempfilepager(text, cmd): + """Page through text by invoking a program on a temporary file.""" + import tempfile + filename = tempfile.mktemp() + file = open(filename, 'w') + file.write(text) + file.close() + try: + os.system(cmd + ' "' + filename + '"') + finally: + os.unlink(filename) + +def ttypager(text): + """Page through text on a text terminal.""" + lines = split(plain(text), '\n') + try: + import tty + fd = sys.stdin.fileno() + old = tty.tcgetattr(fd) + tty.setcbreak(fd) + getchar = lambda: sys.stdin.read(1) + except (ImportError, AttributeError): + tty = None + getchar = lambda: sys.stdin.readline()[:-1][:1] + + try: + r = inc = os.environ.get('LINES', 25) - 1 + sys.stdout.write(join(lines[:inc], '\n') + '\n') + while lines[r:]: + sys.stdout.write('-- more --') + sys.stdout.flush() + c = getchar() + + if c in ('q', 'Q'): + sys.stdout.write('\r \r') + break + elif c in ('\r', '\n'): + sys.stdout.write('\r \r' + lines[r] + '\n') + r = r + 1 + continue + if c in ('b', 'B', '\x1b'): + r = r - inc - inc + if r < 0: r = 0 + sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n') + r = r + inc + + finally: + if tty: + tty.tcsetattr(fd, tty.TCSAFLUSH, old) + +def plainpager(text): + """Simply print unformatted text. This is the ultimate fallback.""" + sys.stdout.write(plain(text)) + +def describe(thing): + """Produce a short description of the given thing.""" + if inspect.ismodule(thing): + if thing.__name__ in sys.builtin_module_names: + return 'built-in module ' + thing.__name__ + if hasattr(thing, '__path__'): + return 'package ' + thing.__name__ + else: + return 'module ' + thing.__name__ + if inspect.isbuiltin(thing): + return 'built-in function ' + thing.__name__ + if inspect.isgetsetdescriptor(thing): + return 'getset descriptor %s.%s.%s' % ( + thing.__objclass__.__module__, thing.__objclass__.__name__, + thing.__name__) + if inspect.ismemberdescriptor(thing): + return 'member descriptor %s.%s.%s' % ( + thing.__objclass__.__module__, thing.__objclass__.__name__, + thing.__name__) + if inspect.isclass(thing): + return 'class ' + thing.__name__ + if inspect.isfunction(thing): + return 'function ' + thing.__name__ + if inspect.ismethod(thing): + return 'method ' + thing.__name__ + if type(thing) is types.InstanceType: + return 'instance of ' + thing.__class__.__name__ + return type(thing).__name__ + +def locate(path, forceload=0): + """Locate an object by name or dotted path, importing as necessary.""" + parts = [part for part in split(path, '.') if part] + module, n = None, 0 + while n < len(parts): + nextmodule = safeimport(join(parts[:n+1], '.'), forceload) + if nextmodule: module, n = nextmodule, n + 1 + else: break + if module: + object = module + for part in parts[n:]: + try: object = getattr(object, part) + except AttributeError: return None + return object + else: + if hasattr(__builtin__, path): + return getattr(__builtin__, path) + +# --------------------------------------- interactive interpreter interface + +text = TextDoc() +html = HTMLDoc() + +class _OldStyleClass: pass +_OLD_INSTANCE_TYPE = type(_OldStyleClass()) + +def resolve(thing, forceload=0): + """Given an object or a path to an object, get the object and its name.""" + if isinstance(thing, str): + object = locate(thing, forceload) + if not object: + raise ImportError, 'no Python documentation found for %r' % thing + return object, thing + else: + return thing, getattr(thing, '__name__', None) + +def render_doc(thing, title='Python Library Documentation: %s', forceload=0): + """Render text documentation, given an object or a path to an object.""" + object, name = resolve(thing, forceload) + desc = describe(object) + module = inspect.getmodule(object) + if name and '.' in name: + desc += ' in ' + name[:name.rfind('.')] + elif module and module is not object: + desc += ' in module ' + module.__name__ + if type(object) is _OLD_INSTANCE_TYPE: + # If the passed object is an instance of an old-style class, + # document its available methods instead of its value. + object = object.__class__ + elif not (inspect.ismodule(object) or + inspect.isclass(object) or + inspect.isroutine(object) or + inspect.isgetsetdescriptor(object) or + inspect.ismemberdescriptor(object) or + isinstance(object, property)): + # If the passed object is a piece of data or an instance, + # document its available methods instead of its value. + object = type(object) + desc += ' object' + return title % desc + '\n\n' + text.document(object, name) + +def doc(thing, title='Python Library Documentation: %s', forceload=0): + """Display text documentation, given an object or a path to an object.""" + try: + pager(render_doc(thing, title, forceload)) + except (ImportError, ErrorDuringImport), value: + print value + +def writedoc(thing, forceload=0): + """Write HTML documentation to a file in the current directory.""" + try: + object, name = resolve(thing, forceload) + page = html.page(describe(object), html.document(object, name)) + sys.stdout.write(page) + #file = open(name + '.html', 'w') + #file.write(page) + #file.close() + #print 'wrote', name + '.html' + except (ImportError, ErrorDuringImport), value: + print value + +def writedocs(dir, pkgpath='', done=None): + """Write out HTML documentation for all modules in a directory tree.""" + if done is None: done = {} + for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath): + writedoc(modname) + return + +class Helper: + + # These dictionaries map a topic name to either an alias, or a tuple + # (label, seealso-items). The "label" is the label of the corresponding + # section in the .rst file under Doc/ and an index into the dictionary + # in pydoc_topics.py. + # + # CAUTION: if you change one of these dictionaries, be sure to adapt the + # list of needed labels in Doc/tools/sphinxext/pyspecific.py and + # regenerate the pydoc_topics.py file by running + # make pydoc-topics + # in Doc/ and copying the output file into the Lib/ directory. + + keywords = { + 'and': 'BOOLEAN', + 'as': 'with', + 'assert': ('assert', ''), + 'break': ('break', 'while for'), + 'class': ('class', 'CLASSES SPECIALMETHODS'), + 'continue': ('continue', 'while for'), + 'def': ('function', ''), + 'del': ('del', 'BASICMETHODS'), + 'elif': 'if', + 'else': ('else', 'while for'), + 'except': 'try', + 'exec': ('exec', ''), + 'finally': 'try', + 'for': ('for', 'break continue while'), + 'from': 'import', + 'global': ('global', 'NAMESPACES'), + 'if': ('if', 'TRUTHVALUE'), + 'import': ('import', 'MODULES'), + 'in': ('in', 'SEQUENCEMETHODS2'), + 'is': 'COMPARISON', + 'lambda': ('lambda', 'FUNCTIONS'), + 'not': 'BOOLEAN', + 'or': 'BOOLEAN', + 'pass': ('pass', ''), + 'print': ('print', ''), + 'raise': ('raise', 'EXCEPTIONS'), + 'return': ('return', 'FUNCTIONS'), + 'try': ('try', 'EXCEPTIONS'), + 'while': ('while', 'break continue if TRUTHVALUE'), + 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'), + 'yield': ('yield', ''), + } + # Either add symbols to this dictionary or to the symbols dictionary + # directly: Whichever is easier. They are merged later. + _symbols_inverse = { + 'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'), + 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&', + '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'), + 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'), + 'UNARY' : ('-', '~'), + 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=', + '^=', '<<=', '>>=', '**=', '//='), + 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'), + 'COMPLEX' : ('j', 'J') + } + symbols = { + '%': 'OPERATORS FORMATTING', + '**': 'POWER', + ',': 'TUPLES LISTS FUNCTIONS', + '.': 'ATTRIBUTES FLOAT MODULES OBJECTS', + '...': 'ELLIPSIS', + ':': 'SLICINGS DICTIONARYLITERALS', + '@': 'def class', + '\\': 'STRINGS', + '_': 'PRIVATENAMES', + '__': 'PRIVATENAMES SPECIALMETHODS', + '`': 'BACKQUOTES', + '(': 'TUPLES FUNCTIONS CALLS', + ')': 'TUPLES FUNCTIONS CALLS', + '[': 'LISTS SUBSCRIPTS SLICINGS', + ']': 'LISTS SUBSCRIPTS SLICINGS' + } + for topic, symbols_ in _symbols_inverse.iteritems(): + for symbol in symbols_: + topics = symbols.get(symbol, topic) + if topic not in topics: + topics = topics + ' ' + topic + symbols[symbol] = topics + + topics = { + 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS ' + 'FUNCTIONS CLASSES MODULES FILES inspect'), + 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING ' + 'TYPES'), + 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'), + 'FORMATTING': ('formatstrings', 'OPERATORS'), + 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS ' + 'FORMATTING TYPES'), + 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'), + 'INTEGER': ('integers', 'int range'), + 'FLOAT': ('floating', 'float math'), + 'COMPLEX': ('imaginary', 'complex cmath'), + 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'), + 'MAPPINGS': 'DICTIONARIES', + 'FUNCTIONS': ('typesfunctions', 'def TYPES'), + 'METHODS': ('typesmethods', 'class def CLASSES TYPES'), + 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'), + 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'), + 'FRAMEOBJECTS': 'TYPES', + 'TRACEBACKS': 'TYPES', + 'NONE': ('bltin-null-object', ''), + 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'), + 'FILES': ('bltin-file-objects', ''), + 'SPECIALATTRIBUTES': ('specialattrs', ''), + 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'), + 'MODULES': ('typesmodules', 'import'), + 'PACKAGES': 'import', + 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN ' + 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER ' + 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES ' + 'LISTS DICTIONARIES BACKQUOTES'), + 'OPERATORS': 'EXPRESSIONS', + 'PRECEDENCE': 'EXPRESSIONS', + 'OBJECTS': ('objects', 'TYPES'), + 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS ' + 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS ' + 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'), + 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'), + 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'), + 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'), + 'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 ' + 'SPECIALMETHODS'), + 'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 ' + 'SPECIALMETHODS'), + 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'), + 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT ' + 'SPECIALMETHODS'), + 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'), + 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'), + 'DYNAMICFEATURES': ('dynamic-features', ''), + 'SCOPING': 'NAMESPACES', + 'FRAMES': 'NAMESPACES', + 'EXCEPTIONS': ('exceptions', 'try except finally raise'), + 'COERCIONS': ('coercion-rules','CONVERSIONS'), + 'CONVERSIONS': ('conversions', 'COERCIONS'), + 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'), + 'SPECIALIDENTIFIERS': ('id-classes', ''), + 'PRIVATENAMES': ('atom-identifiers', ''), + 'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS ' + 'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'), + 'TUPLES': 'SEQUENCES', + 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'), + 'LISTS': ('typesseq-mutable', 'LISTLITERALS'), + 'LISTLITERALS': ('lists', 'LISTS LITERALS'), + 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'), + 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'), + 'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'), + 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ' + 'ATTRIBUTEMETHODS'), + 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'), + 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'), + 'CALLS': ('calls', 'EXPRESSIONS'), + 'POWER': ('power', 'EXPRESSIONS'), + 'UNARY': ('unary', 'EXPRESSIONS'), + 'BINARY': ('binary', 'EXPRESSIONS'), + 'SHIFTING': ('shifting', 'EXPRESSIONS'), + 'BITWISE': ('bitwise', 'EXPRESSIONS'), + 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'), + 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'), + 'ASSERTION': 'assert', + 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'), + 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'), + 'DELETION': 'del', + 'PRINTING': 'print', + 'RETURNING': 'return', + 'IMPORTING': 'import', + 'CONDITIONAL': 'if', + 'LOOPING': ('compound', 'for while break continue'), + 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'), + 'DEBUGGING': ('debugger', 'pdb'), + 'CONTEXTMANAGERS': ('context-managers', 'with'), + } + + def __init__(self, input, output): + self.input = input + self.output = output + + def __repr__(self): + if inspect.stack()[1][3] == '?': + self() + return '' + return '' + + def __call__(self, request=None): + if request is not None: + self.help(request) + else: + self.intro() + self.interact() + self.output.write(''' +You are now leaving help and returning to the Python interpreter. +If you want to ask for help on a particular object directly from the +interpreter, you can type "help(object)". Executing "help('string')" +has the same effect as typing a particular string at the help> prompt. +''') + + def interact(self): + self.output.write('\n') + while True: + try: + request = self.getline('help> ') + if not request: break + except (KeyboardInterrupt, EOFError): + break + request = strip(replace(request, '"', '', "'", '')) + if lower(request) in ('q', 'quit'): break + self.help(request) + + def getline(self, prompt): + """Read one line, using raw_input when available.""" + if self.input is sys.stdin: + return raw_input(prompt) + else: + self.output.write(prompt) + self.output.flush() + return self.input.readline() + + def help(self, request): + if type(request) is type(''): + request = request.strip() + if request == 'help': self.intro() + elif request == 'keywords': self.listkeywords() + elif request == 'symbols': self.listsymbols() + elif request == 'topics': self.listtopics() + elif request == 'modules': self.listmodules() + elif request[:8] == 'modules ': + self.listmodules(split(request)[1]) + elif request in self.symbols: self.showsymbol(request) + elif request in self.keywords: self.showtopic(request) + elif request in self.topics: self.showtopic(request) + elif request: doc(request, 'Help on %s:') + elif isinstance(request, Helper): self() + else: doc(request, 'Help on %s:') + self.output.write('\n') + + def intro(self): + self.output.write(''' +Welcome to Python %s! This is the online help utility. + +If this is your first time using Python, you should definitely check out +the tutorial on the Internet at http://docs.python.org/tutorial/. + +Enter the name of any module, keyword, or topic to get help on writing +Python programs and using Python modules. To quit this help utility and +return to the interpreter, just type "quit". + +To get a list of available modules, keywords, or topics, type "modules", +"keywords", or "topics". Each module also comes with a one-line summary +of what it does; to list the modules whose summaries contain a given word +such as "spam", type "modules spam". +''' % sys.version[:3]) + + def list(self, items, columns=4, width=80): + items = items[:] + items.sort() + colw = width / columns + rows = (len(items) + columns - 1) / columns + for row in range(rows): + for col in range(columns): + i = col * rows + row + if i < len(items): + self.output.write(items[i]) + if col < columns - 1: + self.output.write(' ' + ' ' * (colw-1 - len(items[i]))) + self.output.write('\n') + + def listkeywords(self): + self.output.write(''' +Here is a list of the Python keywords. Enter any keyword to get more help. + +''') + self.list(self.keywords.keys()) + + def listsymbols(self): + self.output.write(''' +Here is a list of the punctuation symbols which Python assigns special meaning +to. Enter any symbol to get more help. + +''') + self.list(self.symbols.keys()) + + def listtopics(self): + self.output.write(''' +Here is a list of available topics. Enter any topic name to get more help. + +''') + self.list(self.topics.keys()) + + def showtopic(self, topic, more_xrefs=''): + try: + import pydoc_topics + except ImportError: + self.output.write(''' +Sorry, topic and keyword documentation is not available because the +module "pydoc_topics" could not be found. +''') + return + target = self.topics.get(topic, self.keywords.get(topic)) + if not target: + self.output.write('no documentation found for %s\n' % repr(topic)) + return + if type(target) is type(''): + return self.showtopic(target, more_xrefs) + + label, xrefs = target + try: + doc = pydoc_topics.topics[label] + except KeyError: + self.output.write('no documentation found for %s\n' % repr(topic)) + return + pager(strip(doc) + '\n') + if more_xrefs: + xrefs = (xrefs or '') + ' ' + more_xrefs + if xrefs: + import StringIO, formatter + buffer = StringIO.StringIO() + formatter.DumbWriter(buffer).send_flowing_data( + 'Related help topics: ' + join(split(xrefs), ', ') + '\n') + self.output.write('\n%s\n' % buffer.getvalue()) + + def showsymbol(self, symbol): + target = self.symbols[symbol] + topic, _, xrefs = target.partition(' ') + self.showtopic(topic, xrefs) + + def listmodules(self, key=''): + if key: + self.output.write(''' +Here is a list of matching modules. Enter any module name to get more help. + +''') + apropos(key) + else: + self.output.write(''' +Please wait a moment while I gather a list of all available modules... + +''') + modules = {} + def callback(path, modname, desc, modules=modules): + if modname and modname[-9:] == '.__init__': + modname = modname[:-9] + ' (package)' + if find(modname, '.') < 0: + modules[modname] = 1 + def onerror(modname): + callback(None, modname, None) + ModuleScanner().run(callback, onerror=onerror) + self.list(modules.keys()) + self.output.write(''' +Enter any module name to get more help. Or, type "modules spam" to search +for modules whose descriptions contain the word "spam". +''') + +help = Helper(sys.stdin, sys.stdout) + +class Scanner: + """A generic tree iterator.""" + def __init__(self, roots, children, descendp): + self.roots = roots[:] + self.state = [] + self.children = children + self.descendp = descendp + + def next(self): + if not self.state: + if not self.roots: + return None + root = self.roots.pop(0) + self.state = [(root, self.children(root))] + node, children = self.state[-1] + if not children: + self.state.pop() + return self.next() + child = children.pop(0) + if self.descendp(child): + self.state.append((child, self.children(child))) + return child + + +class ModuleScanner: + """An interruptible scanner that searches module synopses.""" + + def run(self, callback, key=None, completer=None, onerror=None): + if key: key = lower(key) + self.quit = False + seen = {} + + for modname in sys.builtin_module_names: + if modname != '__main__': + seen[modname] = 1 + if key is None: + callback(None, modname, '') + else: + desc = split(__import__(modname).__doc__ or '', '\n')[0] + if find(lower(modname + ' - ' + desc), key) >= 0: + callback(None, modname, desc) + + for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror): + if self.quit: + break + if key is None: + callback(None, modname, '') + else: + loader = importer.find_module(modname) + if hasattr(loader,'get_source'): + import StringIO + desc = source_synopsis( + StringIO.StringIO(loader.get_source(modname)) + ) or '' + if hasattr(loader,'get_filename'): + path = loader.get_filename(modname) + else: + path = None + else: + module = loader.load_module(modname) + desc = (module.__doc__ or '').splitlines()[0] + path = getattr(module,'__file__',None) + if find(lower(modname + ' - ' + desc), key) >= 0: + callback(path, modname, desc) + + if completer: + completer() + +def apropos(key): + """Print all the one-line module summaries that contain a substring.""" + def callback(path, modname, desc): + if modname[-9:] == '.__init__': + modname = modname[:-9] + ' (package)' + print modname, desc and '- ' + desc + try: import warnings + except ImportError: pass + else: warnings.filterwarnings('ignore') # ignore problems during import + ModuleScanner().run(callback, key) + +# --------------------------------------------------- web browser interface + +def serve(port, callback=None, completer=None): + import BaseHTTPServer, mimetools, select + + # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded. + class Message(mimetools.Message): + def __init__(self, fp, seekable=1): + Message = self.__class__ + Message.__bases__[0].__bases__[0].__init__(self, fp, seekable) + self.encodingheader = self.getheader('content-transfer-encoding') + self.typeheader = self.getheader('content-type') + self.parsetype() + self.parseplist() + + class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler): + def send_document(self, title, contents): + try: + self.send_response(200) + self.send_header('Content-Type', 'text/html') + self.end_headers() + self.wfile.write(html.page(title, contents)) + except IOError: pass + + def do_GET(self): + path = self.path + if path[-5:] == '.html': path = path[:-5] + if path[:1] == '/': path = path[1:] + if path and path != '.': + try: + obj = locate(path, forceload=1) + except ErrorDuringImport, value: + self.send_document(path, html.escape(str(value))) + return + if obj: + self.send_document(describe(obj), html.document(obj, path)) + else: + self.send_document(path, +'no Python documentation found for %s' % repr(path)) + else: + heading = html.heading( +'Python: Index of Modules', +'#ffffff', '#7799ee') + def bltinlink(name): + return '%s' % (name, name) + names = filter(lambda x: x != '__main__', + sys.builtin_module_names) + contents = html.multicolumn(names, bltinlink) + indices = ['

' + html.bigsection( + 'Built-in Modules', '#ffffff', '#ee77aa', contents)] + + seen = {} + for dir in sys.path: + indices.append(html.index(dir, seen)) + contents = heading + join(indices) + '''

+ +pydoc by Ka-Ping Yee <ping@lfw.org>''' + self.send_document('Index of Modules', contents) + + def log_message(self, *args): pass + + class DocServer(BaseHTTPServer.HTTPServer): + def __init__(self, port, callback): + host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost' + self.address = ('', port) + self.url = 'http://%s:%d/' % (host, port) + self.callback = callback + self.base.__init__(self, self.address, self.handler) + + def serve_until_quit(self): + import select + self.quit = False + while not self.quit: + rd, wr, ex = select.select([self.socket.fileno()], [], [], 1) + if rd: self.handle_request() + + def server_activate(self): + self.base.server_activate(self) + if self.callback: self.callback(self) + + DocServer.base = BaseHTTPServer.HTTPServer + DocServer.handler = DocHandler + DocHandler.MessageClass = Message + try: + try: + DocServer(port, callback).serve_until_quit() + except (KeyboardInterrupt, select.error): + pass + finally: + if completer: completer() + +# ----------------------------------------------------- graphical interface + +def gui(): + """Graphical interface (starts web server and pops up a control window).""" + class GUI: + def __init__(self, window, port=7464): + self.window = window + self.server = None + self.scanner = None + + import Tkinter + self.server_frm = Tkinter.Frame(window) + self.title_lbl = Tkinter.Label(self.server_frm, + text='Starting server...\n ') + self.open_btn = Tkinter.Button(self.server_frm, + text='open browser', command=self.open, state='disabled') + self.quit_btn = Tkinter.Button(self.server_frm, + text='quit serving', command=self.quit, state='disabled') + + self.search_frm = Tkinter.Frame(window) + self.search_lbl = Tkinter.Label(self.search_frm, text='Search for') + self.search_ent = Tkinter.Entry(self.search_frm) + self.search_ent.bind('', self.search) + self.stop_btn = Tkinter.Button(self.search_frm, + text='stop', pady=0, command=self.stop, state='disabled') + if sys.platform == 'win32': + # Trying to hide and show this button crashes under Windows. + self.stop_btn.pack(side='right') + + self.window.title('pydoc') + self.window.protocol('WM_DELETE_WINDOW', self.quit) + self.title_lbl.pack(side='top', fill='x') + self.open_btn.pack(side='left', fill='x', expand=1) + self.quit_btn.pack(side='right', fill='x', expand=1) + self.server_frm.pack(side='top', fill='x') + + self.search_lbl.pack(side='left') + self.search_ent.pack(side='right', fill='x', expand=1) + self.search_frm.pack(side='top', fill='x') + self.search_ent.focus_set() + + font = ('helvetica', sys.platform == 'win32' and 8 or 10) + self.result_lst = Tkinter.Listbox(window, font=font, height=6) + self.result_lst.bind('', self.select) + self.result_lst.bind('', self.goto) + self.result_scr = Tkinter.Scrollbar(window, + orient='vertical', command=self.result_lst.yview) + self.result_lst.config(yscrollcommand=self.result_scr.set) + + self.result_frm = Tkinter.Frame(window) + self.goto_btn = Tkinter.Button(self.result_frm, + text='go to selected', command=self.goto) + self.hide_btn = Tkinter.Button(self.result_frm, + text='hide results', command=self.hide) + self.goto_btn.pack(side='left', fill='x', expand=1) + self.hide_btn.pack(side='right', fill='x', expand=1) + + self.window.update() + self.minwidth = self.window.winfo_width() + self.minheight = self.window.winfo_height() + self.bigminheight = (self.server_frm.winfo_reqheight() + + self.search_frm.winfo_reqheight() + + self.result_lst.winfo_reqheight() + + self.result_frm.winfo_reqheight()) + self.bigwidth, self.bigheight = self.minwidth, self.bigminheight + self.expanded = 0 + self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight)) + self.window.wm_minsize(self.minwidth, self.minheight) + self.window.tk.willdispatch() + + import threading + threading.Thread( + target=serve, args=(port, self.ready, self.quit)).start() + + def ready(self, server): + self.server = server + self.title_lbl.config( + text='Python documentation server at\n' + server.url) + self.open_btn.config(state='normal') + self.quit_btn.config(state='normal') + + def open(self, event=None, url=None): + url = url or self.server.url + try: + import webbrowser + webbrowser.open(url) + except ImportError: # pre-webbrowser.py compatibility + if sys.platform == 'win32': + os.system('start "%s"' % url) + elif sys.platform == 'mac': + try: import ic + except ImportError: pass + else: ic.launchurl(url) + else: + rc = os.system('netscape -remote "openURL(%s)" &' % url) + if rc: os.system('netscape "%s" &' % url) + + def quit(self, event=None): + if self.server: + self.server.quit = 1 + self.window.quit() + + def search(self, event=None): + key = self.search_ent.get() + self.stop_btn.pack(side='right') + self.stop_btn.config(state='normal') + self.search_lbl.config(text='Searching for "%s"...' % key) + self.search_ent.forget() + self.search_lbl.pack(side='left') + self.result_lst.delete(0, 'end') + self.goto_btn.config(state='disabled') + self.expand() + + import threading + if self.scanner: + self.scanner.quit = 1 + self.scanner = ModuleScanner() + threading.Thread(target=self.scanner.run, + args=(self.update, key, self.done)).start() + + def update(self, path, modname, desc): + if modname[-9:] == '.__init__': + modname = modname[:-9] + ' (package)' + self.result_lst.insert('end', + modname + ' - ' + (desc or '(no description)')) + + def stop(self, event=None): + if self.scanner: + self.scanner.quit = 1 + self.scanner = None + + def done(self): + self.scanner = None + self.search_lbl.config(text='Search for') + self.search_lbl.pack(side='left') + self.search_ent.pack(side='right', fill='x', expand=1) + if sys.platform != 'win32': self.stop_btn.forget() + self.stop_btn.config(state='disabled') + + def select(self, event=None): + self.goto_btn.config(state='normal') + + def goto(self, event=None): + selection = self.result_lst.curselection() + if selection: + modname = split(self.result_lst.get(selection[0]))[0] + self.open(url=self.server.url + modname + '.html') + + def collapse(self): + if not self.expanded: return + self.result_frm.forget() + self.result_scr.forget() + self.result_lst.forget() + self.bigwidth = self.window.winfo_width() + self.bigheight = self.window.winfo_height() + self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight)) + self.window.wm_minsize(self.minwidth, self.minheight) + self.expanded = 0 + + def expand(self): + if self.expanded: return + self.result_frm.pack(side='bottom', fill='x') + self.result_scr.pack(side='right', fill='y') + self.result_lst.pack(side='top', fill='both', expand=1) + self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight)) + self.window.wm_minsize(self.minwidth, self.bigminheight) + self.expanded = 1 + + def hide(self, event=None): + self.stop() + self.collapse() + + import Tkinter + try: + root = Tkinter.Tk() + # Tk will crash if pythonw.exe has an XP .manifest + # file and the root has is not destroyed explicitly. + # If the problem is ever fixed in Tk, the explicit + # destroy can go. + try: + gui = GUI(root) + root.mainloop() + finally: + root.destroy() + except KeyboardInterrupt: + pass + +# -------------------------------------------------- command-line interface + +def ispath(x): + return isinstance(x, str) and find(x, os.sep) >= 0 + +def cli(): + """Command-line interface (looks at sys.argv to decide what to do).""" + import getopt + class BadUsage: pass + + # Scripts don't get the current directory in their path by default + # unless they are run with the '-m' switch + if '' not in sys.path: + scriptdir = os.path.dirname(sys.argv[0]) + if scriptdir in sys.path: + sys.path.remove(scriptdir) + sys.path.insert(0, '.') + + try: + opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w') + writing = 0 + + for opt, val in opts: + if opt == '-g': + gui() + return + if opt == '-k': + apropos(val) + return + if opt == '-p': + try: + port = int(val) + except ValueError: + raise BadUsage + def ready(server): + print 'pydoc server ready at %s' % server.url + def stopped(): + print 'pydoc server stopped' + serve(port, ready, stopped) + return + if opt == '-w': + writing = 1 + + if not args: raise BadUsage + for arg in args: + if ispath(arg) and not os.path.exists(arg): + print 'file %r does not exist' % arg + break + try: + if ispath(arg) and os.path.isfile(arg): + arg = importfile(arg) + if writing: + if ispath(arg) and os.path.isdir(arg): + writedocs(arg) + else: + writedoc(arg) + else: + help.help(arg) + except ErrorDuringImport, value: + print value + + except (getopt.error, BadUsage): + cmd = os.path.basename(sys.argv[0]) + print """pydoc - the Python documentation tool + +%s ... + Show text documentation on something. may be the name of a + Python keyword, topic, function, module, or package, or a dotted + reference to a class or function within a module or module in a + package. If contains a '%s', it is used as the path to a + Python source file to document. If name is 'keywords', 'topics', + or 'modules', a listing of these things is displayed. + +%s -k + Search for a keyword in the synopsis lines of all available modules. + +%s -p + Start an HTTP server on the given port on the local machine. + +%s -g + Pop up a graphical interface for finding and serving documentation. + +%s -w ... + Write out the HTML documentation for a module to a file in the current + directory. If contains a '%s', it is treated as a filename; if + it names a directory, documentation is written for all the contents. +""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep) + +if __name__ == '__main__': cli() diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 28ca31c..25b0cc4 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -42,8 +42,10 @@ DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer de if ( import_decl ) { kDebug() << " >> Module declaration found! Building documentation"; kDebug() << " >> Identifier: " << import_decl->m_moduleIdentifier; - m_moduleDocumentation = import_decl->generateDocumentationForModule(); - kDebug() << " << Done generating documentation"; + m_fullyQualifiedModuleIdentifier = import_decl->m_moduleIdentifier; + } + else { + kDebug() << "Could not find declaration for this module!" << decl->identifier().identifier().str(); } } diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h index 8f0e292..6a8057c 100644 --- a/duchain/navigation/declarationnavigationcontext.h +++ b/duchain/navigation/declarationnavigationcontext.h @@ -30,6 +30,8 @@ class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigat public: DeclarationNavigationContext(KDevelop::DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, KDevelop::AbstractNavigationContext* previousContext = 0); + QString m_fullyQualifiedModuleIdentifier; + protected: KDevelop::NavigationContextPointer registerChild(KDevelop::DeclarationPointer declaration); // virtual KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const; @@ -40,9 +42,7 @@ class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigat void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ); virtual QString declarationKind(KDevelop::DeclarationPointer decl); - -private: - QString m_moduleDocumentation; + }; } diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index 4e786c2..21712b3 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -11,32 +11,40 @@ namespace Python { -NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) +NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& /* htmlPrefix */, const QString& /* htmlSuffix */) { kDebug() << "Navigation widget for Declaration requested"; m_topContext = topContext; - m_startContext = new DeclarationNavigationContext(declaration, m_topContext); - setContext(m_startContext); - - m_originalHtml = m_startContext->html(); - - m_documentationWebView = new QWebView(this); - m_documentationWebView->load(QUrl("http://localhost:1050/")); - connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); + initBrowser(400); - QGridLayout* newLayout = new QGridLayout(); - newLayout->setRowMinimumHeight(0, 300); - newLayout->setColumnMinimumWidth(0, 400); - newLayout->addWidget(m_documentationWebView); - layout()->addItem(newLayout); + DeclarationNavigationContext* context = new DeclarationNavigationContext(declaration, m_topContext); + m_startContext = context; + setContext(m_startContext); - initBrowser(400); + m_fullyQualifiedModuleIdentifier = context->m_fullyQualifiedModuleIdentifier; + kDebug() << "Identifier: " << m_fullyQualifiedModuleIdentifier; + if ( m_fullyQualifiedModuleIdentifier.length() ) { + m_documentationWebView = new QWebView(this); + m_documentationWebView->load(QUrl("http://localhost:1050/" + m_fullyQualifiedModuleIdentifier + ".html")); + connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); + } } void NavigationWidget::addDocumentationData(bool finished) { kDebug() << "Done loading!"; + disconnect(m_documentationWebView, SIGNAL(loadFinished(bool))); + if ( finished ) { + QGridLayout* newLayout = new QGridLayout(); + newLayout->setRowMinimumHeight(0, 200); + newLayout->setColumnMinimumWidth(0, 500); + newLayout->addWidget(m_documentationWebView); + layout()->addItem(newLayout); + } + else { + kError() << "Failed to get documentation for " << m_fullyQualifiedModuleIdentifier; + } // QWebElement document = m_documentationWebView->page()->mainFrame()->documentElement(); // if ( ! document.isNull() ) { // kDebug() << " >>> Trying to append documentation... "; @@ -48,7 +56,7 @@ void NavigationWidget::addDocumentationData(bool finished) // } } -NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix, const QString& htmlSuffix) +NavigationWidget::NavigationWidget(const KDevelop::IncludeItem& /* includeItem */, KDevelop::TopDUContextPointer /*topContext*/, const QString& /*htmlPrefix*/, const QString& /*htmlSuffix*/) { } diff --git a/duchain/navigation/navigationwidget.h b/duchain/navigation/navigationwidget.h index 8234541..ca0a0c0 100644 --- a/duchain/navigation/navigationwidget.h +++ b/duchain/navigation/navigationwidget.h @@ -19,11 +19,12 @@ public slots: NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); NavigationWidget(const KDevelop::IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()); - static QString shortDescription(KDevelop::Declaration* declaration) { return "Test"; }; - static QString shortDescription(const KDevelop::IncludeItem& includeItem) { return "Test"; }; + static QString shortDescription(KDevelop::Declaration* /*declaration*/) { return "Test"; }; + static QString shortDescription(const KDevelop::IncludeItem& /*includeItem*/) { return "Test"; }; QWebView* m_documentationWebView; QString m_originalHtml; + QString m_fullyQualifiedModuleIdentifier; }; } From 86d02d84a99aa907e724e045cc6a553243841d15 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 21 Nov 2010 01:38:57 +0100 Subject: [PATCH 094/118] Documentation support for "from ... import" syntax --- duchain/contextbuilder.cpp | 5 +++++ duchain/contextbuilder.h | 1 + duchain/declarationbuilder.cpp | 13 +++++++------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 5760877..bb18249 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -145,6 +145,11 @@ void ContextBuilder::openContextForStatementList( const QList& l, DUContex } } +void ContextBuilder::visitAttribute(AttributeAst* node) +{ + Python::AstDefaultVisitor::visitAttribute(node); +} + void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) { RangeInRevision range(node->body.first()->startLine, node->body.first()->startCol, node->body.last()->endLine, node->body.last()->endCol + 100000); diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index bcf6a7c..7189c50 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -74,6 +74,7 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public virtual void visitCode(CodeAst* node); virtual void visitImport(ImportAst* node); virtual void visitImportFrom(ImportFromAst* node); + virtual void visitAttribute(AttributeAst* node); DUContext* openSafeContext( Python::Ast* node, RangeInRevision& range, DUContext::ContextType type, Python::Identifier* identifier = 0 ); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 822cfa4..48b5fd0 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -153,11 +153,11 @@ void DeclarationBuilder::visitImport(ImportAst* node) else dec = visitVariableDeclaration(name->name); QString moduleName = name->name->value; if ( name->asName && name->asName->identifier ) - moduleName += name->asName->identifier->value; + moduleName += "." + name->asName->identifier->value; + kDebug() << "Module name: " << moduleName; if ( dec ) { DUChainWriteLocker lock(DUChain::lock()); dec->m_moduleIdentifier = moduleName; - kDebug() << "Set comment to " << dec->m_moduleIdentifier; } m_importContextsForImportStatement.clear(); } @@ -168,10 +168,11 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node) Python::AstDefaultVisitor::visitImportFrom(node); foreach ( AliasAst* name, node->names ) { importedModuleDeclaration* dec = 0; - if ( name->asName ) visitVariableDeclaration(name->asName); - else visitVariableDeclaration(name->name); - if ( dec && name->name ) { - dec->m_moduleIdentifier = name->name->value; + if ( name->asName ) dec = visitVariableDeclaration(name->asName); + else dec = visitVariableDeclaration(name->name); + if ( dec && name->name && node->module ) { + dec->m_moduleIdentifier = node->module->value + "." + name->name->value; + kDebug() << "FromImport module name: " << name->name->value; } } } From 29c31d469ac24435087c46a23e91f8375999a8a2 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 23 Nov 2010 21:53:13 +0100 Subject: [PATCH 095/118] Start the pydoc server automatically --- duchain/declarationbuilder.cpp | 36 +++++++++++++++---- duchain/declarationbuilder.h | 2 +- .../declarationnavigationcontext.cpp | 3 ++ duchain/navigation/navigationwidget.cpp | 23 ++++++++++++ 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 48b5fd0..4e9d7eb 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -35,10 +35,16 @@ #include #include #include +#include #include #include +#include +#include +#include +#include #include #include +#include #include "contextbuilder.h" @@ -46,6 +52,7 @@ #include "QtGlobal" #include +#include <../kdevplatform/language/duchain/declaration.h> using namespace KTextEditor; @@ -55,7 +62,6 @@ using namespace KDevelop; namespace Python { - DeclarationBuilder::DeclarationBuilder() : DeclarationBuilderBase() { @@ -101,6 +107,9 @@ template T* DeclarationBuilder::visitVariableDeclaration(Ast* node) return visitVariableDeclaration(id, currentVariableDefinition); } +/* + * WARNING: This will return a nullpointer if another than the expected type of variable was found! + * */ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* node, Ast* originalAst) { DUChainWriteLocker lock(DUChain::lock()); @@ -111,17 +120,27 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* existingDeclarations = currentContext()->findDeclarations(identifierForNode(node), until); - T* dec = 0; + Declaration* dec = 0; - if ( ! existingDeclarations.length() ) { + if ( currentContext() && currentContext()->type() == DUContext::Class && ! existingDeclarations.length() ) { + kDebug() << "Creating class member declaration for " << node->value << node->startLine << ":" << node->startCol; + dec = openDeclaration(node, originalAst ? originalAst : node); + closeDeclaration(); + } + else if ( ! existingDeclarations.length() ) { kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; dec = openDeclaration(node, originalAst ? originalAst : node); closeDeclaration(); dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); } - else kDebug() << "Not updating existing declaration for " << node->value; + else { + kDebug() << "Not updating existing declaration for " << node->value; + dec = existingDeclarations.last(); + } // dec->setType<>(); - return dec; + T* result = dynamic_cast(dec); + if ( ! result ) kError() << "variable declaration does not have the expected type"; + return result; } void DeclarationBuilder::visitExceptionHandler(ExceptionHandlerAst* node) @@ -190,10 +209,13 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; - DeclarationBuilderBase::visitClassDefinition( node ); - openDeclaration( node->name, node ); + ClassDeclaration* classDec = new ClassDeclaration(editorFindRange(node->body.first(), node->body.last()), currentContext()); + + openDeclaration( node->name, node ); eventuallyAssignInternalContext(); closeDeclaration(); + + DeclarationBuilderBase::visitClassDefinition( node ); } void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index ce833cd..dcf0a0c 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -58,7 +58,7 @@ class KDEVPYTHONDUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase virtual void visitExceptionHandler(ExceptionHandlerAst* node); virtual void visitCall(CallAst* node); - template T* visitVariableDeclaration(Ast* node); + template T* visitVariableDeclaration(Python::Ast* node); template T* visitVariableDeclaration(Identifier* node, Ast* originalAst = 0); QStack m_importContextsForImportStatement; diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 25b0cc4..94e959f 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -30,6 +30,9 @@ #include #include +#include +#include + namespace Python { using namespace KDevelop; diff --git a/duchain/navigation/navigationwidget.cpp b/duchain/navigation/navigationwidget.cpp index 21712b3..c0131a5 100644 --- a/duchain/navigation/navigationwidget.cpp +++ b/duchain/navigation/navigationwidget.cpp @@ -9,6 +9,15 @@ #include #include +#include + +#include + +#include "parser/parserConfig.h" +#include + +#include + namespace Python { NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDevelop::TopDUContextPointer topContext, const QString& /* htmlPrefix */, const QString& /* htmlSuffix */) @@ -25,6 +34,20 @@ NavigationWidget::NavigationWidget(KDevelop::DeclarationPointer declaration, KDe m_fullyQualifiedModuleIdentifier = context->m_fullyQualifiedModuleIdentifier; kDebug() << "Identifier: " << m_fullyQualifiedModuleIdentifier; if ( m_fullyQualifiedModuleIdentifier.length() ) { + kDebug() << "Checking wether doc server is running"; + QTcpSocket* sock = new QTcpSocket(); + sock->connectToHost(QHostAddress::LocalHost, 1050, QTcpSocket::ReadOnly); + bool running = sock->waitForConnected(300); + if ( ! running ) { + kDebug() << "Not running, starting pydoc server"; + QProcess::startDetached("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + "/pydoc.py" << "-p" << "1050"); + usleep(100000); // give pydoc server 100ms to start up + } + else { + sock->disconnectFromHost(); + } + delete sock; + m_documentationWebView = new QWebView(this); m_documentationWebView->load(QUrl("http://localhost:1050/" + m_fullyQualifiedModuleIdentifier + ".html")); connect( m_documentationWebView, SIGNAL(loadFinished(bool)), SLOT(addDocumentationData(bool)) ); From fdeda16704e603bcaae99f42e6e960be25aab74b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 24 Nov 2010 00:23:12 +0100 Subject: [PATCH 096/118] Parser bug fix... or not, not sure --- pythonparsejob.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index e042c0f..3b28725 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -120,7 +120,7 @@ void ParseJob::run() } readContents(); - m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); + m_session->setContents( QString::fromUtf8(contents().contents) + "\n" ); // append a newline in case the parser doesnt like it without one m_session->setCurrentDocument(m_url); if ( abortRequested() ) @@ -148,6 +148,15 @@ void ParseJob::run() m_duContext = builder.build(filename, m_ast); setDuChain(m_duContext); + { + DUChainWriteLocker lock(DUChain::lock()); + ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); + parsingEnvironmentFile->clearModificationRevisions(); + parsingEnvironmentFile->setModificationRevision(contents().modification); + DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); + m_duContext->clearProblems(); + } + UseBuilder usebuilder( &editor ); usebuilder.buildUses(m_ast); @@ -159,13 +168,6 @@ void ParseJob::run() KDevelop::ICodeHighlighting* hl = m_parent->codeHighlighting(); hl->highlightDUChain(m_duContext); } - - DUChainWriteLocker lock(DUChain::lock()); - ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); - parsingEnvironmentFile->clearModificationRevisions(); - parsingEnvironmentFile->setModificationRevision(contents().modification); - DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); - m_duContext->clearProblems(); } else { @@ -178,17 +180,16 @@ void ParseJob::run() DUChainWriteLocker lock(DUChain::lock()); ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); static const IndexedString langString("python"); - file->setModificationRevision(contents().modification); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); DUChain::self()->addDocumentChain(m_duContext); } { DUChainWriteLocker lock(DUChain::lock()); - DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); m_duContext->clearProblems(); + DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } DUChainWriteLocker lock(DUChain::lock()); From 0e04628d2f996103efd6d5fd7a8dd218281fe06a Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 24 Nov 2010 17:25:21 +0100 Subject: [PATCH 097/118] Changed some things regarding variable declarations --- duchain/contextbuilder.cpp | 1 + duchain/declarationbuilder.cpp | 8 +++++--- duchain/usebuilder.cpp | 14 ++++++++------ parser/astbuilder.cpp | 8 +++++++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index bb18249..49d5f76 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -158,6 +158,7 @@ void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) addImportedContexts(); Python::AstDefaultVisitor::visitClassDefinition(node); closeContext(); + kDebug() << " --- closing CLASS context: " << range.castToSimpleRange(); } void ContextBuilder::visitArguments(ArgumentsAst* node) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 4e9d7eb..6f9064d 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -103,7 +103,6 @@ template T* DeclarationBuilder::visitVariableDeclaration(Ast* node) return 0; } Identifier* id = currentVariableDefinition->identifier; - Q_ASSERT(id); return visitVariableDeclaration(id, currentVariableDefinition); } @@ -122,14 +121,17 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* Declaration* dec = 0; + kDebug() << "VARIABLE CONTEXT: " << currentContext()->scopeIdentifier() << currentContext()->range().castToSimpleRange() << currentContext()->type(); + if ( currentContext() && currentContext()->type() == DUContext::Class && ! existingDeclarations.length() ) { kDebug() << "Creating class member declaration for " << node->value << node->startLine << ":" << node->startCol; - dec = openDeclaration(node, originalAst ? originalAst : node); + kDebug() << "Context type: " << currentContext()->scopeIdentifier() << currentContext()->range().castToSimpleRange(); + dec = openDeclaration(node, originalAst ? originalAst : node, DeclarationIsDefinition); closeDeclaration(); } else if ( ! existingDeclarations.length() ) { kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; - dec = openDeclaration(node, originalAst ? originalAst : node); + dec = openDeclaration(node, originalAst ? originalAst : node, DeclarationIsDefinition); closeDeclaration(); dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); } diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 6c924c6..08c677a 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -53,19 +53,21 @@ void UseBuilder::buildUses(Ast* node) void UseBuilder::visitName(NameAst* node) { DUChainWriteLocker lock(DUChain::lock()); - DUContext* current = currentContext(); QList declarations = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).start); - QList isDecl = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); // TODO not so elegant ;D +// QList isDecl = currentContext()->findDeclarations(identifierForNode(node->identifier), editorFindRange(node, node).end); // TODO not so elegant ;D Declaration* declaration; if ( declarations.length() ) declaration = declarations.last(); else declaration = 0; - - if ( ! declarations.length() && isDecl.length() ) return; + kDebug() << currentContext()->type() << currentContext()->scopeIdentifier() << currentContext()->range().castToSimpleRange(); Q_ASSERT(node->identifier); Q_ASSERT(node->hasUsefulRangeInformation); // TODO remove this! - kDebug() << " Registeriung use for " << node->identifier->value << " at " << node->identifier->startLine << ":" << node->identifier->endCol << "->" << node->identifier->endLine << ":" << node->identifier->endCol + 1 << "with dec" << declaration; - UseBuilderBase::newUse(node, RangeInRevision(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1), DeclarationPointer(declaration)); // +1 for whatever reason + RangeInRevision useRange(node->identifier->startLine, node->identifier->startCol, node->identifier->endLine, node->identifier->endCol + 1); + + if ( declaration && declaration->range() == useRange ) return; + + kDebug() << " Registering use for " << node->identifier->value << " at " << useRange.castToSimpleRange() << "with dec" << declaration; + UseBuilderBase::newUse(node, useRange, DeclarationPointer(declaration)); } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index d92718d..f04eb11 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -314,6 +314,8 @@ bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStrea return false; } + ast->startLine = -5; + m_nodeMap.insert(node_id, ast); m_attributeStore.insert(node_id, attributeDict); @@ -865,7 +867,7 @@ void AstBuilder::populateAst() default: kWarning() << "Unsupported AST type: " << currentAbstractNode->astType; break; } - // Walk throguh the tree and set proper end columns and lines, as the python parser sadly does not do this for us + // Walk through the tree and set proper end columns and lines, as the python parser sadly does not do this for us if ( currentAbstractNode->hasUsefulRangeInformation ) { Ast* parent = currentAbstractNode->parent; while ( parent ) { @@ -873,6 +875,10 @@ void AstBuilder::populateAst() parent->endLine = currentAbstractNode->endLine; parent->endCol = currentAbstractNode->endCol; } + if ( ! parent->hasUsefulRangeInformation && parent->startLine == -5 ) { + parent->startLine = currentAbstractNode->startLine; + parent->startCol = currentAbstractNode->startCol; + } parent = parent->parent; } } From f577024957db81a0cc2014c1990a859ba532250b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sat, 27 Nov 2010 13:47:32 +0100 Subject: [PATCH 098/118] Type is now copied to new variable on assignment (pointless, right now) --- duchain/declarationbuilder.cpp | 21 ++++++++++++++++++++- parser/astbuilder.cpp | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 6f9064d..584b722 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -113,6 +113,7 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* { DUChainWriteLocker lock(DUChain::lock()); Q_ASSERT(node); + AssignmentAst* parent = dynamic_cast(node->parent->parent); QList existingDeclarations; CursorInRevision until = editorFindRange(node, node).end; @@ -133,11 +134,25 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; dec = openDeclaration(node, originalAst ? originalAst : node, DeclarationIsDefinition); closeDeclaration(); - dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); +// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); + dec->setKind(KDevelop::Declaration::Instance); // everything is an object in python + if ( parent ) { + NameAst* singleValue = dynamic_cast(parent->value); + if ( singleValue ) { + kDebug() << "Found a single target value for variable declaration"; + QList newValueDecs = currentContext()->findDeclarations(identifierForNode(singleValue->identifier), until); + if ( newValueDecs.length() > 0 ) { + Declaration* newValueDec = newValueDecs.last(); + kDebug() << newValueDec << newValueDec->type(); + dec->setType(newValueDec->type()); + } + } + } } else { kDebug() << "Not updating existing declaration for " << node->value; dec = existingDeclarations.last(); + setEncountered(dec); } // dec->setType<>(); T* result = dynamic_cast(dec); @@ -179,6 +194,7 @@ void DeclarationBuilder::visitImport(ImportAst* node) if ( dec ) { DUChainWriteLocker lock(DUChain::lock()); dec->m_moduleIdentifier = moduleName; + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); } m_importContextsForImportStatement.clear(); } @@ -195,6 +211,9 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node) dec->m_moduleIdentifier = node->module->value + "." + name->name->value; kDebug() << "FromImport module name: " << name->name->value; } + if ( dec ) { + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); + } } } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index f04eb11..49b60b8 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -356,6 +356,7 @@ Identifier* AstBuilder::createIdentifier(const QString& name, Ast* range) ident->endCol = range->startCol + name.length() - 1; ident->startLine = range->startLine; ident->endLine = range->endLine; + ident->parent = range; return ident; } From 0923053786a1dfc555c4f80e127d0df299b96e3b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Mon, 29 Nov 2010 22:22:00 +0100 Subject: [PATCH 099/118] Removed include --- parser/ast.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/parser/ast.cpp b/parser/ast.cpp index 8a2fc94..ae04f59 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -324,6 +324,3 @@ AliasAst::AliasAst(Ast* parent): Ast(parent, Ast::AliasAstType), name(0), asName } - - -#include "pythonast.h" From c10918a95776aed8f26ea9a8184d52c8b61f7f18 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 29 Nov 2010 22:41:36 +0100 Subject: [PATCH 100/118] use proper non-clashing Identities for Python contexts --- duchain/contextbuilder.cpp | 4 ++-- duchain/pythonducontext.cpp | 10 ++++------ duchain/pythonducontext.h | 7 +++++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 49d5f76..b807f87 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -67,7 +67,7 @@ TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, Parsin file = new ParsingEnvironmentFile(currentDocumentUrl); file->setLanguage(IndexedString("python")); } - TopDUContext* top = new PythonDUContext(currentDocumentUrl, range, file); + TopDUContext* top = new PythonTopDUContext(currentDocumentUrl, range, file); ReferencedTopDUContext ref(top); m_topContext = ref; return top; @@ -75,7 +75,7 @@ TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, Parsin DUContext* ContextBuilder::newContext(const RangeInRevision& range) { - return new PythonDUContext(range, currentContext()); + return new PythonNormalDUContext(range, currentContext()); } void ContextBuilder::setEditor(PythonEditorIntegrator* editor) diff --git a/duchain/pythonducontext.cpp b/duchain/pythonducontext.cpp index 252af18..ab33bcb 100644 --- a/duchain/pythonducontext.cpp +++ b/duchain/pythonducontext.cpp @@ -10,23 +10,21 @@ using namespace KDevelop; namespace Python { - -typedef PythonDUContext PythonTopDUContext; + REGISTER_DUCHAIN_ITEM_WITH_DATA(PythonTopDUContext, TopDUContextData); -typedef PythonDUContext PythonNormalDUContext; REGISTER_DUCHAIN_ITEM_WITH_DATA(PythonNormalDUContext, DUContextData); template<> -QWidget* PythonDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { +QWidget* PythonTopDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { if ( ! decl ) return 0; return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); } template<> -QWidget* PythonDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { +QWidget* PythonNormalDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { if ( ! decl ) return 0; return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); } -} \ No newline at end of file +} diff --git a/duchain/pythonducontext.h b/duchain/pythonducontext.h index d010e3b..5b17cd2 100644 --- a/duchain/pythonducontext.h +++ b/duchain/pythonducontext.h @@ -14,7 +14,7 @@ namespace KDevelop namespace Python { -template +template class PythonDUContext : public BaseContext { public: @@ -41,10 +41,13 @@ class PythonDUContext : public BaseContext virtual QWidget* createNavigationWidget(KDevelop::Declaration* decl, KDevelop::TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const; enum { - Identity = BaseContext::Identity + 51 + Identity = IdentityT }; }; +typedef PythonDUContext PythonTopDUContext; +typedef PythonDUContext PythonNormalDUContext; + } From 12aec70ba3200dfe0764419ba40b60a9630ef87b Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 29 Nov 2010 23:43:51 +0100 Subject: [PATCH 101/118] don't track .kdev4 folder --- .kdev4/python.kdev4 | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .kdev4/python.kdev4 diff --git a/.kdev4/python.kdev4 b/.kdev4/python.kdev4 deleted file mode 100644 index 03baba4..0000000 --- a/.kdev4/python.kdev4 +++ /dev/null @@ -1,35 +0,0 @@ -[Buildset] -BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x0c\x00p\x00y\x00t\x00h\x00o\x00n) - -[CMake] -BuildDirs=/home/sven/projects/kde4/python/build -CMakeDir=/usr/share/cmake/Modules -Current CMake Binary=file:///usr/bin/cmake -CurrentBuildDir=file:///home/sven/projects/kde4/python/build -CurrentBuildType=Debug -CurrentInstallDir= -Extra Arguments= -ProjectRootRelative=./ - -[Launch] -Launch Configurations=Launch Configuration 0 - -[Launch][Launch Configuration 0] -Configured Launch Modes=execute -Configured Launchers=nativeAppLauncher -Name=New Native Application Configuration -Type=Native Application - -[Launch][Launch Configuration 0][Data] -Arguments=-c kdevelop /home/sven/projects/kde4/python/python_helpers/generate_docs.py -Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) -Dependency Action=Nothing -EnvironmentGroup=default -Executable=file:///bin/bash -External Terminal=konsole --noclose --workdir %workdir -e %exe -Use External Terminal=false -Working Directory= -isExecutable=true - -[Project] -VersionControlSupport=kdevgit From 2779185802ae06c7830b5fbe9ce95d2b7098b50f Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 29 Nov 2010 23:55:28 +0100 Subject: [PATCH 102/118] properly clear context before updating it, should solve the strange issue with the context browser ranges but shows up different problems --- duchain/contextbuilder.cpp | 19 +++++++++++++++++++ duchain/contextbuilder.h | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index b807f87..ed27bc6 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -53,6 +53,25 @@ namespace Python TopDUContext* ParseJob::m_internalFunctions; +ReferencedTopDUContext ContextBuilder::build(const IndexedString& url, Ast* node, ReferencedTopDUContext updateContext) +{ + if (!updateContext) { + DUChainReadLocker lock(DUChain::lock()); + updateContext = DUChain::self()->chainForDocument(url); + } + if (updateContext) { + kDebug() << "re-compiling" << url.str(); + DUChainWriteLocker lock(DUChain::lock()); + updateContext->clearImportedParentContexts(); + updateContext->parsingEnvironmentFile()->clearModificationRevisions(); + updateContext->clearProblems(); + } else { + kDebug() << "compiling" << url.str(); + } + + return ContextBuilderBase::build(url, node, updateContext); +} + PythonEditorIntegrator* ContextBuilder::editor() const { return ContextBuilder::m_editor; diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index 7189c50..e605a13 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -48,9 +48,12 @@ typedef KDevelop::AbstractContextBuilder ContextBuilderBase; class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public Python::AstDefaultVisitor { public: + virtual ReferencedTopDUContext build(const KDevelop::IndexedString& url, Ast* node, + ReferencedTopDUContext updateContext = ReferencedTopDUContext()); + void setEditor(PythonEditorIntegrator* editor); void setEditor(ParseSession* session); - + KUrl findModulePath(const QString& name); protected: From 95da156de9ddb43e4167e30d03ac97e3bc5fd5b9 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 29 Nov 2010 23:55:35 +0100 Subject: [PATCH 103/118] cleanup locks --- pythonparsejob.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 3b28725..eb8e6d8 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -172,12 +172,11 @@ void ParseJob::run() else { kWarning() << "===Failed==="; + DUChainWriteLocker lock; { - DUChainReadLocker lock(DUChain::lock()); m_duContext = DUChain::self()->chainForDocument(document()); } if ( ! m_duContext ) { - DUChainWriteLocker lock(DUChain::lock()); ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); static const IndexedString langString("python"); file->setLanguage(langString); @@ -185,14 +184,12 @@ void ParseJob::run() DUChain::self()->addDocumentChain(m_duContext); } { - DUChainWriteLocker lock(DUChain::lock()); m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); m_duContext->clearProblems(); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } - - DUChainWriteLocker lock(DUChain::lock()); + foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; m_duContext->addProblem(p); From e731dbbdad98aea44b1884abdf2d613d4eab31ab Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 30 Nov 2010 20:31:41 +0100 Subject: [PATCH 104/118] Create type declarations for a few basic types --- duchain/declarationbuilder.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 584b722..f6db5c6 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -154,6 +154,25 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* dec = existingDeclarations.last(); setEncountered(dec); } + AssignmentAst* assignment = node->parent && node->parent->parent ? dynamic_cast(node->parent->parent) : 0; + if ( dec->abstractType().isNull() && assignment && assignment->value ) { + switch ( assignment->value->astType ) { + case Python::Ast::StringAstType: + kDebug() << "Found a string variable declaration"; + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeString))); + break; + case Python::Ast::NumberAstType: + kDebug() << "Found a number variable"; + dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeFloat))); + break; + default: + kDebug() << "Could not determine type for variable " << node->value; + break; + } + } + else { + kDebug() << "Could not convert variable declaration to assignment!"; + } // dec->setType<>(); T* result = dynamic_cast(dec); if ( ! result ) kError() << "variable declaration does not have the expected type"; From fe5dcfa57614038bca92f5a5086e5b8e9188a6c2 Mon Sep 17 00:00:00 2001 From: mcanes Date: Thu, 2 Dec 2010 21:09:19 +0100 Subject: [PATCH 105/118] Changed spaces for tabs in some lines. It make crash py3 --- pythonpythonparser.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pythonpythonparser.py b/pythonpythonparser.py index e4b1199..91a54f7 100755 --- a/pythonpythonparser.py +++ b/pythonpythonparser.py @@ -45,11 +45,11 @@ def generic_visit(self, node): value = getattr(node, field) if type(value) not in [types.IntType, types.StringType, types.FloatType, types.BooleanType]: continue - try: - node_xmlrepr.set(field.lower(), str(value)) - except: - sys.stderr.write("Warning: Invalid string literal replaced by empty string!\n") - node_xmlrepr.set(field.lower(), "") + try: + node_xmlrepr.set(field.lower(), str(value)) + except: + sys.stderr.write("Warning: Invalid string literal replaced by empty string!\n") + node_xmlrepr.set(field.lower(), "") super(KDevelopNodeVisitor, self).generic_visit(node) @@ -81,13 +81,13 @@ def generic_visit(self, node): f = sys.stdin.read() v = KDevelopNodeVisitor() try: - parsetree = ast.parse(f) + parsetree = ast.parse(f) except Exception as e: try: - sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) - sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") + sys.stderr.write(str(e.lineno) + ':::' + str(e.offset)) + sys.stderr.write(":::" + str(type(e)).replace('', '') + ':::' + str(e.msg) + ": \"" + str(e.text).replace("\n", "") + "\"") except: - sys.stderr.write('?:::?:::'+str(e)+':::?') + sys.stderr.write('?:::?:::'+str(e)+':::?') else: v.visit(parsetree) sys.stdout.write(etree.tostring(v.basenode, xml_declaration=True, pretty_print=True, encoding='UTF-8')) From 0ed472c01861289677d27b43355b239fb4c21774 Mon Sep 17 00:00:00 2001 From: Miquel Canes Gonzalez Date: Fri, 3 Dec 2010 06:55:09 +0100 Subject: [PATCH 106/118] DuChain basic test added --- duchain/CMakeLists.txt | 1 + duchain/tests/CMakeLists.txt | 2 + duchain/tests/pyduchaintest.cpp | 123 ++++++++++++++++++++++++++++++++ duchain/tests/pyduchaintest.h | 48 +++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 duchain/tests/CMakeLists.txt create mode 100644 duchain/tests/pyduchaintest.cpp create mode 100644 duchain/tests/pyduchaintest.h diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index b6e0d19..064403c 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -33,3 +33,4 @@ install(TARGETS kdev4pythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(navigation) add_subdirectory(declarations) +add_subdirectory(tests) diff --git a/duchain/tests/CMakeLists.txt b/duchain/tests/CMakeLists.txt new file mode 100644 index 0000000..ac8397d --- /dev/null +++ b/duchain/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +kde4_add_unit_test(pyduchaintest pyduchaintest.cpp ) +target_link_libraries(pyduchaintest kdev4pythonduchain ${QT_QTTEST_LIBRARY} ${KDEVPLATFORM_TESTS_LIBRARIES}) diff --git a/duchain/tests/pyduchaintest.cpp b/duchain/tests/pyduchaintest.cpp new file mode 100644 index 0000000..95314e6 --- /dev/null +++ b/duchain/tests/pyduchaintest.cpp @@ -0,0 +1,123 @@ +/***************************************************************************** + * Copyright 2010 (c) Miquel Canes Gonzalez * + * * + * Permission is hereby granted, free of charge, to any person obtaining * + * a copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to * + * the following conditions: * + * * + * The above copyright notice and this permission notice shall be * + * included in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + *****************************************************************************/ + +#include "pyduchaintest.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QTEST_MAIN(PyDUChainTest) + +using namespace KDevelop; +using namespace Python; + +PyDUChainTest::PyDUChainTest(QObject* parent): QObject(parent) +{ + initShell(); +} + +void PyDUChainTest::initShell() +{ + AutoTestShell::init(); + TestCore* core = new TestCore(); + core->initialize(KDevelop::Core::NoUi); + + DUChain::self()->disablePersistentStorage(); + KDevelop::CodeRepresentation::setDiskChangesForbidden(true); +} + +ReferencedTopDUContext PyDUChainTest::parse(const QByteArray& code) +{ + ParseSession* session = new ParseSession; + session->setContents( code + "\n" ); // append a newline in case the parser doesnt like it without one + + static int mytest=0; + KUrl filename("/test"+QString::number(mytest++)); + session->setCurrentDocument(filename); + + QPair parserResults = session->parse(0); + CodeAst* ast = parserResults.first; + + if(!parserResults.second) + return 0; + + PythonEditorIntegrator editor; + DeclarationBuilder builder( &editor ); + + editor.setParseSession(session); + + ReferencedTopDUContext ret = builder.build(IndexedString(filename), ast); + + { + DUChainWriteLocker lock(DUChain::lock()); +// ParsingEnvironmentFilePointer parsingEnvironmentFile = ret->parsingEnvironmentFile(); +// parsingEnvironmentFile->clearModificationRevisions(); +// parsingEnvironmentFile->setModificationRevision(contents().modification); +// DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); + ret->clearProblems(); + } + + UseBuilder usebuilder( &editor ); + usebuilder.buildUses(ast); + + return ret; +} + +void PyDUChainTest::testSimple() +{ + QFETCH(QString, code); + QFETCH(int, decls); + QFETCH(int, uses); + + ReferencedTopDUContext ctx = parse(code.toLatin1()); + QVERIFY(ctx); + + DUChainReadLocker lock(DUChain::lock()); + QVector< Declaration* > declarations = ctx->localDeclarations(ctx); + + QCOMPARE(declarations.size(), decls); + + int usesCount = 0; + foreach(Declaration* d, declarations) + usesCount += d->uses().size(); + + QCOMPARE(usesCount, uses); +} + +void PyDUChainTest::testSimple_data() +{ + QTest::addColumn("code"); + QTest::addColumn("decls"); + QTest::addColumn("uses"); + + QTest::newRow("int") << "a = 'casa'; b = 2; c = 3 + b" << 3 << 1; +} diff --git a/duchain/tests/pyduchaintest.h b/duchain/tests/pyduchaintest.h new file mode 100644 index 0000000..c17e04a --- /dev/null +++ b/duchain/tests/pyduchaintest.h @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright 2010 (c) Miquel Canes Gonzalez * + * * + * Permission is hereby granted, free of charge, to any person obtaining * + * a copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to * + * the following conditions: * + * * + * The above copyright notice and this permission notice shall be * + * included in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + *****************************************************************************/ + +#ifndef PYDUCHAINTEST_H +#define PYDUCHAINTEST_H + +#include + +namespace KDevelop { +class TopDUContext; +class ReferencedTopDUContext; +} + +class PyDUChainTest : public QObject +{ + Q_OBJECT + public: + explicit PyDUChainTest(QObject* parent = 0); + void initShell(); + + KDevelop::ReferencedTopDUContext parse(const QByteArray& code); + + private slots: + void testSimple(); + void testSimple_data(); +}; + +#endif // PYDUCHAINTEST_H From 4af93940ea9fb90d2f5ee5b806907368fb7c4474 Mon Sep 17 00:00:00 2001 From: Miquel Canes Gonzalez Date: Fri, 3 Dec 2010 09:04:56 +0100 Subject: [PATCH 107/118] Added first version of an expression visitor that controls dummy binary and unary operations. --- duchain/CMakeLists.txt | 2 +- duchain/declarationbuilder.cpp | 57 +++++++-------------------------- duchain/expressionvisitor.cpp | 50 +++++++++++++++++++++++++++++ duchain/expressionvisitor.h | 30 +++++++++++++++++ duchain/tests/pyduchaintest.cpp | 9 ++++-- 5 files changed, 100 insertions(+), 48 deletions(-) create mode 100644 duchain/expressionvisitor.cpp create mode 100644 duchain/expressionvisitor.h diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 064403c..eaeb682 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) -set(duchain_SRCS declarations/importedmoduledeclaration.cpp +set(duchain_SRCS expressionvisitor.cpp declarations/importedmoduledeclaration.cpp pythonducontext.cpp contextbuilder.cpp pythoneditorintegrator.cpp diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index f6db5c6..1d53452 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -53,6 +53,7 @@ #include #include <../kdevplatform/language/duchain/declaration.h> +#include "expressionvisitor.h" using namespace KTextEditor; @@ -113,66 +114,26 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* { DUChainWriteLocker lock(DUChain::lock()); Q_ASSERT(node); - AssignmentAst* parent = dynamic_cast(node->parent->parent); - QList existingDeclarations; CursorInRevision until = editorFindRange(node, node).end; - existingDeclarations = currentContext()->findDeclarations(identifierForNode(node), until); - Declaration* dec = 0; kDebug() << "VARIABLE CONTEXT: " << currentContext()->scopeIdentifier() << currentContext()->range().castToSimpleRange() << currentContext()->type(); - if ( currentContext() && currentContext()->type() == DUContext::Class && ! existingDeclarations.length() ) { + if ( currentContext() && currentContext()->type() == DUContext::Class ) { kDebug() << "Creating class member declaration for " << node->value << node->startLine << ":" << node->startCol; kDebug() << "Context type: " << currentContext()->scopeIdentifier() << currentContext()->range().castToSimpleRange(); dec = openDeclaration(node, originalAst ? originalAst : node, DeclarationIsDefinition); closeDeclaration(); - } - else if ( ! existingDeclarations.length() ) { + } else { kDebug() << "Creating variable declaration for " << node->value << node->startLine << ":" << node->startCol; dec = openDeclaration(node, originalAst ? originalAst : node, DeclarationIsDefinition); closeDeclaration(); -// dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeMixed))); + dec->setType(lastType()); dec->setKind(KDevelop::Declaration::Instance); // everything is an object in python - if ( parent ) { - NameAst* singleValue = dynamic_cast(parent->value); - if ( singleValue ) { - kDebug() << "Found a single target value for variable declaration"; - QList newValueDecs = currentContext()->findDeclarations(identifierForNode(singleValue->identifier), until); - if ( newValueDecs.length() > 0 ) { - Declaration* newValueDec = newValueDecs.last(); - kDebug() << newValueDec << newValueDec->type(); - dec->setType(newValueDec->type()); - } - } - } - } - else { - kDebug() << "Not updating existing declaration for " << node->value; - dec = existingDeclarations.last(); - setEncountered(dec); - } - AssignmentAst* assignment = node->parent && node->parent->parent ? dynamic_cast(node->parent->parent) : 0; - if ( dec->abstractType().isNull() && assignment && assignment->value ) { - switch ( assignment->value->astType ) { - case Python::Ast::StringAstType: - kDebug() << "Found a string variable declaration"; - dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeString))); - break; - case Python::Ast::NumberAstType: - kDebug() << "Found a number variable"; - dec->setType(IntegralType::Ptr(new IntegralType(IntegralType::TypeFloat))); - break; - default: - kDebug() << "Could not determine type for variable " << node->value; - break; - } - } - else { - kDebug() << "Could not convert variable declaration to assignment!"; } + // dec->setType<>(); T* result = dynamic_cast(dec); if ( ! result ) kError() << "variable declaration does not have the expected type"; @@ -238,12 +199,18 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node) void DeclarationBuilder::visitAssignment(AssignmentAst* node) { +// visitNode(node->value); + +// qDebug() << "pepeppepe" << node->; + ExpressionVisitor v(currentContext()); + v.visitNode(node->value); + setLastType(v.lastType()); + foreach ( ExpressionAst* target, node->targets ) { if ( target->astType == Ast::NameAstType ) { visitVariableDeclaration(target); } } - visitNode(node->value); } void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp new file mode 100644 index 0000000..5b4626c --- /dev/null +++ b/duchain/expressionvisitor.cpp @@ -0,0 +1,50 @@ +#include "expressionvisitor.h" +#include +#include +#include +#include + +using namespace KDevelop; + +Python::ExpressionVisitor::ExpressionVisitor(DUContext* ctx) + : m_ctx(ctx) +{} + +void Python::ExpressionVisitor::visitNumber(Python::NumberAst* ) +{ + m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeFloat)); +} + +void Python::ExpressionVisitor::visitString(Python::StringAst* ) +{ + m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); +} + +void Python::ExpressionVisitor::visitName(Python::NameAst* node) +{ + qDebug() << "pepepepepe" << node->identifier->value; + QList< Declaration* > d=m_ctx->findDeclarations(KDevelop::Identifier(node->identifier->value)); + Q_ASSERT(!d.isEmpty()); + m_lastType = d.last()->abstractType(); +} + +void Python::ExpressionVisitor::visitBinaryOperation(Python::BinaryOperationAst* node) +{ + visitNode(node->lhs); + KDevelop::AbstractType::Ptr leftType = m_lastType; + + visitNode(node->rhs); + KDevelop::AbstractType::Ptr rightType = m_lastType; + + if(leftType->whichType()==AbstractType::TypeIntegral && leftType->whichType()==AbstractType::TypeIntegral) + m_lastType = leftType; + else + m_lastType = AbstractType::Ptr(new UnsureType); +} + +void Python::ExpressionVisitor::visitUnaryOperation(Python::UnaryOperationAst* node) +{ + visitNode(node->operand); + + //FIXME: m_lastValue = m_lastValue; +} diff --git a/duchain/expressionvisitor.h b/duchain/expressionvisitor.h new file mode 100644 index 0000000..872df41 --- /dev/null +++ b/duchain/expressionvisitor.h @@ -0,0 +1,30 @@ +#ifndef EXPRESSIONVISITOR_H +#define EXPRESSIONVISITOR_H + +#include +#include + +namespace Python +{ + +class ExpressionVisitor : public AstDefaultVisitor +{ + public: + ExpressionVisitor(KDevelop::DUContext* ctx); + + virtual void visitBinaryOperation(BinaryOperationAst* node); + virtual void visitUnaryOperation(UnaryOperationAst* node); + + virtual void visitString(StringAst* node); + virtual void visitNumber(NumberAst* node); + virtual void visitName(NameAst* node); + + KDevelop::AbstractType::Ptr lastType() const { return m_lastType; } + private: + KDevelop::AbstractType::Ptr m_lastType; + KDevelop::DUContext* m_ctx; +}; + +} + +#endif // EXPRESSIONVISITOR_H diff --git a/duchain/tests/pyduchaintest.cpp b/duchain/tests/pyduchaintest.cpp index 95314e6..8261326 100644 --- a/duchain/tests/pyduchaintest.cpp +++ b/duchain/tests/pyduchaintest.cpp @@ -107,8 +107,11 @@ void PyDUChainTest::testSimple() QCOMPARE(declarations.size(), decls); int usesCount = 0; - foreach(Declaration* d, declarations) + foreach(Declaration* d, declarations) { usesCount += d->uses().size(); + + QVERIFY(!d->abstractType().isNull()); + } QCOMPARE(usesCount, uses); } @@ -119,5 +122,7 @@ void PyDUChainTest::testSimple_data() QTest::addColumn("decls"); QTest::addColumn("uses"); - QTest::newRow("int") << "a = 'casa'; b = 2; c = 3 + b" << 3 << 1; + QTest::newRow("assign") << "b = 2;" << 1 << 0; + QTest::newRow("assign_str") << "b = 'hola';" << 1 << 0; + QTest::newRow("op") << "a = 3; b = a+2;" << 2 << 1; } From 3645aa1a217ad8fc87709390e78d4a7aace10784 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Fri, 3 Dec 2010 21:05:58 +0100 Subject: [PATCH 108/118] Added example AST and XML for that --- example_ast.py | 172 +++++++++ example_ast.xml | 990 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1162 insertions(+) create mode 100644 example_ast.py create mode 100644 example_ast.xml diff --git a/example_ast.py b/example_ast.py new file mode 100644 index 0000000..09b78b3 --- /dev/null +++ b/example_ast.py @@ -0,0 +1,172 @@ +a = a and a +a = a or b + +def some_class(foo, bar): + attr1 = 3 + attr2 = 5 + attr3 = 'str' + +some_instance = some_class() +some_instance.attr1 +some_instance.attr2 +some_instance.some_method() + +#comment +""" +multiline comment +foo +bar +""" + +import sys +import random + +import PyQt4.QtCore + +print sys + +def simple_func(foo): + # usage comment, bla, param:foo + pass + +def function(foo): + """ docstring + more + more more + >>> test + >>> test + """ + return foo + +try: + pass +except Exception as e: + print e + +def func(foo, bar, baz, bang, foobang, foobar, foobazbar, foobazbarbang): + return foobang + print foo + print foobazbarbang + + if foobazbar < 5: + pass + +def another_function(param): + print param + +a = 5 + +bar = a == a +a != a +a < a +a <= a +a > a +a >= a +a is a +a is not a +a not in a +a in a + +a = a + 1 +a = a - 1 +a = a * 1 +a = a / 1 +a = a % 1 +a = a ^ 1 +a = a & 1 +a = a | 1 +a = a ** 1 +a = a >> 1 +a = a << 1 + +a = not a +a = +a +a = -a +a = ~a + +a = b[1:2:3][2] +extended = a[1:2, 2:3] + +i += 3 +i += j + +print 3 if 5 < 7 else 4 + +from random import random + +print random + +random(foo=3) + +a = lambda x: x**2 + +@staticmethod +@classmethod +def genfunc(): + yield foo + +for target1, target2 in some_dict.iteritems(): + print target1, target2 + +pi = 3.1415 + +foo = 1, 2 +bar = (1, 2) + +with open('f') as foo: + pass + +global IMAGLOBALVARIABLE +IMAGLOBALVARIABLE = 0 +try: + a = 3 / 0 +except ZeroDivisionError as err: + raise ValueError +else: + do_something() +finally: + BAM + +if 3 and 5: + pass + +for i in xrange(20): + pass + +while True: + break + continue + +del foo + +import random +random.random(3, 5) + +somelist = [1, 2, 3, 4, 5] +somedict = { 'key1' : 'value1', key2: value2 } + +print somelist[...] +print somelist[1:] +print somelist[:20] +print somelist[1:20] +print somelist[1:20:2] + +class bar(parent): + pass + +if foo in bar and 3 < 5: + pass + +a = [x*2 for x in xrange(20)] + +variable.variable2.variable3 = 15 +def function(param1, param2, param3, *paramstar, **paramdstar): + pass + return param1 * param2 + +assert False +if not 3: + pass + +if 3 * 5 == 7: + pass diff --git a/example_ast.xml b/example_ast.xml new file mode 100644 index 0000000..fb10791 --- /dev/null +++ b/example_ast.xml @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c966a06a669a9c7e3ce8bb86a9cd2657c19d9b3b Mon Sep 17 00:00:00 2001 From: Miquel Canes Gonzalez Date: Sat, 4 Dec 2010 07:33:02 +0100 Subject: [PATCH 109/118] Added booleans and binary operators support --- duchain/expressionvisitor.cpp | 71 ++++++++++++++++++++++++++++++--- duchain/expressionvisitor.h | 8 ++++ duchain/tests/pyduchaintest.cpp | 2 + 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp index 5b4626c..d44a946 100644 --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -3,12 +3,22 @@ #include #include #include +#include +#include using namespace KDevelop; +using namespace Python; + +QHash ExpressionVisitor::s_defaultTypes; Python::ExpressionVisitor::ExpressionVisitor(DUContext* ctx) : m_ctx(ctx) -{} +{ + if(s_defaultTypes.isEmpty()) { + s_defaultTypes.insert(KDevelop::Identifier("True"), AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean))); + s_defaultTypes.insert(KDevelop::Identifier("False"), AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean))); + } +} void Python::ExpressionVisitor::visitNumber(Python::NumberAst* ) { @@ -20,12 +30,40 @@ void Python::ExpressionVisitor::visitString(Python::StringAst* ) m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); } +RangeInRevision nodeRange(Python::Ast* node) +{ + qDebug() << node->endLine; +// return RangeInRevision(node->startLine, node->startCol, node->endLine,node->endCol); + return RangeInRevision(0,0, 2, 2); +} + void Python::ExpressionVisitor::visitName(Python::NameAst* node) { - qDebug() << "pepepepepe" << node->identifier->value; - QList< Declaration* > d=m_ctx->findDeclarations(KDevelop::Identifier(node->identifier->value)); - Q_ASSERT(!d.isEmpty()); - m_lastType = d.last()->abstractType(); + KDevelop::Identifier id(node->identifier->value); + QHash < KDevelop::Identifier, AbstractType::Ptr >::const_iterator defId = s_defaultTypes.constFind(id); + if(defId!=s_defaultTypes.constEnd()) { + m_lastType = *defId; + return; + } + + QList< Declaration* > d=m_ctx->findDeclarations(id); +// Q_ASSERT(!d.isEmpty()); + + qDebug() << "visitName" << node->identifier->value << d; + if(!d.isEmpty()) + m_lastType = d.last()->abstractType(); + else { + qDebug("VistName type not found"); + RangeInRevision r = nodeRange(node); + + ProblemPointer p(new Problem); + p->setRange(r); + p->setDescription(i18n("undefined variable '%1'", node->identifier->value)); + p->setFinalLocation(DocumentRange(m_ctx->topContext()->url(), r.castToSimpleRange())); + p->setSeverity(ProblemData::Error); + p->setSource(KDevelop::ProblemData::Parser); + m_ctx->topContext()->addProblem(p); + } } void Python::ExpressionVisitor::visitBinaryOperation(Python::BinaryOperationAst* node) @@ -48,3 +86,26 @@ void Python::ExpressionVisitor::visitUnaryOperation(Python::UnaryOperationAst* n //FIXME: m_lastValue = m_lastValue; } + +void Python::ExpressionVisitor::visitBooleanOperation(Python::BooleanOperationAst* node) +{ + bool problem = false; + foreach (ExpressionAst* expression, node->values) { + visitNode(expression); + if(m_lastType->whichType() != AbstractType::TypeIntegral || m_lastType.cast()->dataType() != IntegralType::TypeBoolean){ + problem = true; + qDebug() << "VistBooleanOperation type not match"; + RangeInRevision r = nodeRange(expression); + ProblemPointer p(new Problem); + p->setRange(r); + p->setDescription(i18n("wrong type '%1'", m_lastType->toString())); + p->setFinalLocation(DocumentRange(m_ctx->topContext()->url(), r.castToSimpleRange())); + p->setSeverity(ProblemData::Error); + p->setSource(KDevelop::ProblemData::SemanticAnalysis); + m_ctx->topContext()->addProblem(p); + } + } + //if(!problem) + m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); +} + diff --git a/duchain/expressionvisitor.h b/duchain/expressionvisitor.h index 872df41..eeeadb7 100644 --- a/duchain/expressionvisitor.h +++ b/duchain/expressionvisitor.h @@ -3,6 +3,11 @@ #include #include +#include + +namespace KDevelop { +class Identifier; +} namespace Python { @@ -14,6 +19,7 @@ class ExpressionVisitor : public AstDefaultVisitor virtual void visitBinaryOperation(BinaryOperationAst* node); virtual void visitUnaryOperation(UnaryOperationAst* node); + virtual void visitBooleanOperation(BooleanOperationAst* node); virtual void visitString(StringAst* node); virtual void visitNumber(NumberAst* node); @@ -21,6 +27,8 @@ class ExpressionVisitor : public AstDefaultVisitor KDevelop::AbstractType::Ptr lastType() const { return m_lastType; } private: + static QHash s_defaultTypes; + KDevelop::AbstractType::Ptr m_lastType; KDevelop::DUContext* m_ctx; }; diff --git a/duchain/tests/pyduchaintest.cpp b/duchain/tests/pyduchaintest.cpp index 8261326..d50c9fc 100644 --- a/duchain/tests/pyduchaintest.cpp +++ b/duchain/tests/pyduchaintest.cpp @@ -125,4 +125,6 @@ void PyDUChainTest::testSimple_data() QTest::newRow("assign") << "b = 2;" << 1 << 0; QTest::newRow("assign_str") << "b = 'hola';" << 1 << 0; QTest::newRow("op") << "a = 3; b = a+2;" << 2 << 1; + QTest::newRow("bool") << "a = True" << 1 << 0; + QTest::newRow("op") << "a = True and True;" << 1 << 0; } From a84ff96e7d1d03ad63c22160e2f6a0680c1703ea Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 5 Dec 2010 12:55:12 +0100 Subject: [PATCH 110/118] Fixed compiler warnings which aren't actually problems --- codecompletion/pythoncodecompletioncontext.cpp | 2 +- codecompletion/pythoncodecompletionworker.cpp | 2 +- duchain/contextbuilder.cpp | 6 +++--- duchain/declarationbuilder.cpp | 2 +- parser/ast.cpp | 2 +- parser/astbuilder.cpp | 6 +++--- parser/astbuilder.h | 2 +- parser/pythondriver.cpp | 2 +- pythonparsejob.cpp | 18 ++++++++++++------ 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 3336495..8f4ffb3 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -29,7 +29,7 @@ typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) +QList PythonCodeCompletionContext::completionItems(bool& /*abort*/, bool /*fullCompletion*/) { QList items; DUChainReadLocker lock(DUChain::lock()); diff --git a/codecompletion/pythoncodecompletionworker.cpp b/codecompletion/pythoncodecompletionworker.cpp index e367eb9..bd6abbd 100644 --- a/codecompletion/pythoncodecompletionworker.cpp +++ b/codecompletion/pythoncodecompletionworker.cpp @@ -17,7 +17,7 @@ PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel } -KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const +KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& /*followingText*/, const KDevelop::CursorInRevision& position) const { PythonCodeCompletionContext* completionContext = new PythonCodeCompletionContext(context, contextText, position, 0); return completionContext; diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index ed27bc6..da166a9 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -103,7 +103,7 @@ void ContextBuilder::setEditor(PythonEditorIntegrator* editor) ContextBuilder::m_editor = editor; } -void ContextBuilder::setEditor(ParseSession* session) +void ContextBuilder::setEditor(ParseSession* /*session*/) { PythonEditorIntegrator* e = new PythonEditorIntegrator(/*session*/); //m_identifierCompiler = new IdentifierCompiler(e->parseSession()); @@ -147,7 +147,7 @@ void ContextBuilder::addImportedContexts() } } -void ContextBuilder::openContextForStatementList( const QList& l, DUContext::ContextType type) +void ContextBuilder::openContextForStatementList( const QList& l, DUContext::ContextType /*type*/) { if ( l.count() > 0 ) { @@ -229,7 +229,7 @@ void ContextBuilder::visitImport(ImportAst* node) { foreach ( AliasAst* name, node->names ) { // for "import ... as", use the as thingy, use the module name otherwise - Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; +// Identifier* variableDeclarationName = name->asName ? name->asName->identifier : name->name; # TODO check this KUrl moduleFilePath = findModulePath(name->name->value); if ( ! moduleFilePath.isValid() ) continue; diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index f6db5c6..cb9b02c 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -249,7 +249,7 @@ void DeclarationBuilder::visitAssignment(AssignmentAst* node) void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) { kDebug() << "opening class definition"; - ClassDeclaration* classDec = new ClassDeclaration(editorFindRange(node->body.first(), node->body.last()), currentContext()); +// ClassDeclaration* classDec = new ClassDeclaration(editorFindRange(node->body.first(), node->body.last()), currentContext()); openDeclaration( node->name, node ); eventuallyAssignInternalContext(); diff --git a/parser/ast.cpp b/parser/ast.cpp index ae04f59..6eeeca3 100644 --- a/parser/ast.cpp +++ b/parser/ast.cpp @@ -136,7 +136,7 @@ ExceptionHandlerAst::ExceptionHandlerAst(Ast* parent): Ast(parent, Ast::Exceptio } -ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0), locals(0), globals(0) +ExecAst::ExecAst(Ast* parent): StatementAst(parent, Ast::ExecAstType), body(0), globals(0), locals(0) { } diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index 49b60b8..f5303eb 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -138,7 +138,7 @@ CodeAst* AstBuilder::parseXmlAst(QString xml) return codeAst; } -void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) { +void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType /*token = QXmlStreamReader::Invalid*/) { bool nodeAdded = false; while ( ! xmlast->atEnd() && ! xmlast->hasError() ) { @@ -165,7 +165,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok } // this will push a parent onto the stack - nodeAdded = parseAstNode(currentElementName, currentElementText, currentElementAttributes); + nodeAdded = parseAstNode(currentElementName, /*currentElementText,*/ currentElementAttributes); // we might need ElementText some day if ( ! nodeAdded ) { m_isRealNodeMap.append(false); continue; @@ -198,7 +198,7 @@ void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::Tok } } -bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes) +bool AstBuilder::parseAstNode(QString name, /*QString text, */ const QList< QXmlStreamAttribute >& attributes) { Ast* ast; diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 4441405..478d444 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -53,7 +53,7 @@ class AstBuilder CodeAst* parseXmlAst(QString xml); QString getXmlForFile(KUrl filename, const QString& contents); void parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token); - bool parseAstNode(QString name, QString text, const QList& attributes); + bool parseAstNode(QString name, /*QString text, */const QList& attributes); KDevelop::TopDUContext* m_topContext; diff --git a/parser/pythondriver.cpp b/parser/pythondriver.cpp index 15c4556..9bfe9c4 100644 --- a/parser/pythondriver.cpp +++ b/parser/pythondriver.cpp @@ -70,7 +70,7 @@ void Driver::setCurrentDocument(KUrl url) m_currentDocument = url; } -QPair Driver::parse( Python::CodeAst* ast ) +QPair Driver::parse( Python::CodeAst* /* ast */) { AstBuilder pythonparser; QPair matched; diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index eb8e6d8..6dc4e74 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -148,18 +148,18 @@ void ParseJob::run() m_duContext = builder.build(filename, m_ast); setDuChain(m_duContext); + UseBuilder usebuilder( &editor ); + usebuilder.buildUses(m_ast); + { DUChainWriteLocker lock(DUChain::lock()); + m_duContext->clearProblems(); ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); parsingEnvironmentFile->clearModificationRevisions(); parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); - m_duContext->clearProblems(); } - UseBuilder usebuilder( &editor ); - usebuilder.buildUses(m_ast); - kDebug() << "----Parsing Succeded---***"; if ( m_parent && m_parent->codeHighlighting() ) { @@ -181,7 +181,7 @@ void ParseJob::run() static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); - DUChain::self()->addDocumentChain(m_duContext); +// DUChain::self()->addDocumentChain(m_duContext); } { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); @@ -189,13 +189,19 @@ void ParseJob::run() m_duContext->clearProblems(); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } - + foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; m_duContext->addProblem(p); } setDuChain(m_duContext); } + + DUChainWriteLocker lock(DUChain::lock()); + if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { + DUChain::self()->addDocumentChain(m_duContext); + } + } ParseSession *ParseJob::parseSession() const From 0f089164e1d5dcbaf566dc80aea34fc1452ec840 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Sun, 5 Dec 2010 13:15:08 +0100 Subject: [PATCH 111/118] Added RegEx for member access code completion --- .../pythoncodecompletioncontext.cpp | 21 ++++++++++++++----- pythonparsejob.cpp | 10 ++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 8f4ffb3..cac5d02 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -51,16 +51,19 @@ QList PythonCodeCompletionContext::completionItems(bo items << CompletionTreeItemPointer( item ); } } + else if ( m_operation == PythonCodeCompletionContext::MemberAccessCompletion ) { + // we don't have type support, so we cannot support completing mebers yet. But we can at least prevent kdevelop from opening a pointless + // popup with completion items you don't want + } else { QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); - Declaration* currentDeclaration; + DeclarationPointer currentDeclaration; int count = declarations.length(); for ( int i = 0; i < count; i++ ) { - currentDeclaration = declarations.at(i).first; - kDebug() << "Adding item: " << currentDeclaration->identifier().identifier().str(); - DeclarationPointer ptr(currentDeclaration); - NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(ptr, KDevelop::CodeCompletionContext::Ptr(this)); + currentDeclaration = DeclarationPointer(declarations.at(i).first); + kDebug() << "Adding item: " << currentDeclaration.data()->identifier().identifier().str(); + NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); kDebug() << item->declaration().data()->identifier().identifier().str(); items << CompletionTreeItemPointer(item); } @@ -218,6 +221,14 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex return; } + QRegExp attributeAccess("(.*)\n[\\s]*(.*)\\.$"); + attributeAccess.setMinimal(true); + bool is_attributeAccess = attributeAccess.exactMatch(currentLine); + if ( is_attributeAccess ) { + m_operation = PythonCodeCompletionContext::MemberAccessCompletion; + return; + } + QRegExp noCompletionPossible("(.*)\n[\\s]*(class|def)[\\s]*$"); noCompletionPossible.setMinimal(true); bool is_noCompletionPossible = noCompletionPossible.exactMatch(currentLine); diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 6dc4e74..a02f0bf 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -181,7 +181,7 @@ void ParseJob::run() static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); -// DUChain::self()->addDocumentChain(m_duContext); + DUChain::self()->addDocumentChain(m_duContext); } { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); @@ -197,10 +197,10 @@ void ParseJob::run() setDuChain(m_duContext); } - DUChainWriteLocker lock(DUChain::lock()); - if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { - DUChain::self()->addDocumentChain(m_duContext); - } +// DUChainWriteLocker lock(DUChain::lock()); +// if ( ! DUChain::self()->chainForDocument(document()) && m_duContext ) { +// DUChain::self()->addDocumentChain(m_duContext); +// } } From 125409d2d5851334ae60676c39c177bb44a21f7b Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Tue, 7 Dec 2010 23:37:51 +0100 Subject: [PATCH 112/118] Hopefully fixed ranges getting invalid now, finally --- pythonparsejob.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index a02f0bf..2077900 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -173,22 +173,18 @@ void ParseJob::run() { kWarning() << "===Failed==="; DUChainWriteLocker lock; - { - m_duContext = DUChain::self()->chainForDocument(document()); + m_duContext = DUChain::self()->chainForDocument(document()); + if ( m_duContext ) { + m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); + m_duContext->clearProblems(); } - if ( ! m_duContext ) { + else { ParsingEnvironmentFile *file = new ParsingEnvironmentFile(document()); static const IndexedString langString("python"); file->setLanguage(langString); m_duContext = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file); DUChain::self()->addDocumentChain(m_duContext); } - { - m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); - m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); - m_duContext->clearProblems(); - DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); - } foreach ( ProblemPointer p, m_session->m_problems ) { kDebug() << "Added problem to context"; From 89ceff7443bdb89fc7d368ea2f8bd43d048a2454 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Wed, 8 Dec 2010 23:20:19 +0100 Subject: [PATCH 113/118] Added more advanced function autocompletion --- codecompletion/CMakeLists.txt | 1 + .../functiondeclarationcompletionitem.cpp | 28 +++++++++++++++++++ .../functiondeclarationcompletionitem.h | 23 +++++++++++++++ .../pythoncodecompletioncontext.cpp | 26 +++++++++++++++-- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 codecompletion/functiondeclarationcompletionitem.cpp create mode 100644 codecompletion/functiondeclarationcompletionitem.h diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 1231c12..7488a09 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -4,6 +4,7 @@ include_directories( ) set(completion_SRCS + functiondeclarationcompletionitem.cpp importfileitem.cpp pythoncodecompletioncontext.cpp pythoncodecompletionmodel.cpp diff --git a/codecompletion/functiondeclarationcompletionitem.cpp b/codecompletion/functiondeclarationcompletionitem.cpp new file mode 100644 index 0000000..912156d --- /dev/null +++ b/codecompletion/functiondeclarationcompletionitem.cpp @@ -0,0 +1,28 @@ + +#include +#include +#include +#include + +#include "functiondeclarationcompletionitem.h" +#include "navigation/navigationwidget.h" + +using namespace KDevelop; + +namespace Python { + +FunctionDeclarationCompletionItem::FunctionDeclarationCompletionItem(DeclarationPointer decl) : NormalDeclarationCompletionItem(decl) { } + +void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document, const KTextEditor::Range& word) +{ + kDebug() << "FunctionDeclarationCompletionItem executed"; + DUChainPointer decl = declaration().dynamicCast(); + Q_ASSERT(decl.data()); + kDebug() << "declaration data: " << decl.data(); + const QString suffix = "()"; + document->replaceText(word, decl.data()->identifier().toString() + suffix); +} + +FunctionDeclarationCompletionItem::~FunctionDeclarationCompletionItem() { } + +} \ No newline at end of file diff --git a/codecompletion/functiondeclarationcompletionitem.h b/codecompletion/functiondeclarationcompletionitem.h new file mode 100644 index 0000000..2efa1a8 --- /dev/null +++ b/codecompletion/functiondeclarationcompletionitem.h @@ -0,0 +1,23 @@ +#ifndef FUNCTIONDECLARATIONCOMPLETIONITEM_H +#define FUNCTIONDECLARATIONCOMPLETIONITEM_H + +#include +#include + +using namespace KDevelop; + +namespace Python { + +class FunctionDeclarationCompletionItem : public KDevelop::NormalDeclarationCompletionItem +{ + +public: + FunctionDeclarationCompletionItem(DeclarationPointer decl); + virtual ~FunctionDeclarationCompletionItem(); + + virtual void executed(KTextEditor::Document* document, const KTextEditor::Range& word); +}; + +} + +#endif // FUNCTIONDECLARATIONCOMPLETIONITEM_H diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index cac5d02..8985aed 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -16,6 +16,8 @@ #include "navigation/navigationwidget.h" #include "importfileitem.h" +#include "functiondeclarationcompletionitem.h" + #include #include #include @@ -23,14 +25,19 @@ #include #include +#include + using namespace KDevelop; typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& /*abort*/, bool /*fullCompletion*/) +QList PythonCodeCompletionContext::completionItems(bool& abort, bool /*fullCompletion*/) { + if ( abort ) + return QList(); + QList items; DUChainReadLocker lock(DUChain::lock()); @@ -56,14 +63,27 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { - QList declarations = m_duContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext()); + if ( abort ) { + return QList(); + } + QList declarations = m_duContext->allDeclarations(m_position, m_duContext->topContext()); DeclarationPointer currentDeclaration; int count = declarations.length(); for ( int i = 0; i < count; i++ ) { + if ( abort ) { + return items; + } currentDeclaration = DeclarationPointer(declarations.at(i).first); kDebug() << "Adding item: " << currentDeclaration.data()->identifier().identifier().str(); - NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); + NormalDeclarationCompletionItem* item; + if ( currentDeclaration.data()->abstractType() && currentDeclaration.data()->abstractType().constData()->whichType() == AbstractType::TypeFunction ) { + kDebug() << "Adding function declaration item"; + item = new FunctionDeclarationCompletionItem(currentDeclaration); + } + else { + item = new NormalDeclarationCompletionItem(currentDeclaration, KDevelop::CodeCompletionContext::Ptr(this)); + } kDebug() << item->declaration().data()->identifier().identifier().str(); items << CompletionTreeItemPointer(item); } From 1aa72bed8ff7af9d21b8cea6198e57f51416b6ff Mon Sep 17 00:00:00 2001 From: Miquel Canes Gonzalez Date: Thu, 9 Dec 2010 08:33:57 +0100 Subject: [PATCH 114/118] Fixing addproblems from expressionvisitor. Fixing boolean operator --- duchain/expressionvisitor.cpp | 36 +++++++++++++++++------------------ pythonparsejob.cpp | 9 +++++---- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp index d44a946..83f0c02 100644 --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -33,8 +33,7 @@ void Python::ExpressionVisitor::visitString(Python::StringAst* ) RangeInRevision nodeRange(Python::Ast* node) { qDebug() << node->endLine; -// return RangeInRevision(node->startLine, node->startCol, node->endLine,node->endCol); - return RangeInRevision(0,0, 2, 2); + return RangeInRevision(node->startLine, node->startCol, node->endLine,node->endCol); } void Python::ExpressionVisitor::visitName(Python::NameAst* node) @@ -59,9 +58,10 @@ void Python::ExpressionVisitor::visitName(Python::NameAst* node) ProblemPointer p(new Problem); p->setRange(r); p->setDescription(i18n("undefined variable '%1'", node->identifier->value)); + qDebug() << "adddProblemKiko" << m_ctx->topContext()->url().str(); p->setFinalLocation(DocumentRange(m_ctx->topContext()->url(), r.castToSimpleRange())); p->setSeverity(ProblemData::Error); - p->setSource(KDevelop::ProblemData::Parser); + p->setSource(KDevelop::ProblemData::SemanticAnalysis); m_ctx->topContext()->addProblem(p); } } @@ -89,23 +89,23 @@ void Python::ExpressionVisitor::visitUnaryOperation(Python::UnaryOperationAst* n void Python::ExpressionVisitor::visitBooleanOperation(Python::BooleanOperationAst* node) { - bool problem = false; +// foreach (ExpressionAst* expression, node->values) { visitNode(expression); - if(m_lastType->whichType() != AbstractType::TypeIntegral || m_lastType.cast()->dataType() != IntegralType::TypeBoolean){ - problem = true; - qDebug() << "VistBooleanOperation type not match"; - RangeInRevision r = nodeRange(expression); - ProblemPointer p(new Problem); - p->setRange(r); - p->setDescription(i18n("wrong type '%1'", m_lastType->toString())); - p->setFinalLocation(DocumentRange(m_ctx->topContext()->url(), r.castToSimpleRange())); - p->setSeverity(ProblemData::Error); - p->setSource(KDevelop::ProblemData::SemanticAnalysis); - m_ctx->topContext()->addProblem(p); - } +// if(m_lastType->whichType() != AbstractType::TypeIntegral || m_lastType.cast()->dataType() != IntegralType::TypeBoolean){ +// problem = true; +// qDebug() << "VistBooleanOperation type not match"; +// RangeInRevision r = nodeRange(expression); +// ProblemPointer p(new Problem); +// p->setRange(r); +// p->setDescription(i18n("wrong type '%1'", m_lastType->toString())); +// p->setFinalLocation(DocumentRange(m_ctx->topContext()->url(), r.castToSimpleRange())); +// p->setSeverity(ProblemData::Error); +// p->setSource(KDevelop::ProblemData::SemanticAnalysis); +// m_ctx->topContext()->addProblem(p); +// } } - //if(!problem) - m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); + + m_lastType = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); } diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index eb8e6d8..8796c48 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -139,7 +139,7 @@ void ParseJob::run() // printer.visitCode( m_ast ); if ( abortRequested() ) return abortJob(); - + PythonEditorIntegrator editor; DeclarationBuilder builder( &editor ); @@ -148,13 +148,14 @@ void ParseJob::run() m_duContext = builder.build(filename, m_ast); setDuChain(m_duContext); - { + { DUChainWriteLocker lock(DUChain::lock()); ParsingEnvironmentFilePointer parsingEnvironmentFile = m_duContext->parsingEnvironmentFile(); parsingEnvironmentFile->clearModificationRevisions(); parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); - m_duContext->clearProblems(); + //m_duContext->clearProblems(); + qDebug() << "cleaning problems kiko"; } UseBuilder usebuilder( &editor ); @@ -186,7 +187,7 @@ void ParseJob::run() { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); - m_duContext->clearProblems(); + // m_duContext->clearProblems(); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } From 90d0e96462df937968b8c4400339bb5c3643376a Mon Sep 17 00:00:00 2001 From: Miquel Canes Gonzalez Date: Thu, 9 Dec 2010 08:45:51 +0100 Subject: [PATCH 115/118] Removing debug, and wrong comment --- pythonparsejob.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index 8796c48..7287502 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -155,7 +155,6 @@ void ParseJob::run() parsingEnvironmentFile->setModificationRevision(contents().modification); DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); //m_duContext->clearProblems(); - qDebug() << "cleaning problems kiko"; } UseBuilder usebuilder( &editor ); @@ -187,7 +186,7 @@ void ParseJob::run() { m_duContext->parsingEnvironmentFile()->clearModificationRevisions(); m_duContext->parsingEnvironmentFile()->setModificationRevision(contents().modification); - // m_duContext->clearProblems(); + m_duContext->clearProblems(); DUChain::self()->updateContextEnvironment(m_duContext, m_duContext->parsingEnvironmentFile().data()); } From 15649bf71540d9adcb293c795419304ed9204a59 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 15:58:49 +0100 Subject: [PATCH 116/118] More autocompletion --- codecompletion/functiondeclarationcompletionitem.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/codecompletion/functiondeclarationcompletionitem.cpp b/codecompletion/functiondeclarationcompletionitem.cpp index 912156d..bd8aecd 100644 --- a/codecompletion/functiondeclarationcompletionitem.cpp +++ b/codecompletion/functiondeclarationcompletionitem.cpp @@ -2,12 +2,15 @@ #include #include #include -#include + +#include +#include #include "functiondeclarationcompletionitem.h" #include "navigation/navigationwidget.h" using namespace KDevelop; +using namespace KTextEditor; namespace Python { @@ -20,7 +23,14 @@ void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document Q_ASSERT(decl.data()); kDebug() << "declaration data: " << decl.data(); const QString suffix = "()"; + int skip = 2; // place cursor behind bracktes + if ( decl.data()->defaultParametersSize() != 0 ) { + skip = 1; // place cursor in brackets if there's parameters + } document->replaceText(word, decl.data()->identifier().toString() + suffix); + if ( View* view = document->activeView() ) { + view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) ); + } } FunctionDeclarationCompletionItem::~FunctionDeclarationCompletionItem() { } From d1a221d98f1c7700f244ac0bc398e6c274983582 Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 22:51:30 +0100 Subject: [PATCH 117/118] Keyword items for code completion --- codecompletion/CMakeLists.txt | 1 + codecompletion/keyworditem.cpp | 47 +++++++++++++++++++ codecompletion/keyworditem.h | 22 +++++++++ .../pythoncodecompletioncontext.cpp | 19 +++++++- codecompletion/pythoncodecompletioncontext.h | 3 +- example_ast.py | 8 ++++ 6 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 codecompletion/keyworditem.cpp create mode 100644 codecompletion/keyworditem.h diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 7488a09..2cdef3d 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -4,6 +4,7 @@ include_directories( ) set(completion_SRCS + keyworditem.cpp functiondeclarationcompletionitem.cpp importfileitem.cpp pythoncodecompletioncontext.cpp diff --git a/codecompletion/keyworditem.cpp b/codecompletion/keyworditem.cpp new file mode 100644 index 0000000..0ed0c13 --- /dev/null +++ b/codecompletion/keyworditem.cpp @@ -0,0 +1,47 @@ +#include "keyworditem.h" +#include +#include +#include +#include +#include + +using namespace KDevelop; +using namespace KTextEditor; + +namespace Python { + +Python::KeywordItem::KeywordItem(KDevelop::CodeCompletionContext::Ptr context, QString keyword) : NormalDeclarationCompletionItem ( DeclarationPointer(), context, 0 ) +{ + m_keyword = keyword; +} + +void Python::KeywordItem::execute ( KTextEditor::Document* document, const KTextEditor::Range& word ) +{ + document->replaceText(word, m_keyword); +} + +QVariant KeywordItem::data ( const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model ) const +{ + switch (role) { + case KDevelop::CodeCompletionModel::IsExpandable: + return QVariant(false); + case Qt::DisplayRole: + if (index.column() == KTextEditor::CodeCompletionModel::Name) { + return QVariant(m_keyword); + } else { + return QVariant(""); + } + break; + case KTextEditor::CodeCompletionModel::ItemSelected: + return QVariant(""); + case KTextEditor::CodeCompletionModel::InheritanceDepth: + return QVariant(0); + default: + //pass + break; + } + + return NormalDeclarationCompletionItem::data(index, role, model); +} + +} diff --git a/codecompletion/keyworditem.h b/codecompletion/keyworditem.h new file mode 100644 index 0000000..488153d --- /dev/null +++ b/codecompletion/keyworditem.h @@ -0,0 +1,22 @@ +#ifndef KEYWORDITEM_H +#define KEYWORDITEM_H + +#include + +using namespace KDevelop; + +namespace Python { + +class KeywordItem : public NormalDeclarationCompletionItem +{ + +public: + KeywordItem(KDevelop::CodeCompletionContext::Ptr context, QString keyword); + virtual void execute ( KTextEditor::Document* document, const KTextEditor::Range& word ); + virtual QVariant data ( const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model ) const; + QString m_keyword; +}; + +} + +#endif // KEYWORDITEM_H diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 8985aed..75bfe43 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -6,9 +6,9 @@ #include "pythoncodecompletioncontext.h" -#include #include #include +#include #include #include @@ -26,6 +26,8 @@ #include #include +#include +#include "keyworditem.h" using namespace KDevelop; @@ -63,6 +65,13 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { + if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion ) { + QStringList keywordItems; + keywordItems << "def" << "class" << "lambda" << "global" << "print"; + foreach ( const QString& current, keywordItems ) { + items << CompletionTreeItemPointer(new KeywordItem(KDevelop::CodeCompletionContext::Ptr(this), current)); + } + } if ( abort ) { return QList(); } @@ -230,6 +239,14 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex return; } + QRegExp newStatementCompletion("(.*)\n[\\s]*$"); + newStatementCompletion.setMinimal(true); + bool isNewStatementCompletion = newStatementCompletion.exactMatch(currentLine); + if ( isNewStatementCompletion ) { + m_operation = PythonCodeCompletionContext::NewStatementCompletion; + return; + } + QRegExp importfile("(.*)\n[\\s]*import[\\s]*$"); importfile.setMinimal(true); bool is_importfile = importfile.exactMatch(currentLine); diff --git a/codecompletion/pythoncodecompletioncontext.h b/codecompletion/pythoncodecompletioncontext.h index 5af62a3..45123f8 100644 --- a/codecompletion/pythoncodecompletioncontext.h +++ b/codecompletion/pythoncodecompletioncontext.h @@ -24,7 +24,8 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: MemberAccessCompletion, DefaultCompletion, ImportSubCompletion, - NoCompletion + NoCompletion, + NewStatementCompletion }; PythonCodeCompletionContext(DUContextPointer context, const QString& text, const KDevelop::CursorInRevision& position, int depth); diff --git a/example_ast.py b/example_ast.py index 09b78b3..68b3113 100644 --- a/example_ast.py +++ b/example_ast.py @@ -51,6 +51,14 @@ def func(foo, bar, baz, bang, foobang, foobar, foobazbar, foobazbarbang): if foobazbar < 5: pass +func(sys) +simple_func() + +def func_without_param(): + pass + +func_without_param() + def another_function(param): print param From 22d211b079905de5dff90657c4c1b10c7f35282c Mon Sep 17 00:00:00 2001 From: Sven Brauch Date: Thu, 9 Dec 2010 22:58:29 +0100 Subject: [PATCH 118/118] Don't display trivial completion items on full completion --- codecompletion/pythoncodecompletioncontext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codecompletion/pythoncodecompletioncontext.cpp b/codecompletion/pythoncodecompletioncontext.cpp index 75bfe43..61b0a25 100644 --- a/codecompletion/pythoncodecompletioncontext.cpp +++ b/codecompletion/pythoncodecompletioncontext.cpp @@ -35,7 +35,7 @@ typedef QPair DeclarationDepthPair; namespace Python { -QList PythonCodeCompletionContext::completionItems(bool& abort, bool /*fullCompletion*/) +QList PythonCodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { if ( abort ) return QList(); @@ -65,7 +65,8 @@ QList PythonCodeCompletionContext::completionItems(bo // popup with completion items you don't want } else { - if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion ) { + // it's stupid to display a 3-letter completion item on manually invoked code completion and makes everything look crowded + if ( m_operation == PythonCodeCompletionContext::NewStatementCompletion && ! fullCompletion ) { QStringList keywordItems; keywordItems << "def" << "class" << "lambda" << "global" << "print"; foreach ( const QString& current, keywordItems ) {