diff options
author | Roberto Raggi <roberto.raggi@nokia.com> | 2010-01-26 14:53:11 +0100 |
---|---|---|
committer | Roberto Raggi <roberto.raggi@nokia.com> | 2010-01-26 14:55:33 +0100 |
commit | ab8c19f2f8c208fdfd5eabc296c6c192c13272a4 (patch) | |
tree | bf7f1349625de125f78057c81d9bd81ce8dd7c37 /src | |
parent | 1e6a0523a141922bd59a5b04477a51b462d0f278 (diff) | |
download | qt-creator-ab8c19f2f8c208fdfd5eabc296c6c192c13272a4.tar.gz |
Some initial work on the type checker for QML/JS.
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/qmljs/qmljscheck.cpp | 258 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscheck.h | 19 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.cpp | 8 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.h | 1 | ||||
-rw-r--r-- | src/plugins/qmljseditor/qmlcodecompletion.cpp | 123 |
5 files changed, 192 insertions, 217 deletions
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 888e81896a..877959b967 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -28,11 +28,18 @@ **************************************************************************/ #include "qmljscheck.h" +#include "qmljsinterpreter.h" +#include "parser/qmljsparser_p.h" #include "parser/qmljsast_p.h" +#include <QtCore/QDebug> using namespace QmlJS; +using namespace QmlJS::Interpreter; -Check::Check() +Check::Check(Interpreter::Engine *engine) + : _engine(engine), + _scope(engine->globalObject()), + _result(0) { } @@ -40,9 +47,43 @@ Check::~Check() { } -void Check::operator()(Document::Ptr doc) +const Interpreter::Value *Check::operator()(AST::ExpressionNode *ast, const Interpreter::ObjectValue *scope) { - _doc = doc; + const Interpreter::ObjectValue *previousScope = switchScope(scope); + const Interpreter::Value *result = check(ast); + (void) switchScope(previousScope); + return result; +} + +const Interpreter::Value *Check::check(AST::ExpressionNode *ast) +{ + const Value *previousResult = switchResult(0); + accept(ast); + const Value *result = switchResult(previousResult); + if (! result) + result = _engine->undefinedValue(); + return result; +} + +Interpreter::Engine *Check::switchEngine(Interpreter::Engine *engine) +{ + Interpreter::Engine *previousEngine = _engine; + _engine = engine; + return previousEngine; +} + +const Interpreter::Value *Check::switchResult(const Interpreter::Value *result) +{ + const Interpreter::Value *previousResult = _result; + _result = result; + return previousResult; +} + +const Interpreter::ObjectValue *Check::switchScope(const Interpreter::ObjectValue *scope) +{ + const Interpreter::ObjectValue *previousScope = _scope; + _scope = scope; + return previousScope; } void Check::accept(AST::Node *node) @@ -52,450 +93,475 @@ void Check::accept(AST::Node *node) bool Check::visit(AST::UiProgram *) { - return true; + return false; } bool Check::visit(AST::UiImportList *) { - return true; + return false; } bool Check::visit(AST::UiImport *) { - return true; + return false; } bool Check::visit(AST::UiPublicMember *) { - return true; + return false; } bool Check::visit(AST::UiSourceElement *) { - return true; + return false; } bool Check::visit(AST::UiObjectDefinition *) { - return true; + return false; } bool Check::visit(AST::UiObjectInitializer *) { - return true; + return false; } bool Check::visit(AST::UiObjectBinding *) { - return true; + return false; } bool Check::visit(AST::UiScriptBinding *) { - return true; + return false; } bool Check::visit(AST::UiArrayBinding *) { - return true; + return false; } bool Check::visit(AST::UiObjectMemberList *) { - return true; + return false; } bool Check::visit(AST::UiArrayMemberList *) { - return true; + return false; } bool Check::visit(AST::UiQualifiedId *) { - return true; + return false; } bool Check::visit(AST::UiSignature *) { - return true; + return false; } bool Check::visit(AST::UiFormalList *) { - return true; + return false; } bool Check::visit(AST::UiFormal *) { - return true; + return false; } bool Check::visit(AST::ThisExpression *) { - return true; + return false; } -bool Check::visit(AST::IdentifierExpression *) +bool Check::visit(AST::IdentifierExpression *ast) { - return true; + if (! ast->name) + return false; + + _result = _scope->lookup(ast->name->asString()); + return false; } bool Check::visit(AST::NullExpression *) { - return true; + _result = _engine->nullValue(); + return false; } bool Check::visit(AST::TrueLiteral *) { - return true; + _result = _engine->booleanValue(); + return false; } bool Check::visit(AST::FalseLiteral *) { - return true; + _result = _engine->booleanValue(); + return false; } bool Check::visit(AST::StringLiteral *) { - return true; + _result = _engine->stringValue(); + return false; } bool Check::visit(AST::NumericLiteral *) { - return true; + _result = _engine->numberValue(); + return false; } bool Check::visit(AST::RegExpLiteral *) { - return true; + _result = _engine->regexpCtor()->construct(); + return false; } bool Check::visit(AST::ArrayLiteral *) { - return true; + _result = _engine->arrayCtor()->construct(); + return false; } bool Check::visit(AST::ObjectLiteral *) { - return true; + return false; } bool Check::visit(AST::ElementList *) { - return true; + return false; } bool Check::visit(AST::Elision *) { - return true; + return false; } bool Check::visit(AST::PropertyNameAndValueList *) { - return true; + return false; } bool Check::visit(AST::NestedExpression *) { - return true; + return true; // visit the child expression } bool Check::visit(AST::IdentifierPropertyName *) { - return true; + return false; } bool Check::visit(AST::StringLiteralPropertyName *) { - return true; + return false; } bool Check::visit(AST::NumericLiteralPropertyName *) { - return true; + return false; } bool Check::visit(AST::ArrayMemberExpression *) { - return true; + return false; } -bool Check::visit(AST::FieldMemberExpression *) +bool Check::visit(AST::FieldMemberExpression *ast) { - return true; + if (! ast->name) + return false; + + if (const Interpreter::Value *base = _engine->convertToObject(check(ast->base))) { + if (const Interpreter::ObjectValue *obj = base->asObjectValue()) { + _result = obj->property(ast->name->asString()); + } + } + + return false; } bool Check::visit(AST::NewMemberExpression *) { - return true; + return false; } bool Check::visit(AST::NewExpression *) { - return true; + return false; } -bool Check::visit(AST::CallExpression *) +bool Check::visit(AST::CallExpression *ast) { - return true; + if (const Interpreter::Value *base = check(ast->base)) { + if (const Interpreter::FunctionValue *obj = base->asFunctionValue()) { + _result = obj->returnValue(); + } + } + return false; } bool Check::visit(AST::ArgumentList *) { - return true; + return false; } bool Check::visit(AST::PostIncrementExpression *) { - return true; + return false; } bool Check::visit(AST::PostDecrementExpression *) { - return true; + return false; } bool Check::visit(AST::DeleteExpression *) { - return true; + return false; } bool Check::visit(AST::VoidExpression *) { - return true; + return false; } bool Check::visit(AST::TypeOfExpression *) { - return true; + return false; } bool Check::visit(AST::PreIncrementExpression *) { - return true; + return false; } bool Check::visit(AST::PreDecrementExpression *) { - return true; + return false; } bool Check::visit(AST::UnaryPlusExpression *) { - return true; + return false; } bool Check::visit(AST::UnaryMinusExpression *) { - return true; + return false; } bool Check::visit(AST::TildeExpression *) { - return true; + return false; } bool Check::visit(AST::NotExpression *) { - return true; + return false; } bool Check::visit(AST::BinaryExpression *) { - return true; + return false; } bool Check::visit(AST::ConditionalExpression *) { - return true; + return false; } bool Check::visit(AST::Expression *) { - return true; + return false; } bool Check::visit(AST::Block *) { - return true; + return false; } bool Check::visit(AST::StatementList *) { - return true; + return false; } bool Check::visit(AST::VariableStatement *) { - return true; + return false; } bool Check::visit(AST::VariableDeclarationList *) { - return true; + return false; } bool Check::visit(AST::VariableDeclaration *) { - return true; + return false; } bool Check::visit(AST::EmptyStatement *) { - return true; + return false; } bool Check::visit(AST::ExpressionStatement *) { - return true; + return false; } bool Check::visit(AST::IfStatement *) { - return true; + return false; } bool Check::visit(AST::DoWhileStatement *) { - return true; + return false; } bool Check::visit(AST::WhileStatement *) { - return true; + return false; } bool Check::visit(AST::ForStatement *) { - return true; + return false; } bool Check::visit(AST::LocalForStatement *) { - return true; + return false; } bool Check::visit(AST::ForEachStatement *) { - return true; + return false; } bool Check::visit(AST::LocalForEachStatement *) { - return true; + return false; } bool Check::visit(AST::ContinueStatement *) { - return true; + return false; } bool Check::visit(AST::BreakStatement *) { - return true; + return false; } bool Check::visit(AST::ReturnStatement *) { - return true; + return false; } bool Check::visit(AST::WithStatement *) { - return true; + return false; } bool Check::visit(AST::SwitchStatement *) { - return true; + return false; } bool Check::visit(AST::CaseBlock *) { - return true; + return false; } bool Check::visit(AST::CaseClauses *) { - return true; + return false; } bool Check::visit(AST::CaseClause *) { - return true; + return false; } bool Check::visit(AST::DefaultClause *) { - return true; + return false; } bool Check::visit(AST::LabelledStatement *) { - return true; + return false; } bool Check::visit(AST::ThrowStatement *) { - return true; + return false; } bool Check::visit(AST::TryStatement *) { - return true; + return false; } bool Check::visit(AST::Catch *) { - return true; + return false; } bool Check::visit(AST::Finally *) { - return true; + return false; } bool Check::visit(AST::FunctionDeclaration *) { - return true; + return false; } bool Check::visit(AST::FunctionExpression *) { - return true; + return false; } bool Check::visit(AST::FormalParameterList *) { - return true; + return false; } bool Check::visit(AST::FunctionBody *) { - return true; + return false; } bool Check::visit(AST::Program *) { - return true; + return false; } bool Check::visit(AST::SourceElements *) { - return true; + return false; } bool Check::visit(AST::FunctionSourceElement *) { - return true; + return false; } bool Check::visit(AST::StatementSourceElement *) { - return true; + return false; } bool Check::visit(AST::DebuggerStatement *) { - return true; + return false; } diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index 2d7352f151..6864de4f8c 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -35,17 +35,29 @@ namespace QmlJS { +namespace Interpreter { + class Engine; + class Value; + class ObjectValue; + class FunctionValue; +} // end of namespace Interpreter + class QMLJS_EXPORT Check: protected AST::Visitor { public: - Check(); + Check(Interpreter::Engine *engine); virtual ~Check(); - void operator()(QmlJS::Document::Ptr doc); + const Interpreter::Value *operator()(AST::ExpressionNode *ast, const Interpreter::ObjectValue *scope); + const Interpreter::Value *check(AST::ExpressionNode *ast); protected: void accept(AST::Node *node); + Interpreter::Engine *switchEngine(Interpreter::Engine *engine); + const Interpreter::Value *switchResult(const Interpreter::Value *result); + const Interpreter::ObjectValue *switchScope(const Interpreter::ObjectValue *scope); + // Ui virtual bool visit(AST::UiProgram *ast); virtual bool visit(AST::UiImportList *ast); @@ -142,6 +154,9 @@ protected: private: QmlJS::Document::Ptr _doc; + Interpreter::Engine *_engine; + const Interpreter::ObjectValue *_scope; + const Interpreter::Value *_result; }; } // end of namespace Qml diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 951d987725..539961d32a 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -82,6 +82,14 @@ AST::Program *Document::jsProgram() const return cast<Program *>(_ast); } +AST::ExpressionNode *Document::expression() const +{ + if (_ast) + return _ast->expressionCast(); + + return 0; +} + AST::Node *Document::ast() const { return _ast; diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index bbbdc2e000..bcf57c5ac7 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -58,6 +58,7 @@ public: QmlJS::AST::UiProgram *qmlProgram() const; QmlJS::AST::Program *jsProgram() const; + QmlJS::AST::ExpressionNode *expression() const; QmlJS::AST::Node *ast() const; QList<QmlJS::DiagnosticMessage> diagnosticMessages() const; diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 56a62c98c9..4a0f6ed3d0 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -36,6 +36,7 @@ #include <qmljs/qmljsinterpreter.h> #include <qmljs/qmljssymbol.h> #include <qmljs/qmljsscanner.h> +#include <qmljs/qmljscheck.h> #include <texteditor/basetexteditor.h> @@ -254,121 +255,6 @@ protected: } }; -class Evaluate: protected AST::Visitor -{ - Interpreter::Engine *_interp; - const Interpreter::ObjectValue *_scope; - const Interpreter::Value *_value; - -public: - Evaluate(Interpreter::Engine *interp) - : _interp(interp), _scope(interp->globalObject()), _value(0) - {} - - void setScope(const Interpreter::ObjectValue *scope) - { _scope = scope; } - - const Interpreter::Value *operator()(AST::Node *node) - { return evaluate(node); } - - const Interpreter::Value *evaluate(AST::Node *node) - { - const Interpreter::Value *previousValue = switchValue(0); - - if (node) - node->accept(this); - - return switchValue(previousValue); - } - -protected: - using AST::Visitor::visit; - - const Interpreter::Value *switchValue(const Interpreter::Value *value) - { - const Interpreter::Value *previousValue = _value; - _value = value; - return previousValue; - } - - virtual bool preVisit(AST::Node *ast) // ### remove me - { - using namespace AST; - - if (cast<NumericLiteral *>(ast)) - return true; - - else if (cast<StringLiteral *>(ast)) - return true; - - else if (cast<IdentifierExpression *>(ast)) - return true; - - else if (cast<NestedExpression *>(ast)) - return true; - - else if (cast<FieldMemberExpression *>(ast)) - return true; - - else if (cast<CallExpression *>(ast)) - return true; - - return false; - } - - virtual bool visit(AST::NestedExpression *) - { - return true; - } - - virtual bool visit(AST::StringLiteral *) - { - _value = _interp->convertToObject(_interp->stringValue()); - return false; - } - - virtual bool visit(AST::NumericLiteral *) - { - _value = _interp->convertToObject(_interp->numberValue()); - return false; - } - - virtual bool visit(AST::IdentifierExpression *ast) - { - if (! ast->name) - return false; - - _value = _scope->lookup(ast->name->asString()); - return false; - } - - virtual bool visit(AST::FieldMemberExpression *ast) - { - if (! ast->name) - return false; - - if (const Interpreter::Value *base = _interp->convertToObject(evaluate(ast->base))) { - if (const Interpreter::ObjectValue *obj = base->asObjectValue()) { - _value = obj->property(ast->name->asString()); - } - } - - return false; - } - - virtual bool visit(AST::CallExpression *ast) - { - if (const Interpreter::Value *base = evaluate(ast->base)) { - if (const Interpreter::FunctionValue *obj = base->asFunctionValue()) { - _value = obj->returnValue(); - } - } - - return false; - } - -}; - class EnumerateProperties: private Interpreter::MemberProcessor { QSet<const Interpreter::ObjectValue *> _processed; @@ -971,12 +857,11 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) exprDoc->setSource(expression); exprDoc->parseExpression(); - if (exprDoc->ast()) { - Evaluate evaluate(&interp); - evaluate.setScope(scope); + if (exprDoc->expression() != 0) { + Check evaluate(&interp); // Evaluate the expression under cursor. - const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->ast())); + const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->expression(), scope)); //qDebug() << "type:" << interp.typeId(value); if (value && completionOperator == QLatin1Char('.')) { // member completion |