Commit 0b2b6f96 authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Initial work on the QML expression evaluator.

parent 454b3bc4
......@@ -78,6 +78,11 @@ QList<DiagnosticMessage> DuiDocument::diagnosticMessages() const
return _diagnosticMessages;
}
QString DuiDocument::source() const
{
return _source;
}
void DuiDocument::setSource(const QString &source)
{
_source = source;
......@@ -129,9 +134,7 @@ DuiDocument::PtrList Snapshot::importedDocuments(const DuiDocument::Ptr &doc, co
const QString docPath = doc->path() + '/' + importPath;
for (Iterator i = iterator(); i.hasNext();) {
DuiDocument::Ptr candidate = i.next().value();
foreach (DuiDocument::Ptr candidate, *this) {
if (candidate == doc)
continue;
......@@ -148,9 +151,7 @@ QMap<QString, DuiDocument::Ptr> Snapshot::componentsDefinedByImportedDocuments(c
const QString docPath = doc->path() + '/' + importPath;
for (Iterator i = iterator(); i.hasNext();) {
DuiDocument::Ptr candidate = i.next().value();
foreach (DuiDocument::Ptr candidate, *this) {
if (candidate == doc)
continue;
......
......@@ -45,23 +45,25 @@ namespace DuiEditor {
class DUIEDITOR_EXPORT DuiDocument
{
public:
typedef QSharedPointer<DuiDocument> Ptr;
typedef QSharedPointer<DuiDocument> Ptr;
typedef QList<DuiDocument::Ptr> PtrList;
typedef QMap<QString, QPair<QmlJS::AST::SourceLocation, QmlJS::AST::Node*> > IdTable;
protected:
DuiDocument(const QString &fileName);
DuiDocument(const QString &fileName);
public:
~DuiDocument();
~DuiDocument();
static DuiDocument::Ptr create(const QString &fileName);
static DuiDocument::Ptr create(const QString &fileName);
QmlJS::AST::UiProgram *program() const;
QList<QmlJS::DiagnosticMessage> diagnosticMessages() const;
QmlJS::AST::UiProgram *program() const;
QList<QmlJS::DiagnosticMessage> diagnosticMessages() const;
void setSource(const QString &source);
bool parse();
QString source() const;
void setSource(const QString &source);
bool parse();
bool isParsedCorrectly() const
{ return _parsedCorrectly; }
......@@ -73,30 +75,26 @@ public:
QString componentName() const { return _componentName; }
private:
QmlJS::Engine *_engine;
QmlJS::NodePool *_pool;
QmlJS::AST::UiProgram *_program;
QList<QmlJS::DiagnosticMessage> _diagnosticMessages;
QString _fileName;
QmlJS::Engine *_engine;
QmlJS::NodePool *_pool;
QmlJS::AST::UiProgram *_program;
QList<QmlJS::DiagnosticMessage> _diagnosticMessages;
QString _fileName;
QString _path;
QString _componentName;
QString _source;
QString _source;
bool _parsedCorrectly;
IdTable _ids;
};
class DUIEDITOR_EXPORT Snapshot: protected QMap<QString, DuiDocument::Ptr>
class DUIEDITOR_EXPORT Snapshot: public QMap<QString, DuiDocument::Ptr>
{
public:
Snapshot();
~Snapshot();
Snapshot();
~Snapshot();
void insert(const DuiDocument::Ptr &document);
typedef QMapIterator<QString, DuiDocument::Ptr> Iterator;
Iterator iterator() const
{ return Iterator(*this); }
DuiDocument::Ptr document(const QString &fileName) const
{ return value(fileName); }
......
......@@ -37,7 +37,9 @@
#include "qmljsastvisitor_p.h"
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
#include "qmlexpressionundercursor.h"
#include "qmllookupcontext.h"
#include "resolveqmlexpression.h"
#include "rewriter_p.h"
#include "idcollector.h"
......@@ -714,16 +716,32 @@ TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cur
if (!doc)
return link;
NavigationTokenFinder finder;
finder(doc, cursor.position(), snapshot);
if (finder.targetFound()) {
link.fileName = finder.fileName();
link.pos = finder.linkPosition();
link.length = finder.linkLength();
if (resolveTarget) {
link.line = finder.targetLine();
link.column = finder.targetColumn() - 1;
// NavigationTokenFinder finder;
// finder(doc, cursor.position(), snapshot);
// if (finder.targetFound()) {
// link.fileName = finder.fileName();
// link.pos = finder.linkPosition();
// link.length = finder.linkLength();
//
// if (resolveTarget) {
// link.line = finder.targetLine();
// link.column = finder.targetColumn() - 1;
// }
// }
QmlExpressionUnderCursor expressionUnderCursor;
expressionUnderCursor(cursor, doc->program());
QmlLookupContext context(expressionUnderCursor.expressionScopes(),
expressionUnderCursor.expressionNode(),
doc, snapshot);
ResolveQmlExpression resolve(context);
if (QmlLookupContext::Symbol *symbol = resolve(expressionUnderCursor.expressionNode())) {
if (UiObjectMember *member = static_cast<UiObjectMember *>(symbol)) { // ### FIXME: don't use static_cast<>
const int begin = member->firstSourceLocation().begin();
const int end = member->lastSourceLocation().end();
qDebug() << doc->source().mid(begin, end - begin);
}
}
......
......@@ -42,7 +42,7 @@ class QTimer;
QT_END_NAMESPACE
namespace Core {
class ICore;
class ICore;
}
namespace DuiEditor {
......@@ -52,103 +52,102 @@ class DuiModelManagerInterface;
namespace Internal {
class DuiHighlighter;
class ScriptEditor;
class ScriptEditorEditable : public TextEditor::BaseTextEditorEditable
{
Q_OBJECT
Q_OBJECT
public:
ScriptEditorEditable(ScriptEditor *, const QList<int> &);
QList<int> context() const;
ScriptEditorEditable(ScriptEditor *, const QList<int> &);
QList<int> context() const;
bool duplicateSupported() const { return true; }
Core::IEditor *duplicate(QWidget *parent);
const char *kind() const;
bool isTemporary() const { return false; }
bool duplicateSupported() const { return true; }
Core::IEditor *duplicate(QWidget *parent);
const char *kind() const;
bool isTemporary() const { return false; }
private:
QList<int> m_context;
QList<int> m_context;
};
struct Declaration
{
QString text;
int startLine;
int startColumn;
int endLine;
int endColumn;
Declaration()
: startLine(0),
startColumn(0),
endLine(0),
endColumn(0)
{ }
QString text;
int startLine;
int startColumn;
int endLine;
int endColumn;
Declaration()
: startLine(0),
startColumn(0),
endLine(0),
endColumn(0)
{ }
};
class ScriptEditor : public TextEditor::BaseTextEditor
{
Q_OBJECT
Q_OBJECT
public:
typedef QList<int> Context;
typedef QList<int> Context;
ScriptEditor(const Context &context,
QWidget *parent = 0);
~ScriptEditor();
ScriptEditor(const Context &context,
QWidget *parent = 0);
~ScriptEditor();
QList<Declaration> declarations() const;
QStringList words() const;
QStringList keywords() const;
QList<Declaration> declarations() const;
QStringList words() const;
QStringList keywords() const;
QList<QmlJS::DiagnosticMessage> diagnosticMessages() const
{ return m_diagnosticMessages; }
QList<QmlJS::DiagnosticMessage> diagnosticMessages() const
{ return m_diagnosticMessages; }
virtual void unCommentSelection();
virtual void unCommentSelection();
DuiDocument::Ptr duiDocument() const { return m_document; }
public slots:
virtual void setFontSettings(const TextEditor::FontSettings &);
virtual void setFontSettings(const TextEditor::FontSettings &);
private slots:
void onDocumentUpdated(DuiDocument::Ptr doc);
void updateDocument();
void updateDocumentNow();
void jumpToMethod(int index);
void updateMethodBoxIndex();
void updateMethodBoxToolTip();
void updateFileName();
void updateDocument();
void updateDocumentNow();
void jumpToMethod(int index);
void updateMethodBoxIndex();
void updateMethodBoxToolTip();
void updateFileName();
// refactoring ops
void renameIdUnderCursor();
// refactoring ops
void renameIdUnderCursor();
protected:
void contextMenuEvent(QContextMenuEvent *e);
TextEditor::BaseTextEditorEditable *createEditableInterface();
void createToolBar(ScriptEditorEditable *editable);
void contextMenuEvent(QContextMenuEvent *e);
TextEditor::BaseTextEditorEditable *createEditableInterface();
void createToolBar(ScriptEditorEditable *editable);
TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
virtual void reformat(QTextDocument *doc, QTextBlock block);
private:
virtual bool isElectricCharacter(const QChar &ch) const;
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
virtual bool isElectricCharacter(const QChar &ch) const;
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
QString wordUnderCursor() const;
QString wordUnderCursor() const;
const Context m_context;
const Context m_context;
QTimer *m_updateDocumentTimer;
QComboBox *m_methodCombo;
QList<Declaration> m_declarations;
QStringList m_words;
QMap<QString, QList<QmlJS::AST::SourceLocation> > m_ids; // ### use QMultiMap
QList<QmlJS::DiagnosticMessage> m_diagnosticMessages;
DuiDocument::Ptr m_document;
QTimer *m_updateDocumentTimer;
QComboBox *m_methodCombo;
QList<Declaration> m_declarations;
QStringList m_words;
QMap<QString, QList<QmlJS::AST::SourceLocation> > m_ids; // ### use QMultiMap
QList<QmlJS::DiagnosticMessage> m_diagnosticMessages;
DuiDocument::Ptr m_document;
DuiModelManagerInterface *m_modelManager;
};
......
......@@ -9,12 +9,20 @@ using namespace QmlJS;
using namespace QmlJS::AST;
QmlExpressionUnderCursor::QmlExpressionUnderCursor()
: _expressionNode(0),
_pos(0)
{
}
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor)
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor,
QmlJS::AST::UiProgram *program)
{
_pos = cursor.position();
_expressionNode = 0;
_scopes.clear();
if (program)
program->accept(this);
}
bool QmlExpressionUnderCursor::visit(QmlJS::AST::Block *ast)
......
......@@ -14,7 +14,7 @@ class QmlExpressionUnderCursor: protected QmlJS::AST::Visitor
public:
QmlExpressionUnderCursor();
void operator()(const QTextCursor &cursor);
void operator()(const QTextCursor &cursor, QmlJS::AST::UiProgram *program);
QStack<QmlJS::AST::Node *> expressionScopes() const
{ return _expressionScopes; }
......@@ -36,7 +36,6 @@ private:
QStack<QmlJS::AST::Node *> _scopes;
QStack<QmlJS::AST::Node *> _expressionScopes;
QmlJS::AST::Node *_expressionNode;
quint32 _pos;
};
......
......@@ -20,3 +20,19 @@ QmlLookupContext::QmlLookupContext(const QStack<QmlJS::AST::Node *> &scopes,
_snapshot(snapshot)
{
}
QmlLookupContext::Symbol *QmlLookupContext::resolve(const QString &name) const
{
// ### TODO: look at property definitions
// look at the ids.
foreach (DuiDocument::Ptr doc, _snapshot) {
const DuiDocument::IdTable ids = doc->ids();
const QPair<SourceLocation, Node *> use = ids.value(name);
if (Node *node = use.second)
return node;
}
return 0;
}
......@@ -17,6 +17,10 @@ public:
const DuiDocument::Ptr &doc,
const Snapshot &snapshot);
typedef QmlJS::AST::Node Symbol; // ### FIXME: this needs to be a class.
Symbol *resolve(const QString &name) const;
private:
QStack<QmlJS::AST::Node *> _scopes;
QmlJS::AST::Node *_expressionNode;
......
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
#include "resolveqmlexpression.h"
using namespace DuiEditor;
......@@ -8,6 +7,61 @@ using namespace DuiEditor::Internal;
using namespace QmlJS;
using namespace QmlJS::AST;
ResolveQmlExpression::ResolveQmlExpression()
ResolveQmlExpression::ResolveQmlExpression(const QmlLookupContext &context)
: _context(context), _value(0)
{
}
QmlLookupContext::Symbol *ResolveQmlExpression::typeOf(Node *node)
{
QmlLookupContext::Symbol *previousValue = switchValue(0);
if (node)
node->accept(this);
return switchValue(previousValue);
}
QmlLookupContext::Symbol *ResolveQmlExpression::switchValue(QmlLookupContext::Symbol *value)
{
QmlLookupContext::Symbol *previousValue = _value;
_value = value;
return previousValue;
}
bool ResolveQmlExpression::visit(IdentifierExpression *ast)
{
const QString name = ast->name->asString();
_value = _context.resolve(name);
return false;
}
bool ResolveQmlExpression::visit(FieldMemberExpression *ast)
{
const QString memberName = ast->name->asString();
if (QmlLookupContext::Symbol *base = typeOf(ast->base)) {
UiObjectMemberList *members = 0;
if (UiObjectBinding *uiObjectBinding = cast<UiObjectBinding *>(base)) {
if (uiObjectBinding->initializer)
members = uiObjectBinding->initializer->members;
} else if (UiObjectDefinition *uiObjectDefinition = cast<UiObjectDefinition *>(base)) {
if (uiObjectDefinition->initializer)
members = uiObjectDefinition->initializer->members;
}
for (UiObjectMemberList *it = members; it; it = it->next) {
UiObjectMember *member = it->member;
if (UiPublicMember *publicMember = cast<UiPublicMember *>(member)) {
if (publicMember->name->asString() == memberName) {
_value = publicMember;
break; // we're done.
}
}
}
}
return false;
}
......@@ -2,6 +2,7 @@
#define RESOLVEQMLEXPRESSION_H
#include "qmljsastvisitor_p.h"
#include "qmllookupcontext.h"
namespace DuiEditor {
namespace Internal {
......@@ -9,11 +10,23 @@ namespace Internal {
class ResolveQmlExpression: protected QmlJS::AST::Visitor
{
public:
ResolveQmlExpression();
ResolveQmlExpression(const QmlLookupContext &context);
QmlLookupContext::Symbol *operator()(QmlJS::AST::Node *node)
{ return typeOf(node); }
protected:
using QmlJS::AST::Visitor::visit;
QmlLookupContext::Symbol *typeOf(QmlJS::AST::Node *node);
QmlLookupContext::Symbol *switchValue(QmlLookupContext::Symbol *symbol);
virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
private:
QmlLookupContext _context;
QmlLookupContext::Symbol *_value;
};
} // namespace Internal
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment