From 3d44c5621d7c69d4b8ef81bbab66f831b1978618 Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Mon, 8 Feb 2010 21:37:59 +0100 Subject: [PATCH] Improved completion of JavaScript expressions. --- src/libs/qmljs/qmljsdocument.cpp | 65 +++++++------------ src/libs/qmljs/qmljsdocument.h | 3 + src/libs/qmljs/qmljslink.cpp | 22 +++++-- src/plugins/qmljseditor/qmlcodecompletion.cpp | 1 + src/plugins/qmljseditor/qmljseditor.cpp | 10 +-- 5 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index fc3fb9ec883..3ba72a4bee6 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -129,7 +129,7 @@ void Document::setDocumentRevision(int revision) _documentRevision = revision; } -bool Document::parseQml() +bool Document::parse_helper(int startToken) { Q_ASSERT(! _engine); Q_ASSERT(! _pool); @@ -144,8 +144,21 @@ bool Document::parseQml() lexer.setCode(_source, /*line = */ 1); - _parsedCorrectly = parser.parse(); - _ast = parser.ast(); + switch (startToken) { + case QmlJSGrammar::T_FEED_UI_PROGRAM: + _parsedCorrectly = parser.parse(); + break; + case QmlJSGrammar::T_FEED_JS_PROGRAM: + _parsedCorrectly = parser.parseProgram(); + break; + case QmlJSGrammar::T_FEED_JS_EXPRESSION: + _parsedCorrectly = parser.parseExpression(); + break; + default: + Q_ASSERT(0); + } + + _ast = parser.rootNode(); _diagnosticMessages = parser.diagnosticMessages(); _bind = new Bind(this); @@ -153,51 +166,19 @@ bool Document::parseQml() return _parsedCorrectly; } -bool Document::parseJavaScript() +bool Document::parseQml() { - Q_ASSERT(! _engine); - Q_ASSERT(! _pool); - Q_ASSERT(! _ast); - Q_ASSERT(! _bind); - - _engine = new Engine(); - _pool = new NodePool(_fileName, _engine); - - Lexer lexer(_engine); - Parser parser(_engine); - - lexer.setCode(_source, /*line = */ 1); - - _parsedCorrectly = parser.parseProgram(); - _ast = cast<Program*>(parser.rootNode()); - _diagnosticMessages = parser.diagnosticMessages(); - - _bind = new Bind(this); + return parse_helper(QmlJSGrammar::T_FEED_UI_PROGRAM); +} - return _parsedCorrectly; +bool Document::parseJavaScript() +{ + return parse_helper(QmlJSGrammar::T_FEED_JS_PROGRAM); } bool Document::parseExpression() { - Q_ASSERT(! _engine); - Q_ASSERT(! _pool); - Q_ASSERT(! _ast); - - _engine = new Engine(); - _pool = new NodePool(_fileName, _engine); - - Lexer lexer(_engine); - Parser parser(_engine); - - lexer.setCode(_source, /*line = */ 1); - - _parsedCorrectly = parser.parseExpression(); - _ast = parser.rootNode(); - if (_ast) - _ast = _ast->expressionCast(); - _diagnosticMessages = parser.diagnosticMessages(); - - return _parsedCorrectly; + return parse_helper(QmlJSGrammar::T_FEED_JS_EXPRESSION); } Bind *Document::bind() const diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index 5cc07ccf6bb..767ca281235 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -81,6 +81,9 @@ public: QString path() const { return _path; } QString componentName() const { return _componentName; } +private: + bool parse_helper(int kind); + private: QmlJS::Engine *_engine; NodePool *_pool; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index f39b91c04e3..e2f9316df33 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -45,17 +45,31 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject) // ### FIXME: May want to link to instantiating components from here. - if (bind->_rootObjectValue) - _context->pushScope(bind->_rootObjectValue); + qDebug() << "**** here" << currentObject; ObjectValue *scopeObject = 0; if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject)) scopeObject = bind->_qmlObjects.value(definition); else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject)) scopeObject = bind->_qmlObjects.value(binding); + else if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) { + _context->pushScope(bind->_rootObjectValue); - if (scopeObject && scopeObject != bind->_rootObjectValue) - _context->pushScope(scopeObject); + ObjectValue *activation = engine()->newObject(/*prototype = */ 0); + for (FormalParameterList *it = fun->formals; it; it = it->next) { + if (it->name) + activation->setProperty(it->name->asString(), engine()->undefinedValue()); + } + _context->pushScope(activation); + } + + if (scopeObject) { + if (bind->_rootObjectValue) + _context->pushScope(bind->_rootObjectValue); + + if (scopeObject != bind->_rootObjectValue) + _context->pushScope(scopeObject); + } const QStringList &includedScripts = bind->includedScripts(); for (int index = includedScripts.size() - 1; index != -1; --index) { diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 6d1bb3f064f..e063819295d 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -654,6 +654,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) // Set up the current scope chain. AST::Node *declaringMember = semanticInfo.declaringMember(editor->position()); + qDebug() << "*** declaring member:" << declaringMember; context.build(declaringMember, document, snapshot); // Search for the operator that triggered the completion. diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index 786d6e76418..65ddfe75489 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -387,8 +387,8 @@ public: { _textDocument = textDocument; _ranges.clear(); - if (doc && doc->qmlProgram() != 0) - doc->qmlProgram()->accept(this); + if (doc && doc->ast() != 0) + doc->ast()->accept(this); return _ranges; } @@ -409,7 +409,6 @@ protected: return true; } -#if 0 // ### create ranges for function declarations. virtual bool visit(AST::FunctionExpression *ast) { _ranges.append(createRange(ast)); @@ -421,7 +420,6 @@ protected: _ranges.append(createRange(ast)); return true; } -#endif Range createRange(AST::UiObjectMember *member, AST::UiObjectInitializer *ast) { @@ -448,6 +446,7 @@ protected: range.end = QTextCursor(_textDocument); range.end.setPosition(ast->rbraceToken.end()); + return range; } @@ -649,8 +648,9 @@ void QmlJSTextEditor::updateDocumentNow() void QmlJSTextEditor::onDocumentUpdated(QmlJS::Document::Ptr doc) { - if (file()->fileName() != doc->fileName()) + if (file()->fileName() != doc->fileName()) { return; + } if (doc->documentRevision() != document()->revision()) { // got an outdated document. -- GitLab