diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-02-10 15:56:50 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-02-10 15:56:50 (GMT) |
commit | dfb33cf9739a6dd0a6c90961c65f71692f093a38 (patch) | |
tree | e3ab31f1f2bfb7ba780adb2a6a2d23aaa88a7454 /src/declarative/qml | |
parent | f74029e286e97067ac39086955481bf979af69dc (diff) | |
parent | 1c1d31d702ee22b2cf501a4472b7068ad160df68 (diff) | |
download | Qt-dfb33cf9739a6dd0a6c90961c65f71692f093a38.zip Qt-dfb33cf9739a6dd0a6c90961c65f71692f093a38.tar.gz Qt-dfb33cf9739a6dd0a6c90961c65f71692f093a38.tar.bz2 |
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-qml into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-qml: (3377 commits)
Expect fail.
Expect fails.
Attempt to clairify highlight range docs
Make sure item release isn't deferred indefinately
Expect fail.
Missing file
Exclude plugins example in test.
Test
Crash
Fix tests
Compile.
Remove pathview test.
Remove unneeded
Fix repeater test.
Revert "Remove unimplemented methods from header"
Revert "Replace QList<>* support with QmlListProperty"
Revert "Compile"
Add expected fail and created QTBUG-8072 for qml animation auto-test
Fix expected error message.
Consolidate the two pathview tests and fix them all.
...
Diffstat (limited to 'src/declarative/qml')
141 files changed, 52308 insertions, 0 deletions
diff --git a/src/declarative/qml/parser/parser.pri b/src/declarative/qml/parser/parser.pri new file mode 100644 index 0000000..4530479 --- /dev/null +++ b/src/declarative/qml/parser/parser.pri @@ -0,0 +1,21 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/qmljsast_p.h \ + $$PWD/qmljsastfwd_p.h \ + $$PWD/qmljsastvisitor_p.h \ + $$PWD/qmljsengine_p.h \ + $$PWD/qmljsgrammar_p.h \ + $$PWD/qmljslexer_p.h \ + $$PWD/qmljsmemorypool_p.h \ + $$PWD/qmljsnodepool_p.h \ + $$PWD/qmljsparser_p.h \ + $$PWD/qmljsglobal_p.h + +SOURCES += \ + $$PWD/qmljsast.cpp \ + $$PWD/qmljsastvisitor.cpp \ + $$PWD/qmljsengine_p.cpp \ + $$PWD/qmljsgrammar.cpp \ + $$PWD/qmljslexer.cpp \ + $$PWD/qmljsparser.cpp diff --git a/src/declarative/qml/parser/qmljs.g b/src/declarative/qml/parser/qmljs.g new file mode 100644 index 0000000..90949d5 --- /dev/null +++ b/src/declarative/qml/parser/qmljs.g @@ -0,0 +1,3075 @@ +---------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +-- All rights reserved. +-- Contact: Nokia Corporation (qt-info@nokia.com) +-- +-- This file is part of the QtDeclarative module of the Qt Toolkit. +-- +-- $QT_BEGIN_LICENSE:LGPL-ONLY$ +-- GNU Lesser General Public License Usage +-- This file may be used under the terms of the GNU Lesser +-- General Public License version 2.1 as published by the Free Software +-- Foundation and appearing in the file LICENSE.LGPL included in the +-- packaging of this file. Please review the following information to +-- ensure the GNU Lesser General Public License version 2.1 requirements +-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +-- +-- If you have questions regarding the use of this file, please contact +-- Nokia at qt-info@nokia.com. +-- $QT_END_LICENSE$ +-- +---------------------------------------------------------------------------- + +%parser QmlJSGrammar +%decl qmljsparser_p.h +%impl qmljsparser.cpp +%expect 2 +%expect-rr 2 + +%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&=" +%token T_BREAK "break" T_CASE "case" T_CATCH "catch" +%token T_COLON ":" T_COMMA ";" T_CONTINUE "continue" +%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/" +%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "." +%token T_ELSE "else" T_EQ "=" T_EQ_EQ "==" +%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for" +%token T_FUNCTION "function" T_GE ">=" T_GT ">" +%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>" +%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if" +%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{" +%token T_LBRACKET "[" T_LE "<=" T_LPAREN "(" +%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<=" +%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" +%token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" +%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" +%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" +%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" +%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" +%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")" +%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*" +%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal" +%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly" +%token T_SWITCH "switch" T_THIS "this" T_THROW "throw" +%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof" +%token T_VAR "var" T_VOID "void" T_WHILE "while" +%token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" +%token T_NULL "null" T_TRUE "true" T_FALSE "false" +%token T_CONST "const" +%token T_DEBUGGER "debugger" +%token T_RESERVED_WORD "reserved word" +%token T_MULTILINE_STRING_LITERAL "multiline string literal" +%token T_COMMENT "comment" + +--- context keywords. +%token T_PUBLIC "public" +%token T_IMPORT "import" +%token T_AS "as" + +--- feed tokens +%token T_FEED_UI_PROGRAM +%token T_FEED_UI_OBJECT_MEMBER +%token T_FEED_JS_STATEMENT +%token T_FEED_JS_EXPRESSION +%token T_FEED_JS_SOURCE_ELEMENT +%token T_FEED_JS_PROGRAM + +%nonassoc SHIFT_THERE +%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY +%nonassoc REDUCE_HERE + +%start TopLevel + +/./**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtDebug> +#include <QtGui/QApplication> + +#include <string.h> + +#include "qmljsengine_p.h" +#include "qmljslexer_p.h" +#include "qmljsast_p.h" +#include "qmljsnodepool_p.h" + +./ + +/:/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +#ifndef QMLJSPARSER_P_H +#define QMLJSPARSER_P_H + +#include "qmljsglobal_p.h" +#include "qmljsgrammar_p.h" +#include "qmljsast_p.h" +#include "qmljsengine_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Parser: protected $table +{ +public: + union Value { + int ival; + double dval; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiParameterList *UiParameterList; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiArrayMemberList *UiArrayMemberList; + AST::UiQualifiedId *UiQualifiedId; + AST::UiSignature *UiSignature; + AST::UiFormalList *UiFormalList; + AST::UiFormal *UiFormal; + }; + +public: + Parser(Engine *engine); + ~Parser(); + + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } + bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; + + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } + + AST::UiObjectMember *uiObjectMember() const + { + if (! program) + return 0; + + return program->uiObjectMemberCast(); + } + + AST::Node *rootNode() const + { return program; } + + QList<DiagnosticMessage> diagnosticMessages() const + { return diagnostic_messages; } + + inline DiagnosticMessage diagnosticMessage() const + { + foreach (const DiagnosticMessage &d, diagnostic_messages) { + if (! d.kind == DiagnosticMessage::Warning) + return d; + } + + return DiagnosticMessage(); + } + + inline QString errorMessage() const + { return diagnosticMessage().message; } + + inline int errorLineNumber() const + { return diagnosticMessage().loc.startLine; } + + inline int errorColumnNumber() const + { return diagnosticMessage().loc.startColumn; } + +protected: + bool parse(int startToken); + + void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline AST::SourceLocation &loc(int index) + { return location_stack [tos + index - 1]; } + + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + +protected: + Engine *driver; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + }; + + double yylval; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList<DiagnosticMessage> diagnostic_messages; +}; + +} // end of namespace QmlJS + + +:/ + + +/. + +#include "qmljsparser_p.h" +#include <QVarLengthArray> + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QmlJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); +} + +inline static bool automatic(Engine *driver, int token) +{ + return token == $table::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +Parser::Parser(Engine *engine): + driver(engine), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse(int startToken) +{ + Lexer *lexer = driver->lexer(); + bool hadErrors = false; + int yytoken = -1; + int action = 0; + + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + tos = -1; + program = 0; + + do { + if (++tos == stack_size) + reallocateStack(); + + state_stack[tos] = action; + + _Lcheck_token: + if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { + yyprevlloc = yylloc; + + if (first_token == last_token) { + yytoken = lexer->lex(); + yylval = lexer->dval(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + loc(1) = yylloc; + } else { + --tos; + return ! hadErrors; + } + } else if (action < 0) { + const int r = -action - 1; + tos -= rhs[r]; + + switch (r) { +./ + +-------------------------------------------------------------------------------------------------------- +-- Declarative UI +-------------------------------------------------------------------------------------------------------- + +TopLevel: T_FEED_UI_PROGRAM UiProgram ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_STATEMENT Statement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_EXPRESSION Expression ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_PROGRAM Program ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +UiProgram: UiImportListOpt UiRootMember ; +/. +case $rule_number: { + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; +./ + +UiImportListOpt: Empty ; +UiImportListOpt: UiImportList ; +/. +case $rule_number: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; +./ + +UiImportList: UiImport ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; +./ + +UiImportList: UiImportList UiImport ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), + sym(1).UiImportList, sym(2).UiImport); +} break; +./ + +ImportId: MemberExpression ; + +UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->semicolonToken = loc(2); +} break; +./ + +UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->semicolonToken = loc(3); +} break; +./ + +UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->asToken = loc(3); + sym(1).UiImport->importIdToken = loc(4); + sym(1).UiImport->importId = sym(4).sval; + sym(1).UiImport->semicolonToken = loc(5); +} break; +./ + +UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->asToken = loc(2); + sym(1).UiImport->importIdToken = loc(3); + sym(1).UiImport->importId = sym(3).sval; + sym(1).UiImport->semicolonToken = loc(4); +} break; +./ + + +UiImportHead: T_IMPORT ImportId ; +/. +case $rule_number: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + QString text; + for (AST::UiQualifiedId *q = qualifiedId; q; q = q->next) { + text += q->name->asString(); + if (q->next) text += QLatin1String("."); + } + node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId); + node->fileNameToken = loc(2); + } + + sym(1).Node = node; + + if (! node) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id or a string literal"))); + + return false; // ### remove me + } +} break; +./ + +Empty: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +UiRootMember: UiObjectDefinition ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMember ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMemberList UiObjectMember ; +/. +case $rule_number: { + AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; +./ + +UiArrayMemberList: UiObjectDefinition ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ; +/. +case $rule_number: { + AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectInitializer: T_LBRACE T_RBRACE ; +/. +case $rule_number: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0); + node->lbraceToken = loc(1); + node->rbraceToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ; +/. +case $rule_number: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiObjectDefinition: UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiObjectDefinition ; + +UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; +/. +case $rule_number: { + AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); + node->colonToken = loc(2); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiQualifiedId T_COLON Block ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON EmptyStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON ExpressionStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON IfStatement ; --- ### do we really want if statement in a binding? +/.case $rule_number:./ + +/. +{ + AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiPropertyType: T_VAR ; +/. +case $rule_number: +./ +UiPropertyType: T_RESERVED_WORD ; +/. +case $rule_number: { + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); + break; +} +./ + +UiPropertyType: T_IDENTIFIER ; + +UiParameterListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +UiParameterListOpt: UiParameterList ; +/. +case $rule_number: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; +./ + +UiParameterList: UiPropertyType JsIdentifier ; +/. +case $rule_number: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ; +/. +case $rule_number: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); + node->commaToken = loc(2); + node->identifierToken = loc(4); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->parameters = sym(4).UiParameterList; + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY UiPropertyType T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY UiPropertyType T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, + sym(5).Expression); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->colonToken = loc(4); + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType T_IDENTIFIER T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; +./ + +UiObjectMember: VariableStatement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; +./ + +JsIdentifier: T_IDENTIFIER; + +JsIdentifier: T_PROPERTY ; +/. +case $rule_number: { + QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +JsIdentifier: T_SIGNAL ; +/. +case $rule_number: { + QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +JsIdentifier: T_READONLY ; +/. +case $rule_number: { + QString s = QLatin1String(QmlJSGrammar::spell[T_READONLY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +-------------------------------------------------------------------------------------------------------- +-- Expressions +-------------------------------------------------------------------------------------------------------- + +PrimaryExpression: T_THIS ; +/. +case $rule_number: { + AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); + node->thisToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: JsIdentifier ; +/. +case $rule_number: { + AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NULL ; +/. +case $rule_number: { + AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); + node->nullToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_TRUE ; +/. +case $rule_number: { + AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); + node->trueToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_FALSE ; +/. +case $rule_number: { + AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); + node->falseToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_MULTILINE_STRING_LITERAL ; +/.case $rule_number:./ + +PrimaryExpression: T_STRING_LITERAL ; +/. +case $rule_number: { + AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_DIVIDE_ ; +/: +#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(Lexer::NoPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; // ### remove me + } + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_DIVIDE_EQ ; +/: +#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(Lexer::EqualPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; + } + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET Elision T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; +./ + +-- PrimaryExpression: T_LBRACE T_RBRACE ; +-- /. +-- case $rule_number: { +-- sym(1).Node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); +-- } break; +-- ./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; +/. +case $rule_number: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + else + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); + node->lbraceToken = loc(1); + node->lbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ; +/. +case $rule_number: { + AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + node->lbraceToken = loc(1); + node->lbraceToken = loc(4); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LPAREN Expression T_RPAREN ; +/. +case $rule_number: { + AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); + node->lparenToken = loc(1); + node->rparenToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiQualifiedId: MemberExpression ; +/. +case $rule_number: { + if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, + QLatin1String("Ignored annotation"))); + + sym(1).Expression = mem->base; + } + + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { + sym(1).UiQualifiedId = qualifiedId; + } else { + sym(1).UiQualifiedId = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id"))); + + return false; // ### recover + } +} break; +./ + +ElementList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); +} break; +./ + +ElementList: Elision AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; +./ + +ElementList: ElementList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ElementList: ElementList T_COMMA Elision AssignmentExpression ; +/. +case $rule_number: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +Elision: T_COMMA ; +/. +case $rule_number: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; +} break; +./ + +Elision: Elision T_COMMA ; +/. +case $rule_number: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + node->commaToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +PropertyName: T_IDENTIFIER %prec REDUCE_HERE ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_SIGNAL ; +/.case $rule_number:./ + +PropertyName: T_PROPERTY ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_STRING_LITERAL ; +/. +case $rule_number: { + AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: ReservedIdentifier ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +ReservedIdentifier: T_BREAK ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CASE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CATCH ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CONTINUE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DEFAULT ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DELETE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DO ; +/. +case $rule_number: +./ +ReservedIdentifier: T_ELSE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FALSE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FINALLY ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FOR ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FUNCTION ; +/. +case $rule_number: +./ +ReservedIdentifier: T_IF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_IN ; +/. +case $rule_number: +./ +ReservedIdentifier: T_INSTANCEOF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_NEW ; +/. +case $rule_number: +./ +ReservedIdentifier: T_NULL ; +/. +case $rule_number: +./ +ReservedIdentifier: T_RETURN ; +/. +case $rule_number: +./ +ReservedIdentifier: T_SWITCH ; +/. +case $rule_number: +./ +ReservedIdentifier: T_THIS ; +/. +case $rule_number: +./ +ReservedIdentifier: T_THROW ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TRUE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TRY ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TYPEOF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_VAR ; +/. +case $rule_number: +./ +ReservedIdentifier: T_VOID ; +/. +case $rule_number: +./ +ReservedIdentifier: T_WHILE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CONST ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DEBUGGER ; +/. +case $rule_number: +./ +ReservedIdentifier: T_RESERVED_WORD ; +/. +case $rule_number: +./ +ReservedIdentifier: T_WITH ; +/. +case $rule_number: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; +./ + +PropertyIdentifier: JsIdentifier ; +PropertyIdentifier: ReservedIdentifier ; + +MemberExpression: PrimaryExpression ; +MemberExpression: FunctionExpression ; + +MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +MemberExpression: MemberExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); + node->newToken = loc(1); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + sym(1).Node = node; +} break; +./ + +NewExpression: MemberExpression ; + +NewExpression: T_NEW NewExpression ; +/. +case $rule_number: { + AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; +./ + +CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +ArgumentListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ArgumentListOpt: ArgumentList ; +/. +case $rule_number: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; +./ + +ArgumentList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); +} break; +./ + +ArgumentList: ArgumentList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +LeftHandSideExpression: NewExpression ; +LeftHandSideExpression: CallExpression ; +PostfixExpression: LeftHandSideExpression ; + +PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ; +/. +case $rule_number: { + AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; +/. +case $rule_number: { + AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +UnaryExpression: PostfixExpression ; + +UnaryExpression: T_DELETE UnaryExpression ; +/. +case $rule_number: { + AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_VOID UnaryExpression ; +/. +case $rule_number: { + AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TYPEOF UnaryExpression ; +/. +case $rule_number: { + AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TILDE UnaryExpression ; +/. +case $rule_number: { + AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_NOT UnaryExpression ; +/. +case $rule_number: { + AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: UnaryExpression ; + +MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mul, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Div, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mod, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AdditiveExpression: MultiplicativeExpression ; + +AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Add, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Sub, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: AdditiveExpression ; + +ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::LShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::RShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::URShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: ShiftExpression ; + +RelationalExpression: RelationalExpression T_LT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_GT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_LE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_GE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_IN ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::In, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: ShiftExpression ; + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: RelationalExpression ; + +EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: RelationalExpressionNotIn ; + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseANDExpression: EqualityExpression ; + +BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseANDExpressionNotIn: EqualityExpressionNotIn ; + +BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseXORExpression: BitwiseANDExpression ; + +BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ; + +BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseORExpression: BitwiseXORExpression ; + +BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ; + +BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalANDExpression: BitwiseORExpression ; + +LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ; + +LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalORExpression: LogicalANDExpression ; + +LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalORExpressionNotIn: LogicalANDExpressionNotIn ; + +LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ConditionalExpression: LogicalORExpression ; + +ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +ConditionalExpressionNotIn: LogicalORExpressionNotIn ; + +ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +AssignmentExpression: ConditionalExpression ; + +AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AssignmentExpressionNotIn: ConditionalExpressionNotIn ; + +AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AssignmentOperator: T_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::Assign; +} break; +./ + +AssignmentOperator: T_STAR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceMul; +} break; +./ + +AssignmentOperator: T_DIVIDE_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceDiv; +} break; +./ + +AssignmentOperator: T_REMAINDER_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceMod; +} break; +./ + +AssignmentOperator: T_PLUS_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceAdd; +} break; +./ + +AssignmentOperator: T_MINUS_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceSub; +} break; +./ + +AssignmentOperator: T_LT_LT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; +./ + +AssignmentOperator: T_GT_GT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; +./ + +AssignmentOperator: T_GT_GT_GT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; +./ + +AssignmentOperator: T_AND_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceAnd; +} break; +./ + +AssignmentOperator: T_XOR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceXor; +} break; +./ + +AssignmentOperator: T_OR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceOr; +} break; +./ + +Expression: AssignmentExpression ; + +Expression: Expression T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ExpressionOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ExpressionOpt: Expression ; + +ExpressionNotIn: AssignmentExpressionNotIn ; + +ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ExpressionNotInOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ExpressionNotInOpt: ExpressionNotIn ; + +Statement: Block ; +Statement: VariableStatement ; +Statement: EmptyStatement ; +Statement: ExpressionStatement ; +Statement: IfStatement ; +Statement: IterationStatement ; +Statement: ContinueStatement ; +Statement: BreakStatement ; +Statement: ReturnStatement ; +Statement: WithStatement ; +Statement: LabelledStatement ; +Statement: SwitchStatement ; +Statement: ThrowStatement ; +Statement: TryStatement ; +Statement: DebuggerStatement ; + + +Block: T_LBRACE StatementListOpt T_RBRACE ; +/. +case $rule_number: { + AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +StatementList: Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); +} break; +./ + +StatementList: StatementList Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); +} break; +./ + +StatementListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +StatementListOpt: StatementList ; +/. +case $rule_number: { + sym(1).Node = sym(1).StatementList->finish (); +} break; +./ + +VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ; +/. +case $rule_number: { + AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), + sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + node->declarationKindToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +VariableDeclarationKind: T_CONST ; +/. +case $rule_number: { + sym(1).ival = T_CONST; +} break; +./ + +VariableDeclarationKind: T_VAR ; +/. +case $rule_number: { + sym(1).ival = T_VAR; +} break; +./ + +VariableDeclarationList: VariableDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; +/. +case $rule_number: { + AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; +./ + +VariableDeclaration: JsIdentifier InitialiserOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +Initialiser: T_EQ AssignmentExpression ; +/. +case $rule_number: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; +./ + +InitialiserOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserOpt: Initialiser ; + +InitialiserNotIn: T_EQ AssignmentExpressionNotIn ; +/. +case $rule_number: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; +./ + +InitialiserNotInOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserNotInOpt: InitialiserNotIn ; + +EmptyStatement: T_SEMICOLON ; +/. +case $rule_number: { + AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; +./ + +ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ExpressionStatement: Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ; +/. +case $rule_number: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(5); + sym(1).Node = node; +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + + +IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ; +/. +case $rule_number: { + AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + node->doToken = loc(1); + node->whileToken = loc(3); + node->lparenToken = loc(4); + node->rparenToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->whileToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Expression, sym(9).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->firstSemicolonToken = loc(4); + node->secondSemicolonToken = loc(6); + node->rparenToken = loc(8); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), + sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(8).Expression, sym(10).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->firstSemicolonToken = loc(5); + node->secondSemicolonToken = loc(7); + node->rparenToken = loc(9); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->inToken = loc(4); + node->rparenToken = loc(6); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), + sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->inToken = loc(5); + node->rparenToken = loc(7); + sym(1).Node = node; +} break; +./ + +ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE T_SEMICOLON ; +/. +case $rule_number: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + node->continueToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK T_SEMICOLON ; +/. +case $rule_number: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); + node->breakToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ; +/. +case $rule_number: { + AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + node->returnToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->withToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ; +/. +case $rule_number: { + AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + node->switchToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(5); + sym(1).Node = node; +} break; +./ + +CaseClauses: CaseClause ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); +} break; +./ + +CaseClauses: CaseClauses CaseClause ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); +} break; +./ + +CaseClausesOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +CaseClausesOpt: CaseClauses ; +/. +case $rule_number: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; +./ + +CaseClause: T_CASE Expression T_COLON StatementListOpt ; +/. +case $rule_number: { + AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + node->caseToken = loc(1); + node->colonToken = loc(3); + sym(1).Node = node; +} break; +./ + +DefaultClause: T_DEFAULT T_COLON StatementListOpt ; +/. +case $rule_number: { + AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + node->defaultToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +LabelledStatement: T_SIGNAL T_COLON Statement ; +/.case $rule_number:./ + +LabelledStatement: T_PROPERTY T_COLON Statement ; +/. +case $rule_number: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +LabelledStatement: T_IDENTIFIER T_COLON Statement ; +/. +case $rule_number: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ThrowStatement: T_THROW Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + node->throwToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Catch ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Finally ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Catch Finally ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ; +/. +case $rule_number: { + AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); + node->catchToken = loc(1); + node->lparenToken = loc(2); + node->identifierToken = loc(3); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +Finally: T_FINALLY Block ; +/. +case $rule_number: { + AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; +./ + +DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +DebuggerStatement: T_DEBUGGER T_SEMICOLON ; +/. +case $rule_number: { + AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; +./ + +FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (sym(2).sval) + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; +./ + +FormalParameterList: JsIdentifier ; +/. +case $rule_number: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +FormalParameterList: FormalParameterList T_COMMA JsIdentifier ; +/. +case $rule_number: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + node->commaToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +FormalParameterListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FormalParameterListOpt: FormalParameterList ; +/. +case $rule_number: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; +./ + +FunctionBodyOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FunctionBodyOpt: FunctionBody ; + +FunctionBody: SourceElements ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; +./ + +Program: SourceElements ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; +./ + +SourceElements: SourceElement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); +} break; +./ + +SourceElements: SourceElements SourceElement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); +} break; +./ + +SourceElement: Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); +} break; +./ + +SourceElement: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); +} break; +./ + +IdentifierOpt: ; +/. +case $rule_number: { + sym(1).sval = 0; +} break; +./ + +IdentifierOpt: JsIdentifier ; + +PropertyNameAndValueListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +PropertyNameAndValueListOpt: PropertyNameAndValueList ; + +/. + } // switch + action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); + } // if + } while (action != 0); + + if (first_token == last_token) { + const int errorState = state_stack[tos]; + + // automatic insertion of `;' + if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QmlParser", "Missing `;'"); + //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); + + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + yytoken = T_SEMICOLON; + yylval = 0; + + action = errorState; + + goto _Lcheck_token; + } + + hadErrors = true; + + token_buffer[0].token = yytoken; + token_buffer[0].dval = yylval; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->dval(); + token_buffer[1].loc = yylloc = location(lexer); + + if (t_action(errorState, yytoken)) { + QString msg; + int token = token_buffer[0].token; + if (token < 0 || token >= TERMINAL_COUNT) + msg = qApp->translate("QmlParser", "Syntax error"); + else + msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + action = errorState; + goto _Lcheck_token; + } + + static int tokens[] = { + T_PLUS, + T_EQ, + + T_COMMA, + T_COLON, + T_SEMICOLON, + + T_RPAREN, T_RBRACKET, T_RBRACE, + + T_NUMERIC_LITERAL, + T_IDENTIFIER, + + T_LPAREN, T_LBRACKET, T_LBRACE, + + EOF_SYMBOL + }; + + for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { + int a = t_action(errorState, *tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = *tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + first_token = &token_buffer[0]; + last_token = &token_buffer[2]; + + action = errorState; + goto _Lcheck_token; + } + } + + for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || + tk == T_FEED_JS_SOURCE_ELEMENT) + continue; + + int a = t_action(errorState, tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + action = errorState; + goto _Lcheck_token; + } + } + + const QString msg = qApp->translate("QmlParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + +./ +/: +QT_QML_END_NAMESPACE + + + +#endif // QMLJSPARSER_P_H +:/ diff --git a/src/declarative/qml/parser/qmljsast.cpp b/src/declarative/qml/parser/qmljsast.cpp new file mode 100644 index 0000000..e80b05e --- /dev/null +++ b/src/declarative/qml/parser/qmljsast.cpp @@ -0,0 +1,955 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsast_p.h" + +#include "qmljsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { namespace AST { + +void Node::accept(Visitor *visitor) +{ + if (visitor->preVisit(this)) { + accept0(visitor); + } + visitor->postVisit(this); +} + +void Node::accept(Node *node, Visitor *visitor) +{ + if (node) + node->accept(visitor); +} + +ExpressionNode *Node::expressionCast() +{ + return 0; +} + +BinaryExpression *Node::binaryExpressionCast() +{ + return 0; +} + +Statement *Node::statementCast() +{ + return 0; +} + +UiObjectMember *Node::uiObjectMemberCast() +{ + return 0; +} + +ExpressionNode *ExpressionNode::expressionCast() +{ + return this; +} + +BinaryExpression *BinaryExpression::binaryExpressionCast() +{ + return this; +} + +Statement *Statement::statementCast() +{ + return this; +} + +UiObjectMember *UiObjectMember::uiObjectMemberCast() +{ + return this; +} + +void NestedExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + visitor->endVisit(this); +} + +void ThisExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void IdentifierExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NullExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void TrueLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void FalseLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void StringLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NumericLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void RegExpLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ArrayLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + accept(elision, visitor); + } + + visitor->endVisit(this); +} + +void ObjectLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(properties, visitor); + } + + visitor->endVisit(this); +} + +void ElementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (ElementList *it = this; it; it = it->next) { + accept(it->elision, visitor); + accept(it->expression, visitor); + } + } + + visitor->endVisit(this); +} + +void Elision::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + // ### + } + + visitor->endVisit(this); +} + +void PropertyNameAndValueList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (PropertyNameAndValueList *it = this; it; it = it->next) { + accept(it->name, visitor); + accept(it->value, visitor); + } + } + + visitor->endVisit(this); +} + +void IdentifierPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void StringLiteralPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NumericLiteralPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ArrayMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void FieldMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void NewMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(arguments, visitor); + } + + visitor->endVisit(this); +} + +void NewExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void CallExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(arguments, visitor); + } + + visitor->endVisit(this); +} + +void ArgumentList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (ArgumentList *it = this; it; it = it->next) { + accept(it->expression, visitor); + } + } + + visitor->endVisit(this); +} + +void PostIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void PostDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void DeleteExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void VoidExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TypeOfExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryPlusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryMinusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TildeExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void NotExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void BinaryExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(left, visitor); + accept(right, visitor); + } + + visitor->endVisit(this); +} + +void ConditionalExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(ok, visitor); + accept(ko, visitor); + } + + visitor->endVisit(this); +} + +void Expression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(left, visitor); + accept(right, visitor); + } + + visitor->endVisit(this); +} + +void Block::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void StatementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (StatementList *it = this; it; it = it->next) { + accept(it->statement, visitor); + } + } + + visitor->endVisit(this); +} + +void VariableStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declarations, visitor); + } + + visitor->endVisit(this); +} + +void VariableDeclarationList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (VariableDeclarationList *it = this; it; it = it->next) { + accept(it->declaration, visitor); + } + } + + visitor->endVisit(this); +} + +void VariableDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void EmptyStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ExpressionStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void IfStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(ok, visitor); + accept(ko, visitor); + } + + visitor->endVisit(this); +} + +void DoWhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void WhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(initialiser, visitor); + accept(condition, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declarations, visitor); + accept(condition, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(initialiser, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declaration, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ContinueStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void BreakStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ReturnStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void WithStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void SwitchStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(block, visitor); + } + + visitor->endVisit(this); +} + +void CaseBlock::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(clauses, visitor); + accept(defaultClause, visitor); + accept(moreClauses, visitor); + } + + visitor->endVisit(this); +} + +void CaseClauses::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (CaseClauses *it = this; it; it = it->next) { + accept(it->clause, visitor); + } + } + + visitor->endVisit(this); +} + +void CaseClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void DefaultClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void LabelledStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ThrowStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TryStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + accept(catchExpression, visitor); + accept(finallyExpression, visitor); + } + + visitor->endVisit(this); +} + +void Catch::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void Finally::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void FunctionDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + accept(body, visitor); + } + + visitor->endVisit(this); +} + +void FunctionExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + accept(body, visitor); + } + + visitor->endVisit(this); +} + +void FormalParameterList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + // ### + } + + visitor->endVisit(this); +} + +void FunctionBody::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + } + + visitor->endVisit(this); +} + +void Program::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + } + + visitor->endVisit(this); +} + +void SourceElements::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (SourceElements *it = this; it; it = it->next) { + accept(it->element, visitor); + } + } + + visitor->endVisit(this); +} + +void FunctionSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declaration, visitor); + } + + visitor->endVisit(this); +} + +void StatementSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void DebuggerStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void UiProgram::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(imports, visitor); + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiSignature::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + } + visitor->endVisit(this); +} + +void UiFormalList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiFormalList *it = this; it; it = it->next) { + accept(it->formal, visitor); + } + } + visitor->endVisit(this); +} + +void UiFormal::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} + +void UiPublicMember::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectDefinition::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedTypeNameId, visitor); + accept(initializer, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectInitializer::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(qualifiedTypeNameId, visitor); + accept(initializer, visitor); + } + + visitor->endVisit(this); +} + +void UiScriptBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void UiArrayBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectMemberList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiObjectMemberList *it = this; it; it = it->next) + accept(it->member, visitor); + } + + visitor->endVisit(this); +} + +void UiArrayMemberList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiArrayMemberList *it = this; it; it = it->next) + accept(it->member, visitor); + } + + visitor->endVisit(this); +} + +void UiQualifiedId::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void UiImport::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(importUri, visitor); + } + + visitor->endVisit(this); +} + +void UiImportList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(import, visitor); + accept(next, visitor); + } + + visitor->endVisit(this); +} + +void UiSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(sourceElement, visitor); + } + + visitor->endVisit(this); +} + +} } // namespace QmlJS::AST + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qmljsast_p.h b/src/declarative/qml/parser/qmljsast_p.h new file mode 100644 index 0000000..032fbb1 --- /dev/null +++ b/src/declarative/qml/parser/qmljsast_p.h @@ -0,0 +1,2678 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSAST_P_H +#define QMLJSAST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsastvisitor_p.h" +#include "qmljsglobal_p.h" + +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +#define QMLJS_DECLARE_AST_NODE(name) \ + enum { K = Kind_##name }; + +namespace QSOperator // ### rename +{ + +enum Op { + Add, + And, + InplaceAnd, + Assign, + BitAnd, + BitOr, + BitXor, + InplaceSub, + Div, + InplaceDiv, + Equal, + Ge, + Gt, + In, + InplaceAdd, + InstanceOf, + Le, + LShift, + InplaceLeftShift, + Lt, + Mod, + InplaceMod, + Mul, + InplaceMul, + NotEqual, + Or, + InplaceOr, + RShift, + InplaceRightShift, + StrictEqual, + StrictNotEqual, + Sub, + URShift, + InplaceURightShift, + InplaceXor +}; + +} // namespace QSOperator + +namespace QmlJS { +class NameId; +namespace AST { + +template <typename _T1, typename _T2> +_T1 cast(_T2 *ast) +{ + if (ast && ast->kind == static_cast<_T1>(0)->K) + return static_cast<_T1>(ast); + + return 0; +} + +class QML_PARSER_EXPORT Node +{ +public: + enum Kind { + Kind_Undefined, + + Kind_ArgumentList, + Kind_ArrayLiteral, + Kind_ArrayMemberExpression, + Kind_BinaryExpression, + Kind_Block, + Kind_BreakStatement, + Kind_CallExpression, + Kind_CaseBlock, + Kind_CaseClause, + Kind_CaseClauses, + Kind_Catch, + Kind_ConditionalExpression, + Kind_ContinueStatement, + Kind_DebuggerStatement, + Kind_DefaultClause, + Kind_DeleteExpression, + Kind_DoWhileStatement, + Kind_ElementList, + Kind_Elision, + Kind_EmptyStatement, + Kind_Expression, + Kind_ExpressionStatement, + Kind_FalseLiteral, + Kind_FieldMemberExpression, + Kind_Finally, + Kind_ForEachStatement, + Kind_ForStatement, + Kind_FormalParameterList, + Kind_FunctionBody, + Kind_FunctionDeclaration, + Kind_FunctionExpression, + Kind_FunctionSourceElement, + Kind_IdentifierExpression, + Kind_IdentifierPropertyName, + Kind_IfStatement, + Kind_LabelledStatement, + Kind_LocalForEachStatement, + Kind_LocalForStatement, + Kind_NewExpression, + Kind_NewMemberExpression, + Kind_NotExpression, + Kind_NullExpression, + Kind_NumericLiteral, + Kind_NumericLiteralPropertyName, + Kind_ObjectLiteral, + Kind_PostDecrementExpression, + Kind_PostIncrementExpression, + Kind_PreDecrementExpression, + Kind_PreIncrementExpression, + Kind_Program, + Kind_PropertyName, + Kind_PropertyNameAndValueList, + Kind_RegExpLiteral, + Kind_ReturnStatement, + Kind_SourceElement, + Kind_SourceElements, + Kind_StatementList, + Kind_StatementSourceElement, + Kind_StringLiteral, + Kind_StringLiteralPropertyName, + Kind_SwitchStatement, + Kind_ThisExpression, + Kind_ThrowStatement, + Kind_TildeExpression, + Kind_TrueLiteral, + Kind_TryStatement, + Kind_TypeOfExpression, + Kind_UnaryMinusExpression, + Kind_UnaryPlusExpression, + Kind_VariableDeclaration, + Kind_VariableDeclarationList, + Kind_VariableStatement, + Kind_VoidExpression, + Kind_WhileStatement, + Kind_WithStatement, + Kind_NestedExpression, + + Kind_UiArrayBinding, + Kind_UiImport, + Kind_UiImportList, + Kind_UiObjectBinding, + Kind_UiObjectDefinition, + Kind_UiObjectInitializer, + Kind_UiObjectMemberList, + Kind_UiArrayMemberList, + Kind_UiProgram, + Kind_UiParameterList, + Kind_UiPublicMember, + Kind_UiQualifiedId, + Kind_UiScriptBinding, + Kind_UiSourceElement, + Kind_UiFormal, + Kind_UiFormalList, + Kind_UiSignature + }; + + inline Node() + : kind(Kind_Undefined) {} + + virtual ~Node() {} + + virtual ExpressionNode *expressionCast(); + virtual BinaryExpression *binaryExpressionCast(); + virtual Statement *statementCast(); + virtual UiObjectMember *uiObjectMemberCast(); + + void accept(Visitor *visitor); + static void accept(Node *node, Visitor *visitor); + + inline static void acceptChild(Node *node, Visitor *visitor) + { return accept(node, visitor); } // ### remove + + virtual void accept0(Visitor *visitor) = 0; + +// attributes + int kind; +}; + +class QML_PARSER_EXPORT ExpressionNode: public Node +{ +public: + ExpressionNode() {} + virtual ~ExpressionNode() {} + + virtual ExpressionNode *expressionCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class QML_PARSER_EXPORT Statement: public Node +{ +public: + Statement() {} + virtual ~Statement() {} + + virtual Statement *statementCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class QML_PARSER_EXPORT UiFormal: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiFormal) + + UiFormal(NameId *name, NameId *alias = 0) + : name(name), alias(alias) + { } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + NameId *alias; + SourceLocation identifierToken; + SourceLocation asToken; + SourceLocation aliasToken; +}; + +class QML_PARSER_EXPORT UiFormalList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiFormalList) + + UiFormalList(UiFormal *formal) + : formal(formal), next(this) {} + + UiFormalList(UiFormalList *previous, UiFormal *formal) + : formal(formal) + { + next = previous->next; + previous->next = this; + } + + UiFormalList *finish() + { + UiFormalList *head = next; + next = 0; + return head; + } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + UiFormal *formal; + UiFormalList *next; +}; + +class QML_PARSER_EXPORT UiSignature: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiSignature) + + UiSignature(UiFormalList *formals = 0) + : formals(formals) + { } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceLocation lparenToken; + UiFormalList *formals; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT NestedExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NestedExpression) + + NestedExpression(ExpressionNode *expression) + : expression(expression) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lparenToken; } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + +// attributes + ExpressionNode *expression; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ThisExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(ThisExpression) + + ThisExpression() { kind = K; } + virtual ~ThisExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return thisToken; } + + virtual SourceLocation lastSourceLocation() const + { return thisToken; } + +// attributes + SourceLocation thisToken; +}; + +class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(IdentifierExpression) + + IdentifierExpression(NameId *n): + name (n) { kind = K; } + + virtual ~IdentifierExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return identifierToken; } + +// attributes + NameId *name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NullExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NullExpression) + + NullExpression() { kind = K; } + virtual ~NullExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return nullToken; } + + virtual SourceLocation lastSourceLocation() const + { return nullToken; } + +// attributes + SourceLocation nullToken; +}; + +class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(TrueLiteral) + + TrueLiteral() { kind = K; } + virtual ~TrueLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return trueToken; } + + virtual SourceLocation lastSourceLocation() const + { return trueToken; } + +// attributes + SourceLocation trueToken; +}; + +class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(FalseLiteral) + + FalseLiteral() { kind = K; } + virtual ~FalseLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return falseToken; } + + virtual SourceLocation lastSourceLocation() const + { return falseToken; } + +// attributes + SourceLocation falseToken; +}; + +class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NumericLiteral) + + NumericLiteral(double v): + value(v) { kind = K; } + virtual ~NumericLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + double value; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT StringLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(StringLiteral) + + StringLiteral(NameId *v): + value (v) { kind = K; } + + virtual ~StringLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + NameId *value; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(RegExpLiteral) + + RegExpLiteral(NameId *p, int f): + pattern (p), flags (f) { kind = K; } + + virtual ~RegExpLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + NameId *pattern; + int flags; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(ArrayLiteral) + + ArrayLiteral(Elision *e): + elements (0), elision (e) + { kind = K; } + + ArrayLiteral(ElementList *elts): + elements (elts), elision (0) + { kind = K; } + + ArrayLiteral(ElementList *elts, Elision *e): + elements (elts), elision (e) + { kind = K; } + + virtual ~ArrayLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbracketToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + +// attributes + ElementList *elements; + Elision *elision; + SourceLocation lbracketToken; + SourceLocation commaToken; + SourceLocation rbracketToken; +}; + +class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(ObjectLiteral) + + ObjectLiteral(): + properties (0) { kind = K; } + + ObjectLiteral(PropertyNameAndValueList *plist): + properties (plist) { kind = K; } + + virtual ~ObjectLiteral() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + PropertyNameAndValueList *properties; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT ElementList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(ElementList) + + ElementList(Elision *e, ExpressionNode *expr): + elision (e), expression (expr), next (this) + { kind = K; } + + ElementList(ElementList *previous, Elision *e, ExpressionNode *expr): + elision (e), expression (expr) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~ElementList() {} + + inline ElementList *finish () + { + ElementList *front = next; + next = 0; + return front; + } + + virtual void accept0(Visitor *visitor); + +// attributes + Elision *elision; + ExpressionNode *expression; + ElementList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT Elision: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(Elision) + + Elision(): + next (this) { kind = K; } + + Elision(Elision *previous) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~Elision() {} + + virtual void accept0(Visitor *visitor); + + inline Elision *finish () + { + Elision *front = next; + next = 0; + return front; + } + +// attributes + Elision *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PropertyNameAndValueList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(PropertyNameAndValueList) + + PropertyNameAndValueList(PropertyName *n, ExpressionNode *v): + name (n), value (v), next (this) + { kind = K; } + + PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v): + name (n), value (v) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~PropertyNameAndValueList() {} + + virtual void accept0(Visitor *visitor); + + inline PropertyNameAndValueList *finish () + { + PropertyNameAndValueList *front = next; + next = 0; + return front; + } + +// attributes + PropertyName *name; + ExpressionNode *value; + PropertyNameAndValueList *next; + SourceLocation colonToken; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PropertyName: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(PropertyName) + + PropertyName() { kind = K; } + virtual ~PropertyName() {} + +// attributes + SourceLocation propertyNameToken; +}; + +class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName +{ +public: + QMLJS_DECLARE_AST_NODE(IdentifierPropertyName) + + IdentifierPropertyName(NameId *n): + id (n) { kind = K; } + + virtual ~IdentifierPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *id; +}; + +class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName +{ +public: + QMLJS_DECLARE_AST_NODE(StringLiteralPropertyName) + + StringLiteralPropertyName(NameId *n): + id (n) { kind = K; } + virtual ~StringLiteralPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *id; +}; + +class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName +{ +public: + QMLJS_DECLARE_AST_NODE(NumericLiteralPropertyName) + + NumericLiteralPropertyName(double n): + id (n) { kind = K; } + virtual ~NumericLiteralPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + double id; +}; + +class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(ArrayMemberExpression) + + ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e): + base (b), expression (e) + { kind = K; } + + virtual ~ArrayMemberExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + +// attributes + ExpressionNode *base; + ExpressionNode *expression; + SourceLocation lbracketToken; + SourceLocation rbracketToken; +}; + +class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(FieldMemberExpression) + + FieldMemberExpression(ExpressionNode *b, NameId *n): + base (b), name (n) + { kind = K; } + + virtual ~FieldMemberExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return identifierToken; } + + // attributes + ExpressionNode *base; + NameId *name; + SourceLocation dotToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NewMemberExpression) + + NewMemberExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = K; } + + virtual ~NewMemberExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return newToken; } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + + // attributes + ExpressionNode *base; + ArgumentList *arguments; + SourceLocation newToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT NewExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NewExpression) + + NewExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~NewExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return newToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation newToken; +}; + +class QML_PARSER_EXPORT CallExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(CallExpression) + + CallExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = K; } + + virtual ~CallExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + +// attributes + ExpressionNode *base; + ArgumentList *arguments; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ArgumentList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(ArgumentList) + + ArgumentList(ExpressionNode *e): + expression (e), next (this) + { kind = K; } + + ArgumentList(ArgumentList *previous, ExpressionNode *e): + expression (e) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~ArgumentList() {} + + virtual void accept0(Visitor *visitor); + + inline ArgumentList *finish () + { + ArgumentList *front = next; + next = 0; + return front; + } + +// attributes + ExpressionNode *expression; + ArgumentList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(PostIncrementExpression) + + PostIncrementExpression(ExpressionNode *b): + base (b) { kind = K; } + + virtual ~PostIncrementExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return incrementToken; } + +// attributes + ExpressionNode *base; + SourceLocation incrementToken; +}; + +class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(PostDecrementExpression) + + PostDecrementExpression(ExpressionNode *b): + base (b) { kind = K; } + + virtual ~PostDecrementExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return decrementToken; } + +// attributes + ExpressionNode *base; + SourceLocation decrementToken; +}; + +class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(DeleteExpression) + + DeleteExpression(ExpressionNode *e): + expression (e) { kind = K; } + virtual ~DeleteExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return deleteToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation deleteToken; +}; + +class QML_PARSER_EXPORT VoidExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(VoidExpression) + + VoidExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~VoidExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return voidToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation voidToken; +}; + +class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(TypeOfExpression) + + TypeOfExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~TypeOfExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return typeofToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation typeofToken; +}; + +class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(PreIncrementExpression) + + PreIncrementExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~PreIncrementExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return incrementToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation incrementToken; +}; + +class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(PreDecrementExpression) + + PreDecrementExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~PreDecrementExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return decrementToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation decrementToken; +}; + +class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(UnaryPlusExpression) + + UnaryPlusExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~UnaryPlusExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return plusToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation plusToken; +}; + +class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(UnaryMinusExpression) + + UnaryMinusExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~UnaryMinusExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return minusToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation minusToken; +}; + +class QML_PARSER_EXPORT TildeExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(TildeExpression) + + TildeExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~TildeExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return tildeToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation tildeToken; +}; + +class QML_PARSER_EXPORT NotExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(NotExpression) + + NotExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~NotExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return notToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation notToken; +}; + +class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(BinaryExpression) + + BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r): + left (l), op (o), right (r) + { kind = K; } + + virtual ~BinaryExpression() {} + + virtual BinaryExpression *binaryExpressionCast(); + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return left->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return right->lastSourceLocation(); } + +// attributes + ExpressionNode *left; + int op; + ExpressionNode *right; + SourceLocation operatorToken; +}; + +class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(ConditionalExpression) + + ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f): + expression (e), ok (t), ko (f) + { kind = K; } + + virtual ~ConditionalExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return expression->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return ko->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + ExpressionNode *ok; + ExpressionNode *ko; + SourceLocation questionToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename +{ +public: + QMLJS_DECLARE_AST_NODE(Expression) + + Expression(ExpressionNode *l, ExpressionNode *r): + left (l), right (r) { kind = K; } + + virtual ~Expression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return left->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return right->lastSourceLocation(); } + +// attributes + ExpressionNode *left; + ExpressionNode *right; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT Block: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(Block) + + Block(StatementList *slist): + statements (slist) { kind = K; } + + virtual ~Block() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + + // attributes + StatementList *statements; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT StatementList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(StatementList) + + StatementList(Statement *stmt): + statement (stmt), next (this) + { kind = K; } + + StatementList(StatementList *previous, Statement *stmt): + statement (stmt) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~StatementList() {} + + virtual void accept0(Visitor *visitor); + + inline StatementList *finish () + { + StatementList *front = next; + next = 0; + return front; + } + +// attributes + Statement *statement; + StatementList *next; +}; + +class QML_PARSER_EXPORT VariableStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(VariableStatement) + + VariableStatement(VariableDeclarationList *vlist): + declarations (vlist) + { kind = K; } + + virtual ~VariableStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return declarationKindToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + VariableDeclarationList *declarations; + SourceLocation declarationKindToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT VariableDeclaration: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(VariableDeclaration) + + VariableDeclaration(NameId *n, ExpressionNode *e): + name (n), expression (e), readOnly(false) + { kind = K; } + + virtual ~VariableDeclaration() {} + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + ExpressionNode *expression; + bool readOnly; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT VariableDeclarationList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(VariableDeclarationList) + + VariableDeclarationList(VariableDeclaration *decl): + declaration (decl), next (this) + { kind = K; } + + VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl): + declaration (decl) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~VariableDeclarationList() {} + + virtual void accept0(Visitor *visitor); + + inline VariableDeclarationList *finish (bool readOnly) + { + VariableDeclarationList *front = next; + next = 0; + if (readOnly) { + VariableDeclarationList *vdl; + for (vdl = front; vdl != 0; vdl = vdl->next) + vdl->declaration->readOnly = true; + } + return front; + } + +// attributes + VariableDeclaration *declaration; + VariableDeclarationList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT EmptyStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(EmptyStatement) + + EmptyStatement() { kind = K; } + virtual ~EmptyStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return semicolonToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT ExpressionStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ExpressionStatement) + + ExpressionStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~ExpressionStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return expression->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + ExpressionNode *expression; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT IfStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(IfStatement) + + IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0): + expression (e), ok (t), ko (f) + { kind = K; } + + virtual ~IfStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return ifToken; } + + virtual SourceLocation lastSourceLocation() const + { + if (ko) + return ko->lastSourceLocation(); + + return ok->lastSourceLocation(); + } + +// attributes + ExpressionNode *expression; + Statement *ok; + Statement *ko; + SourceLocation ifToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation elseToken; +}; + +class QML_PARSER_EXPORT DoWhileStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(DoWhileStatement) + + DoWhileStatement(Statement *stmt, ExpressionNode *e): + statement (stmt), expression (e) + { kind = K; } + + virtual ~DoWhileStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return doToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + Statement *statement; + ExpressionNode *expression; + SourceLocation doToken; + SourceLocation whileToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT WhileStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(WhileStatement) + + WhileStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = K; } + + virtual ~WhileStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return whileToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + Statement *statement; + SourceLocation whileToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ForStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ForStatement) + + ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + initialiser (i), condition (c), expression (e), statement (stmt) + { kind = K; } + + virtual ~ForStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *initialiser; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation firstSemicolonToken; + SourceLocation secondSemicolonToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT LocalForStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(LocalForStatement) + + LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + declarations (vlist), condition (c), expression (e), statement (stmt) + { kind = K; } + + virtual ~LocalForStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + VariableDeclarationList *declarations; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation varToken; + SourceLocation firstSemicolonToken; + SourceLocation secondSemicolonToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ForEachStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ForEachStatement) + + ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt): + initialiser (i), expression (e), statement (stmt) + { kind = K; } + + virtual ~ForEachStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *initialiser; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation inToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT LocalForEachStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(LocalForEachStatement) + + LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt): + declaration (v), expression (e), statement (stmt) + { kind = K; } + + virtual ~LocalForEachStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + VariableDeclaration *declaration; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation varToken; + SourceLocation inToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ContinueStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ContinueStatement) + + ContinueStatement(NameId *l = 0): + label (l) { kind = K; } + + virtual ~ContinueStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return continueToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + NameId *label; + SourceLocation continueToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT BreakStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(BreakStatement) + + BreakStatement(NameId *l = 0): + label (l) { kind = K; } + + virtual ~BreakStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return breakToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + // attributes + NameId *label; + SourceLocation breakToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT ReturnStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ReturnStatement) + + ReturnStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~ReturnStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return returnToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + ExpressionNode *expression; + SourceLocation returnToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT WithStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(WithStatement) + + WithStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = K; } + + virtual ~WithStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return withToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + Statement *statement; + SourceLocation withToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT CaseBlock: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(CaseBlock) + + CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0): + clauses (c), defaultClause (d), moreClauses (r) + { kind = K; } + + virtual ~CaseBlock() {} + + virtual void accept0(Visitor *visitor); + +// attributes + CaseClauses *clauses; + DefaultClause *defaultClause; + CaseClauses *moreClauses; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT SwitchStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(SwitchStatement) + + SwitchStatement(ExpressionNode *e, CaseBlock *b): + expression (e), block (b) + { kind = K; } + + virtual ~SwitchStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return switchToken; } + + virtual SourceLocation lastSourceLocation() const + { return block->rbraceToken; } + +// attributes + ExpressionNode *expression; + CaseBlock *block; + SourceLocation switchToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT CaseClauses: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(CaseClauses) + + CaseClauses(CaseClause *c): + clause (c), next (this) + { kind = K; } + + CaseClauses(CaseClauses *previous, CaseClause *c): + clause (c) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~CaseClauses() {} + + virtual void accept0(Visitor *visitor); + + inline CaseClauses *finish () + { + CaseClauses *front = next; + next = 0; + return front; + } + +//attributes + CaseClause *clause; + CaseClauses *next; +}; + +class QML_PARSER_EXPORT CaseClause: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(CaseClause) + + CaseClause(ExpressionNode *e, StatementList *slist): + expression (e), statements (slist) + { kind = K; } + + virtual ~CaseClause() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + StatementList *statements; + SourceLocation caseToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT DefaultClause: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(DefaultClause) + + DefaultClause(StatementList *slist): + statements (slist) + { kind = K; } + + virtual ~DefaultClause() {} + + virtual void accept0(Visitor *visitor); + +// attributes + StatementList *statements; + SourceLocation defaultToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT LabelledStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(LabelledStatement) + + LabelledStatement(NameId *l, Statement *stmt): + label (l), statement (stmt) + { kind = K; } + + virtual ~LabelledStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + NameId *label; + Statement *statement; + SourceLocation identifierToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT ThrowStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(ThrowStatement) + + ThrowStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual ~ThrowStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return throwToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + // attributes + ExpressionNode *expression; + SourceLocation throwToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT Catch: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(Catch) + + Catch(NameId *n, Block *stmt): + name (n), statement (stmt) + { kind = K; } + + virtual ~Catch() {} + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + Block *statement; + SourceLocation catchToken; + SourceLocation lparenToken; + SourceLocation identifierToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT Finally: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(Finally) + + Finally(Block *stmt): + statement (stmt) + { kind = K; } + + virtual ~Finally() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Block *statement; + SourceLocation finallyToken; +}; + +class QML_PARSER_EXPORT TryStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(TryStatement) + + TryStatement(Statement *stmt, Catch *c, Finally *f): + statement (stmt), catchExpression (c), finallyExpression (f) + { kind = K; } + + TryStatement(Statement *stmt, Finally *f): + statement (stmt), catchExpression (0), finallyExpression (f) + { kind = K; } + + TryStatement(Statement *stmt, Catch *c): + statement (stmt), catchExpression (c), finallyExpression (0) + { kind = K; } + + virtual ~TryStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return tryToken; } + + virtual SourceLocation lastSourceLocation() const + { + if (finallyExpression) + return finallyExpression->statement->rbraceToken; + else if (catchExpression) + return catchExpression->statement->rbraceToken; + + return statement->lastSourceLocation(); + } + +// attributes + Statement *statement; + Catch *catchExpression; + Finally *finallyExpression; + SourceLocation tryToken; +}; + +class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode +{ +public: + QMLJS_DECLARE_AST_NODE(FunctionExpression) + + FunctionExpression(NameId *n, FormalParameterList *f, FunctionBody *b): + name (n), formals (f), body (b) + { kind = K; } + + virtual ~FunctionExpression() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return functionToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + NameId *name; + FormalParameterList *formals; + FunctionBody *body; + SourceLocation functionToken; + SourceLocation identifierToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression +{ +public: + QMLJS_DECLARE_AST_NODE(FunctionDeclaration) + + FunctionDeclaration(NameId *n, FormalParameterList *f, FunctionBody *b): + FunctionExpression(n, f, b) + { kind = K; } + + virtual ~FunctionDeclaration() {} + + virtual void accept0(Visitor *visitor); +}; + +class QML_PARSER_EXPORT FormalParameterList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(FormalParameterList) + + FormalParameterList(NameId *n): + name (n), next (this) + { kind = K; } + + FormalParameterList(FormalParameterList *previous, NameId *n): + name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~FormalParameterList() {} + + virtual void accept0(Visitor *visitor); + + inline FormalParameterList *finish () + { + FormalParameterList *front = next; + next = 0; + return front; + } + +// attributes + NameId *name; + FormalParameterList *next; + SourceLocation commaToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT FunctionBody: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(FunctionBody) + + FunctionBody(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual ~FunctionBody() {} + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT Program: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(Program) + + Program(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual ~Program() {} + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT SourceElements: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(SourceElements) + + SourceElements(SourceElement *elt): + element (elt), next (this) + { kind = K; } + + SourceElements(SourceElements *previous, SourceElement *elt): + element (elt) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~SourceElements() {} + + virtual void accept0(Visitor *visitor); + + inline SourceElements *finish () + { + SourceElements *front = next; + next = 0; + return front; + } + +// attributes + SourceElement *element; + SourceElements *next; +}; + +class QML_PARSER_EXPORT SourceElement: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(SourceElement) + + inline SourceElement() + { kind = K; } + + virtual ~SourceElement() {} +}; + +class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement +{ +public: + QMLJS_DECLARE_AST_NODE(FunctionSourceElement) + + FunctionSourceElement(FunctionDeclaration *f): + declaration (f) + { kind = K; } + + virtual ~FunctionSourceElement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + FunctionDeclaration *declaration; +}; + +class QML_PARSER_EXPORT StatementSourceElement: public SourceElement +{ +public: + QMLJS_DECLARE_AST_NODE(StatementSourceElement) + + StatementSourceElement(Statement *stmt): + statement (stmt) + { kind = K; } + + virtual ~StatementSourceElement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; +}; + +class QML_PARSER_EXPORT DebuggerStatement: public Statement +{ +public: + QMLJS_DECLARE_AST_NODE(DebuggerStatement) + + DebuggerStatement() + { kind = K; } + + virtual ~DebuggerStatement() {} + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return debuggerToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + SourceLocation debuggerToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiProgram: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiProgram) + + UiProgram(UiImportList *imports, UiObjectMemberList *members) + : imports(imports), members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiImportList *imports; + UiObjectMemberList *members; +}; + +class QML_PARSER_EXPORT UiQualifiedId: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiQualifiedId) + + UiQualifiedId(NameId *name) + : next(this), name(name) + { kind = K; } + + UiQualifiedId(UiQualifiedId *previous, NameId *name) + : name(name) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~UiQualifiedId() {} + + UiQualifiedId *finish() + { + UiQualifiedId *head = next; + next = 0; + return head; + } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *next; + NameId *name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiImport: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiImport) + + UiImport(NameId *fileName) + : fileName(fileName), importUri(0), importId(0) + { kind = K; } + + UiImport(UiQualifiedId *uri) + : fileName(0), importUri(uri), importId(0) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return importToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *fileName; + UiQualifiedId *importUri; + NameId *importId; + SourceLocation importToken; + SourceLocation fileNameToken; + SourceLocation versionToken; + SourceLocation asToken; + SourceLocation importIdToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiImportList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiImportList) + + UiImportList(UiImport *import) + : import(import), + next(this) + { kind = K; } + + UiImportList(UiImportList *previous, UiImport *import) + : import(import) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual SourceLocation firstSourceLocation() const + { + if (import) return import->firstSourceLocation(); + else return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + for (const UiImportList *it = this; it; it = it->next) + if (!it->next && it->import) + return it->import->lastSourceLocation(); + + return SourceLocation(); + } + + UiImportList *finish() + { + UiImportList *head = next; + next = 0; + return head; + } + + virtual void accept0(Visitor *visitor); + +// attributes + UiImport *import; + UiImportList *next; +}; + +class QML_PARSER_EXPORT UiObjectMember: public Node +{ +public: + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; + + virtual UiObjectMember *uiObjectMemberCast(); +}; + +class QML_PARSER_EXPORT UiObjectMemberList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiObjectMemberList) + + UiObjectMemberList(UiObjectMember *member) + : next(this), member(member) + { kind = K; } + + UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member) + : member(member) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + UiObjectMemberList *finish() + { + UiObjectMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiObjectMemberList *next; + UiObjectMember *member; +}; + +class QML_PARSER_EXPORT UiArrayMemberList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiArrayMemberList) + + UiArrayMemberList(UiObjectMember *member) + : next(this), member(member) + { kind = K; } + + UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member) + : member(member) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + UiArrayMemberList *finish() + { + UiArrayMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiArrayMemberList *next; + UiObjectMember *member; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT UiObjectInitializer: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiObjectInitializer) + + UiObjectInitializer(UiObjectMemberList *members) + : members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceLocation lbraceToken; + UiObjectMemberList *members; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT UiParameterList: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(UiParameterList) + + UiParameterList(NameId *t, NameId *n): + type (t), name (n), next (this) + { kind = K; } + + UiParameterList(UiParameterList *previous, NameId *t, NameId *n): + type (t), name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual ~UiParameterList() {} + + virtual void accept0(Visitor *) {} + + inline UiParameterList *finish () + { + UiParameterList *front = next; + next = 0; + return front; + } + +// attributes + NameId *type; + NameId *name; + UiParameterList *next; + SourceLocation commaToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiPublicMember) + + UiPublicMember(NameId *memberType, + NameId *name) + : type(Property), typeModifier(0), memberType(memberType), name(name), expression(0), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + UiPublicMember(NameId *memberType, + NameId *name, + ExpressionNode *expression) + : type(Property), typeModifier(0), memberType(memberType), name(name), expression(expression), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (defaultToken.isValid()) + return defaultToken; + else if (readonlyToken.isValid()) + return readonlyToken; + + return propertyToken; + } + + virtual SourceLocation lastSourceLocation() const + { + return semicolonToken; + } + + virtual void accept0(Visitor *visitor); + +// attributes + enum { Signal, Property } type; + NameId *typeModifier; + NameId *memberType; + NameId *name; + ExpressionNode *expression; + bool isDefaultMember; + bool isReadonlyMember; + UiParameterList *parameters; + SourceLocation defaultToken; + SourceLocation readonlyToken; + SourceLocation propertyToken; + SourceLocation typeModifierToken; + SourceLocation typeToken; + SourceLocation identifierToken; + SourceLocation colonToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiObjectDefinition) + + UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedTypeNameId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return initializer->rbraceToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; +}; + +class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiSourceElement) + + UiSourceElement(Node *sourceElement) + : sourceElement(sourceElement) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement)) + return funDecl->firstSourceLocation(); + else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement)) + return varStmt->firstSourceLocation(); + + return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement)) + return funDecl->lastSourceLocation(); + else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement)) + return varStmt->lastSourceLocation(); + + return SourceLocation(); + } + + + virtual void accept0(Visitor *visitor); + +// attributes + Node *sourceElement; +}; + +class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiObjectBinding) + + UiObjectBinding(UiQualifiedId *qualifiedId, + UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedId(qualifiedId), + qualifiedTypeNameId(qualifiedTypeNameId), + initializer(initializer) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return initializer->rbraceToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiScriptBinding) + + UiScriptBinding(UiQualifiedId *qualifiedId, + Statement *statement) + : qualifiedId(qualifiedId), + statement(statement) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + Statement *statement; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember +{ +public: + QMLJS_DECLARE_AST_NODE(UiArrayBinding) + + UiArrayBinding(UiQualifiedId *qualifiedId, + UiArrayMemberList *members) + : qualifiedId(qualifiedId), + members(members) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + UiArrayMemberList *members; + SourceLocation colonToken; + SourceLocation lbracketToken; + SourceLocation rbracketToken; +}; + +} } // namespace AST + + + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qmljsastfwd_p.h b/src/declarative/qml/parser/qmljsastfwd_p.h new file mode 100644 index 0000000..f571a2e --- /dev/null +++ b/src/declarative/qml/parser/qmljsastfwd_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSAST_FWD_P_H +#define QMLJSAST_FWD_P_H + +#include "qmljsglobal_p.h" + +#include <QtCore/qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { namespace AST { + +class SourceLocation +{ +public: + SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0) + : offset(offset), length(length), + startLine(line), startColumn(column) + { } + + bool isValid() const { return length != 0; } + + quint32 begin() const { return offset; } + quint32 end() const { return offset + length; } + +// attributes + // ### encode + quint32 offset; + quint32 length; + quint32 startLine; + quint32 startColumn; +}; + +class Visitor; +class Node; +class ExpressionNode; +class Statement; +class ThisExpression; +class IdentifierExpression; +class NullExpression; +class TrueLiteral; +class FalseLiteral; +class NumericLiteral; +class StringLiteral; +class RegExpLiteral; +class ArrayLiteral; +class ObjectLiteral; +class ElementList; +class Elision; +class PropertyNameAndValueList; +class PropertyName; +class IdentifierPropertyName; +class StringLiteralPropertyName; +class NumericLiteralPropertyName; +class ArrayMemberExpression; +class FieldMemberExpression; +class NewMemberExpression; +class NewExpression; +class CallExpression; +class ArgumentList; +class PostIncrementExpression; +class PostDecrementExpression; +class DeleteExpression; +class VoidExpression; +class TypeOfExpression; +class PreIncrementExpression; +class PreDecrementExpression; +class UnaryPlusExpression; +class UnaryMinusExpression; +class TildeExpression; +class NotExpression; +class BinaryExpression; +class ConditionalExpression; +class Expression; // ### rename +class Block; +class StatementList; +class VariableStatement; +class VariableDeclarationList; +class VariableDeclaration; +class EmptyStatement; +class ExpressionStatement; +class IfStatement; +class DoWhileStatement; +class WhileStatement; +class ForStatement; +class LocalForStatement; +class ForEachStatement; +class LocalForEachStatement; +class ContinueStatement; +class BreakStatement; +class ReturnStatement; +class WithStatement; +class SwitchStatement; +class CaseBlock; +class CaseClauses; +class CaseClause; +class DefaultClause; +class LabelledStatement; +class ThrowStatement; +class TryStatement; +class Catch; +class Finally; +class FunctionDeclaration; +class FunctionExpression; +class FormalParameterList; +class FunctionBody; +class Program; +class SourceElements; +class SourceElement; +class FunctionSourceElement; +class StatementSourceElement; +class DebuggerStatement; +class NestedExpression; + +// ui elements +class UiProgram; +class UiImportList; +class UiImport; +class UiPublicMember; +class UiObjectDefinition; +class UiObjectInitializer; +class UiObjectBinding; +class UiScriptBinding; +class UiSourceElement; +class UiArrayBinding; +class UiObjectMember; +class UiObjectMemberList; +class UiArrayMemberList; +class UiQualifiedId; +class UiFormalList; +class UiFormal; +class UiSignature; + +} } // namespace AST + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qmljsastvisitor.cpp b/src/declarative/qml/parser/qmljsastvisitor.cpp new file mode 100644 index 0000000..1290c89 --- /dev/null +++ b/src/declarative/qml/parser/qmljsastvisitor.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { namespace AST { + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +} } // namespace QmlJS::AST + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/parser/qmljsastvisitor_p.h b/src/declarative/qml/parser/qmljsastvisitor_p.h new file mode 100644 index 0000000..1b50bcc --- /dev/null +++ b/src/declarative/qml/parser/qmljsastvisitor_p.h @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSASTVISITOR_P_H +#define QMLJSASTVISITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsastfwd_p.h" +#include "qmljsglobal_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { namespace AST { + +class QML_PARSER_EXPORT Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual bool preVisit(Node *) { return true; } + virtual void postVisit(Node *) {} + + // Ui + virtual bool visit(UiProgram *) { return true; } + virtual bool visit(UiImportList *) { return true; } + virtual bool visit(UiImport *) { return true; } + virtual bool visit(UiPublicMember *) { return true; } + virtual bool visit(UiSourceElement *) { return true; } + virtual bool visit(UiObjectDefinition *) { return true; } + virtual bool visit(UiObjectInitializer *) { return true; } + virtual bool visit(UiObjectBinding *) { return true; } + virtual bool visit(UiScriptBinding *) { return true; } + virtual bool visit(UiArrayBinding *) { return true; } + virtual bool visit(UiObjectMemberList *) { return true; } + virtual bool visit(UiArrayMemberList *) { return true; } + virtual bool visit(UiQualifiedId *) { return true; } + virtual bool visit(UiSignature *) { return true; } + virtual bool visit(UiFormalList *) { return true; } + virtual bool visit(UiFormal *) { return true; } + + virtual void endVisit(UiProgram *) {} + virtual void endVisit(UiImportList *) {} + virtual void endVisit(UiImport *) {} + virtual void endVisit(UiPublicMember *) {} + virtual void endVisit(UiSourceElement *) {} + virtual void endVisit(UiObjectDefinition *) {} + virtual void endVisit(UiObjectInitializer *) {} + virtual void endVisit(UiObjectBinding *) {} + virtual void endVisit(UiScriptBinding *) {} + virtual void endVisit(UiArrayBinding *) {} + virtual void endVisit(UiObjectMemberList *) {} + virtual void endVisit(UiArrayMemberList *) {} + virtual void endVisit(UiQualifiedId *) {} + virtual void endVisit(UiSignature *) {} + virtual void endVisit(UiFormalList *) {} + virtual void endVisit(UiFormal *) {} + + // QmlJS + virtual bool visit(ThisExpression *) { return true; } + virtual void endVisit(ThisExpression *) {} + + virtual bool visit(IdentifierExpression *) { return true; } + virtual void endVisit(IdentifierExpression *) {} + + virtual bool visit(NullExpression *) { return true; } + virtual void endVisit(NullExpression *) {} + + virtual bool visit(TrueLiteral *) { return true; } + virtual void endVisit(TrueLiteral *) {} + + virtual bool visit(FalseLiteral *) { return true; } + virtual void endVisit(FalseLiteral *) {} + + virtual bool visit(StringLiteral *) { return true; } + virtual void endVisit(StringLiteral *) {} + + virtual bool visit(NumericLiteral *) { return true; } + virtual void endVisit(NumericLiteral *) {} + + virtual bool visit(RegExpLiteral *) { return true; } + virtual void endVisit(RegExpLiteral *) {} + + virtual bool visit(ArrayLiteral *) { return true; } + virtual void endVisit(ArrayLiteral *) {} + + virtual bool visit(ObjectLiteral *) { return true; } + virtual void endVisit(ObjectLiteral *) {} + + virtual bool visit(ElementList *) { return true; } + virtual void endVisit(ElementList *) {} + + virtual bool visit(Elision *) { return true; } + virtual void endVisit(Elision *) {} + + virtual bool visit(PropertyNameAndValueList *) { return true; } + virtual void endVisit(PropertyNameAndValueList *) {} + + virtual bool visit(NestedExpression *) { return true; } + virtual void endVisit(NestedExpression *) {} + + virtual bool visit(IdentifierPropertyName *) { return true; } + virtual void endVisit(IdentifierPropertyName *) {} + + virtual bool visit(StringLiteralPropertyName *) { return true; } + virtual void endVisit(StringLiteralPropertyName *) {} + + virtual bool visit(NumericLiteralPropertyName *) { return true; } + virtual void endVisit(NumericLiteralPropertyName *) {} + + virtual bool visit(ArrayMemberExpression *) { return true; } + virtual void endVisit(ArrayMemberExpression *) {} + + virtual bool visit(FieldMemberExpression *) { return true; } + virtual void endVisit(FieldMemberExpression *) {} + + virtual bool visit(NewMemberExpression *) { return true; } + virtual void endVisit(NewMemberExpression *) {} + + virtual bool visit(NewExpression *) { return true; } + virtual void endVisit(NewExpression *) {} + + virtual bool visit(CallExpression *) { return true; } + virtual void endVisit(CallExpression *) {} + + virtual bool visit(ArgumentList *) { return true; } + virtual void endVisit(ArgumentList *) {} + + virtual bool visit(PostIncrementExpression *) { return true; } + virtual void endVisit(PostIncrementExpression *) {} + + virtual bool visit(PostDecrementExpression *) { return true; } + virtual void endVisit(PostDecrementExpression *) {} + + virtual bool visit(DeleteExpression *) { return true; } + virtual void endVisit(DeleteExpression *) {} + + virtual bool visit(VoidExpression *) { return true; } + virtual void endVisit(VoidExpression *) {} + + virtual bool visit(TypeOfExpression *) { return true; } + virtual void endVisit(TypeOfExpression *) {} + + virtual bool visit(PreIncrementExpression *) { return true; } + virtual void endVisit(PreIncrementExpression *) {} + + virtual bool visit(PreDecrementExpression *) { return true; } + virtual void endVisit(PreDecrementExpression *) {} + + virtual bool visit(UnaryPlusExpression *) { return true; } + virtual void endVisit(UnaryPlusExpression *) {} + + virtual bool visit(UnaryMinusExpression *) { return true; } + virtual void endVisit(UnaryMinusExpression *) {} + + virtual bool visit(TildeExpression *) { return true; } + virtual void endVisit(TildeExpression *) {} + + virtual bool visit(NotExpression *) { return true; } + virtual void endVisit(NotExpression *) {} + + virtual bool visit(BinaryExpression *) { return true; } + virtual void endVisit(BinaryExpression *) {} + + virtual bool visit(ConditionalExpression *) { return true; } + virtual void endVisit(ConditionalExpression *) {} + + virtual bool visit(Expression *) { return true; } + virtual void endVisit(Expression *) {} + + virtual bool visit(Block *) { return true; } + virtual void endVisit(Block *) {} + + virtual bool visit(StatementList *) { return true; } + virtual void endVisit(StatementList *) {} + + virtual bool visit(VariableStatement *) { return true; } + virtual void endVisit(VariableStatement *) {} + + virtual bool visit(VariableDeclarationList *) { return true; } + virtual void endVisit(VariableDeclarationList *) {} + + virtual bool visit(VariableDeclaration *) { return true; } + virtual void endVisit(VariableDeclaration *) {} + + virtual bool visit(EmptyStatement *) { return true; } + virtual void endVisit(EmptyStatement *) {} + + virtual bool visit(ExpressionStatement *) { return true; } + virtual void endVisit(ExpressionStatement *) {} + + virtual bool visit(IfStatement *) { return true; } + virtual void endVisit(IfStatement *) {} + + virtual bool visit(DoWhileStatement *) { return true; } + virtual void endVisit(DoWhileStatement *) {} + + virtual bool visit(WhileStatement *) { return true; } + virtual void endVisit(WhileStatement *) {} + + virtual bool visit(ForStatement *) { return true; } + virtual void endVisit(ForStatement *) {} + + virtual bool visit(LocalForStatement *) { return true; } + virtual void endVisit(LocalForStatement *) {} + + virtual bool visit(ForEachStatement *) { return true; } + virtual void endVisit(ForEachStatement *) {} + + virtual bool visit(LocalForEachStatement *) { return true; } + virtual void endVisit(LocalForEachStatement *) {} + + virtual bool visit(ContinueStatement *) { return true; } + virtual void endVisit(ContinueStatement *) {} + + virtual bool visit(BreakStatement *) { return true; } + virtual void endVisit(BreakStatement *) {} + + virtual bool visit(ReturnStatement *) { return true; } + virtual void endVisit(ReturnStatement *) {} + + virtual bool visit(WithStatement *) { return true; } + virtual void endVisit(WithStatement *) {} + + virtual bool visit(SwitchStatement *) { return true; } + virtual void endVisit(SwitchStatement *) {} + + virtual bool visit(CaseBlock *) { return true; } + virtual void endVisit(CaseBlock *) {} + + virtual bool visit(CaseClauses *) { return true; } + virtual void endVisit(CaseClauses *) {} + + virtual bool visit(CaseClause *) { return true; } + virtual void endVisit(CaseClause *) {} + + virtual bool visit(DefaultClause *) { return true; } + virtual void endVisit(DefaultClause *) {} + + virtual bool visit(LabelledStatement *) { return true; } + virtual void endVisit(LabelledStatement *) {} + + virtual bool visit(ThrowStatement *) { return true; } + virtual void endVisit(ThrowStatement *) {} + + virtual bool visit(TryStatement *) { return true; } + virtual void endVisit(TryStatement *) {} + + virtual bool visit(Catch *) { return true; } + virtual void endVisit(Catch *) {} + + virtual bool visit(Finally *) { return true; } + virtual void endVisit(Finally *) {} + + virtual bool visit(FunctionDeclaration *) { return true; } + virtual void endVisit(FunctionDeclaration *) {} + + virtual bool visit(FunctionExpression *) { return true; } + virtual void endVisit(FunctionExpression *) {} + + virtual bool visit(FormalParameterList *) { return true; } + virtual void endVisit(FormalParameterList *) {} + + virtual bool visit(FunctionBody *) { return true; } + virtual void endVisit(FunctionBody *) {} + + virtual bool visit(Program *) { return true; } + virtual void endVisit(Program *) {} + + virtual bool visit(SourceElements *) { return true; } + virtual void endVisit(SourceElements *) {} + + virtual bool visit(FunctionSourceElement *) { return true; } + virtual void endVisit(FunctionSourceElement *) {} + + virtual bool visit(StatementSourceElement *) { return true; } + virtual void endVisit(StatementSourceElement *) {} + + virtual bool visit(DebuggerStatement *) { return true; } + virtual void endVisit(DebuggerStatement *) {} +}; + +} } // namespace AST + +QT_QML_END_NAMESPACE + +#endif // QMLJSASTVISITOR_P_H diff --git a/src/declarative/qml/parser/qmljsengine_p.cpp b/src/declarative/qml/parser/qmljsengine_p.cpp new file mode 100644 index 0000000..b8ecd18 --- /dev/null +++ b/src/declarative/qml/parser/qmljsengine_p.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsengine_p.h" + +#include "qmljsglobal_p.h" +#include "qmljsnodepool_p.h" + +#include <qnumeric.h> +#include <QHash> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +uint qHash(const QmlJS::NameId &id) +{ return qHash(id.asString()); } + +QString numberToString(double value) +{ return QString::number(value); } + +int Ecma::RegExp::flagFromChar(const QChar &ch) +{ + static QHash<QChar, int> flagsHash; + if (flagsHash.isEmpty()) { + flagsHash[QLatin1Char('g')] = Global; + flagsHash[QLatin1Char('i')] = IgnoreCase; + flagsHash[QLatin1Char('m')] = Multiline; + } + QHash<QChar, int>::const_iterator it; + it = flagsHash.constFind(ch); + if (it == flagsHash.constEnd()) + return 0; + return it.value(); +} + +QString Ecma::RegExp::flagsToString(int flags) +{ + QString result; + if (flags & Global) + result += QLatin1Char('g'); + if (flags & IgnoreCase) + result += QLatin1Char('i'); + if (flags & Multiline) + result += QLatin1Char('m'); + return result; +} + +NodePool::NodePool(const QString &fileName, Engine *engine) + : m_fileName(fileName), m_engine(engine) +{ + m_engine->setNodePool(this); +} + +NodePool::~NodePool() +{ +} + +Code *NodePool::createCompiledCode(AST::Node *, CompilationUnit &) +{ + Q_ASSERT(0); + return 0; +} + +static int toDigit(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'a') && (c <= 'z')) + return 10 + c - 'a'; + else if ((c >= 'A') && (c <= 'Z')) + return 10 + c - 'A'; + return -1; +} + +double integerFromString(const char *buf, int size, int radix) +{ + if (size == 0) + return qSNaN(); + + double sign = 1.0; + int i = 0; + if (buf[0] == '+') { + ++i; + } else if (buf[0] == '-') { + sign = -1.0; + ++i; + } + + if (((size-i) >= 2) && (buf[i] == '0')) { + if (((buf[i+1] == 'x') || (buf[i+1] == 'X')) + && (radix < 34)) { + if ((radix != 0) && (radix != 16)) + return 0; + radix = 16; + i += 2; + } else { + if (radix == 0) { + radix = 8; + ++i; + } + } + } else if (radix == 0) { + radix = 10; + } + + int j = i; + for ( ; i < size; ++i) { + int d = toDigit(buf[i]); + if ((d == -1) || (d >= radix)) + break; + } + double result; + if (j == i) { + if (!qstrcmp(buf, "Infinity")) + result = qInf(); + else + result = qSNaN(); + } else { + result = 0; + double multiplier = 1; + for (--i ; i >= j; --i, multiplier *= radix) + result += toDigit(buf[i]) * multiplier; + } + result *= sign; + return result; +} + +double integerFromString(const QString &str, int radix) +{ + QByteArray ba = str.trimmed().toLatin1(); + return integerFromString(ba.constData(), ba.size(), radix); +} + + +Engine::Engine() + : _lexer(0), _nodePool(0) +{ } + +Engine::~Engine() +{ } + +QSet<NameId> Engine::literals() const +{ return _literals; } + +void Engine::addComment(int pos, int len, int line, int col) +{ if (len > 0) _comments.append(QmlJS::AST::SourceLocation(pos, len, line, col)); } + +QList<QmlJS::AST::SourceLocation> Engine::comments() const +{ return _comments; } + +NameId *Engine::intern(const QChar *u, int s) +{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); } + +QString Engine::toString(NameId *id) +{ return id->asString(); } + +Lexer *Engine::lexer() const +{ return _lexer; } + +void Engine::setLexer(Lexer *lexer) +{ _lexer = lexer; } + +NodePool *Engine::nodePool() const +{ return _nodePool; } + +void Engine::setNodePool(NodePool *nodePool) +{ _nodePool = nodePool; } + + + +} // end of namespace QmlJS + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/parser/qmljsengine_p.h b/src/declarative/qml/parser/qmljsengine_p.h new file mode 100644 index 0000000..2c15af3 --- /dev/null +++ b/src/declarative/qml/parser/qmljsengine_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSENGINE_P_H +#define QMLJSENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsglobal_p.h" +#include "qmljsastfwd_p.h" + +#include <QString> +#include <QSet> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { +class QML_PARSER_EXPORT NameId +{ + QString _text; + +public: + NameId(const QChar *u, int s) + : _text(u, s) + { } + + const QString asString() const + { return _text; } + + bool operator == (const NameId &other) const + { return _text == other._text; } + + bool operator != (const NameId &other) const + { return _text != other._text; } + + bool operator < (const NameId &other) const + { return _text < other._text; } +}; + +uint qHash(const QmlJS::NameId &id); + +} // end of namespace QmlJS + +#if defined(Q_CC_MSVC) && _MSC_VER <= 1300 +//this ensures that code outside QmlJS can use the hash function +//it also a workaround for some compilers +inline uint qHash(const QmlJS::NameId &nameId) { return QmlJS::qHash(nameId); } +#endif + +namespace QmlJS { + +class Lexer; +class NodePool; + +namespace Ecma { + +class QML_PARSER_EXPORT RegExp +{ +public: + enum RegExpFlag { + Global = 0x01, + IgnoreCase = 0x02, + Multiline = 0x04 + }; + +public: + static int flagFromChar(const QChar &); + static QString flagsToString(int flags); +}; + +} // end of namespace Ecma + +class QML_PARSER_EXPORT DiagnosticMessage +{ +public: + enum Kind { Warning, Error }; + + DiagnosticMessage() + : kind(Error) {} + + DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) + : kind(kind), loc(loc), message(message) {} + + bool isWarning() const + { return kind == Warning; } + + bool isError() const + { return kind == Error; } + + Kind kind; + AST::SourceLocation loc; + QString message; +}; + +class QML_PARSER_EXPORT Engine +{ + Lexer *_lexer; + NodePool *_nodePool; + QSet<NameId> _literals; + QList<QmlJS::AST::SourceLocation> _comments; + +public: + Engine(); + ~Engine(); + + QSet<NameId> literals() const; + + void addComment(int pos, int len, int line, int col); + QList<QmlJS::AST::SourceLocation> comments() const; + + NameId *intern(const QChar *u, int s); + + static QString toString(NameId *id); + + Lexer *lexer() const; + void setLexer(Lexer *lexer); + + NodePool *nodePool() const; + void setNodePool(NodePool *nodePool); +}; + +} // end of namespace QmlJS + +QT_QML_END_NAMESPACE + +#endif // QMLJSENGINE_P_H diff --git a/src/declarative/qml/parser/qmljsglobal_p.h b/src/declarative/qml/parser/qmljsglobal_p.h new file mode 100644 index 0000000..49e50cf --- /dev/null +++ b/src/declarative/qml/parser/qmljsglobal_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QMLJSGLOBAL_P_H +#define QMLJSGLOBAL_P_H + +#include <QtCore/qglobal.h> + +#ifdef QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE + +# ifdef QMLJS_BUILD_DIR +# define QML_PARSER_EXPORT Q_DECL_EXPORT +# elif QML_BUILD_STATIC_LIB +# define QML_PARSER_EXPORT +# else +# define QML_PARSER_EXPORT Q_DECL_IMPORT +# endif // QMLJS_BUILD_DIR + +#else // !QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE QT_END_NAMESPACE +# define QML_PARSER_EXPORT +#endif // QT_CREATOR + +#endif // QMLJSGLOBAL_P_H diff --git a/src/declarative/qml/parser/qmljsgrammar.cpp b/src/declarative/qml/parser/qmljsgrammar.cpp new file mode 100644 index 0000000..b416959 --- /dev/null +++ b/src/declarative/qml/parser/qmljsgrammar.cpp @@ -0,0 +1,939 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! +#include "qmljsgrammar_p.h" + +QT_BEGIN_NAMESPACE + +const char *const QmlJSGrammar::spell [] = { + "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue", + "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===", + "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier", + "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=", + "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=", + "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return", + ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch", + "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", + "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public", + "import", "as", 0, 0, 0, 0, 0, 0, 0, 0}; + +const short QmlJSGrammar::lhs [] = { + 100, 100, 100, 100, 100, 100, 101, 107, 107, 110, + 110, 112, 111, 111, 111, 111, 111, 111, 111, 111, + 114, 109, 108, 117, 117, 118, 118, 119, 119, 116, + 105, 105, 105, 105, 105, 105, 105, 125, 125, 125, + 126, 126, 127, 127, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 115, 115, 115, 115, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 120, 132, 132, 132, 132, 131, + 131, 134, 134, 136, 136, 136, 136, 136, 136, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 138, 138, 113, 113, 113, 113, 113, 141, 141, 142, + 142, 142, 142, 140, 140, 143, 143, 144, 144, 145, + 145, 145, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 147, 147, 147, 147, 148, 148, 148, 149, + 149, 149, 149, 150, 150, 150, 150, 150, 150, 150, + 151, 151, 151, 151, 151, 151, 152, 152, 152, 152, + 152, 153, 153, 153, 153, 153, 154, 154, 155, 155, + 156, 156, 157, 157, 158, 158, 159, 159, 160, 160, + 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, + 135, 135, 166, 166, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 103, 103, 168, 168, + 169, 169, 170, 170, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 121, + 182, 182, 181, 181, 129, 129, 183, 183, 184, 184, + 186, 186, 185, 187, 190, 188, 188, 191, 189, 189, + 122, 123, 123, 124, 124, 171, 171, 171, 171, 171, + 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, + 174, 174, 175, 177, 192, 192, 195, 195, 193, 193, + 196, 194, 176, 176, 176, 178, 178, 179, 179, 179, + 197, 198, 180, 180, 128, 139, 202, 202, 199, 199, + 200, 200, 203, 106, 204, 204, 104, 104, 201, 201, + 133, 133, 205}; + +const short QmlJSGrammar::rhs [] = { + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 2, 1, 2, 2, 3, 3, 5, 5, 4, 4, + 2, 0, 1, 1, 2, 1, 3, 2, 3, 2, + 1, 5, 4, 3, 3, 3, 3, 1, 1, 1, + 0, 1, 2, 4, 6, 6, 3, 3, 7, 7, + 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, + 5, 3, 4, 3, 1, 1, 2, 3, 4, 1, + 2, 3, 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 3, 5, 1, 2, 4, + 4, 4, 3, 0, 1, 1, 3, 1, 1, 1, + 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 1, 3, 3, 3, 1, 3, 3, 1, + 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 3, 1, 3, 3, 3, + 3, 1, 3, 3, 3, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 5, 1, 5, + 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 0, 1, + 1, 3, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 2, 0, 1, 3, 3, 1, 1, 1, 3, + 1, 3, 2, 2, 2, 0, 1, 2, 0, 1, + 1, 2, 2, 7, 5, 7, 7, 5, 9, 10, + 7, 8, 2, 2, 3, 3, 2, 2, 3, 3, + 3, 3, 5, 5, 3, 5, 1, 2, 0, 1, + 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, + 5, 2, 2, 2, 8, 8, 1, 3, 0, 1, + 0, 1, 1, 1, 1, 2, 1, 1, 0, 1, + 0, 1, 2}; + +const short QmlJSGrammar::action_default [] = { + 0, 0, 0, 0, 0, 0, 22, 0, 170, 237, + 201, 209, 205, 149, 221, 197, 3, 134, 68, 150, + 213, 217, 138, 167, 148, 153, 133, 187, 174, 0, + 75, 76, 71, 339, 63, 341, 0, 0, 0, 0, + 73, 0, 0, 69, 72, 0, 0, 64, 66, 65, + 74, 67, 0, 70, 0, 0, 163, 0, 0, 150, + 169, 152, 151, 0, 0, 0, 165, 166, 164, 168, + 0, 198, 0, 0, 0, 0, 188, 0, 0, 0, + 0, 0, 0, 178, 0, 0, 0, 172, 173, 171, + 176, 180, 179, 177, 175, 190, 189, 191, 0, 206, + 0, 202, 0, 0, 144, 131, 143, 132, 100, 101, + 102, 127, 103, 128, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 129, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 130, 0, + 0, 142, 238, 145, 0, 146, 0, 147, 141, 0, + 234, 227, 225, 232, 233, 231, 230, 236, 229, 228, + 226, 235, 222, 0, 210, 0, 0, 214, 0, 0, + 218, 0, 0, 144, 136, 0, 135, 0, 140, 154, + 0, 340, 329, 330, 0, 327, 0, 328, 0, 331, + 245, 252, 251, 259, 247, 0, 248, 332, 0, 338, + 249, 250, 255, 253, 335, 333, 337, 256, 0, 267, + 0, 0, 0, 0, 339, 63, 0, 341, 64, 239, + 281, 65, 0, 0, 0, 268, 0, 0, 257, 258, + 0, 246, 254, 282, 283, 326, 336, 0, 297, 298, + 299, 300, 0, 293, 294, 295, 296, 323, 324, 0, + 0, 0, 0, 0, 286, 287, 243, 241, 203, 211, + 207, 223, 199, 244, 0, 150, 215, 219, 192, 181, + 0, 0, 200, 0, 0, 0, 0, 193, 0, 0, + 0, 0, 0, 185, 183, 186, 184, 182, 195, 194, + 196, 0, 208, 0, 204, 0, 242, 150, 0, 224, + 239, 240, 0, 239, 0, 0, 289, 0, 0, 0, + 291, 0, 212, 0, 0, 216, 0, 0, 220, 279, + 0, 271, 280, 274, 0, 278, 0, 239, 272, 0, + 239, 0, 0, 290, 0, 0, 0, 292, 340, 329, + 0, 0, 331, 0, 325, 0, 315, 0, 0, 0, + 285, 0, 284, 0, 342, 0, 99, 261, 264, 0, + 100, 267, 103, 128, 105, 106, 71, 110, 111, 63, + 112, 115, 69, 72, 64, 239, 65, 74, 118, 67, + 120, 70, 122, 123, 268, 125, 126, 130, 0, 92, + 0, 0, 94, 98, 96, 83, 95, 97, 0, 93, + 82, 262, 260, 138, 139, 144, 0, 137, 0, 314, + 0, 301, 302, 0, 313, 0, 0, 0, 304, 309, + 307, 310, 0, 0, 308, 309, 0, 305, 0, 306, + 263, 312, 0, 263, 311, 0, 316, 317, 0, 263, + 318, 319, 0, 0, 320, 0, 0, 0, 321, 322, + 156, 155, 0, 0, 0, 288, 0, 0, 0, 303, + 276, 269, 0, 277, 273, 0, 275, 265, 0, 266, + 270, 86, 0, 0, 90, 77, 0, 79, 88, 0, + 80, 89, 91, 81, 87, 78, 0, 84, 160, 158, + 162, 159, 157, 161, 6, 334, 4, 2, 61, 85, + 0, 0, 64, 66, 65, 31, 5, 0, 62, 0, + 40, 39, 38, 0, 0, 53, 0, 54, 0, 59, + 60, 0, 40, 0, 0, 0, 0, 0, 49, 50, + 0, 51, 0, 52, 0, 55, 56, 0, 0, 0, + 0, 0, 57, 58, 0, 47, 41, 48, 42, 0, + 0, 0, 0, 44, 0, 45, 46, 43, 0, 0, + 30, 34, 35, 36, 37, 138, 263, 0, 0, 100, + 267, 103, 128, 105, 106, 71, 110, 111, 63, 112, + 115, 69, 72, 64, 239, 65, 74, 118, 67, 120, + 70, 122, 123, 268, 125, 126, 130, 138, 0, 26, + 0, 0, 32, 27, 33, 28, 24, 0, 29, 25, + 8, 0, 10, 0, 9, 0, 1, 21, 12, 0, + 13, 0, 14, 0, 19, 20, 0, 15, 16, 0, + 17, 18, 11, 23, 7, 343}; + +const short QmlJSGrammar::goto_default [] = { + 7, 616, 206, 195, 204, 506, 494, 615, 634, 610, + 614, 612, 617, 22, 613, 18, 505, 607, 598, 560, + 507, 190, 194, 196, 200, 523, 549, 548, 199, 231, + 26, 473, 472, 355, 354, 9, 353, 356, 106, 17, + 144, 24, 13, 143, 19, 25, 56, 23, 8, 28, + 27, 268, 15, 262, 10, 258, 12, 260, 11, 259, + 20, 266, 21, 267, 14, 261, 257, 298, 410, 263, + 264, 201, 192, 191, 203, 232, 202, 207, 228, 229, + 193, 359, 358, 230, 462, 461, 320, 321, 464, 323, + 463, 322, 418, 422, 425, 421, 420, 440, 441, 184, + 198, 180, 183, 197, 205, 0}; + +const short QmlJSGrammar::action_index [] = { + 439, 1109, 2228, 2228, 2132, 814, -74, 18, 147, -100, + 31, -17, -49, 232, -100, 318, 85, -100, -100, 554, + 33, 94, 331, 215, -100, -100, -100, 448, 231, 1109, + -100, -100, -100, 320, -100, 1940, 1472, 1109, 1109, 1109, + -100, 724, 1109, -100, -100, 1109, 1109, -100, -100, -100, + -100, -100, 1109, -100, 1109, 1109, -100, 1109, 1109, 129, + 157, -100, -100, 1109, 1109, 1109, -100, -100, -100, 200, + 1109, 293, 1109, 1109, 1109, 1109, 466, 1109, 1109, 1109, + 1109, 1109, 1109, 179, 1109, 1109, 1109, 119, 125, 95, + 188, 198, 184, 203, 178, 567, 567, 484, 1109, -5, + 1109, 67, 1844, 1109, 1109, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, -100, -100, -100, -100, -100, -100, 110, + 1109, -100, -100, 70, 61, -100, 1109, -100, -100, 1109, + -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, + -100, -100, -100, 1109, 55, 1109, 1109, 73, 63, 1109, + -100, 1844, 1109, 1109, -100, 141, -100, 41, -100, -100, + 87, -100, 255, 80, 78, -100, 287, -100, 83, 2228, + -100, -100, -100, -100, -100, 225, -100, -100, 52, -100, + -100, -100, -100, -100, -100, 2228, -100, -100, 420, -100, + 408, 113, 2132, 50, 330, 65, 46, 2420, 72, 1109, + -100, 74, 75, 1109, 77, -100, 53, 56, -100, -100, + 323, -100, -100, -100, -100, -100, -100, 96, -100, -100, + -100, -100, 99, -100, -100, -100, -100, -100, -100, 60, + 47, 1109, 118, 93, -100, -100, 1291, -100, 79, 66, + 64, -100, 413, 76, 51, 664, 89, 97, 393, 183, + 337, 1109, 413, 1109, 1109, 1109, 1109, 411, 1109, 1109, + 1109, 1109, 1109, 252, 272, 212, 217, 221, 490, 490, + 383, 1109, 64, 1109, 84, 1109, -100, 536, 1109, -100, + 1109, 69, 68, 1109, 44, 2132, -100, 1109, 124, 2132, + -100, 1109, 54, 1109, 1109, 71, 88, 1109, -100, 82, + 122, 154, -100, -100, 1109, -100, 343, 1109, -100, 81, + 1109, 90, 2132, -100, 1109, 112, 2132, -100, 86, 333, + -39, -10, 2228, -33, -100, 2132, -100, 1109, 246, 2132, + 4, 2132, -100, 10, 16, -21, -100, -100, 2132, -26, + 480, 19, 462, 128, 1109, 2132, 6, -9, 400, 8, + -22, 840, -3, -6, -100, 1202, -100, -7, -28, 5, + 1109, 2, -23, 1109, 0, 1109, -34, -30, 1109, -100, + 2036, 21, -100, -100, -100, -100, -100, -100, 1109, -100, + -100, -100, -100, 209, -100, 1109, 40, -100, 2132, -100, + 101, -100, -100, 2132, -100, 1109, 120, 43, -100, 62, + -100, 59, 109, 1109, -100, 57, 58, -100, 39, -100, + 2132, -100, 117, 2132, -100, 199, -100, -100, 107, 2132, + 34, -100, 24, 11, -100, 346, -19, 14, -100, -100, + -100, -100, 1109, 133, 2132, -100, 1109, 126, 2132, -100, + 20, -100, 173, -100, -100, 1109, -100, -100, 303, -100, + -100, -100, 100, 1656, -100, -100, 1564, -100, -100, 1748, + -100, -100, -100, -100, -100, -100, 131, -100, -100, -100, + -100, -100, -100, -100, -100, 2228, -100, -100, -100, 158, + -20, 752, 165, -16, 22, -100, -100, 98, -100, 189, + -100, -100, -100, 28, 170, -100, 1109, -100, 230, -100, + -100, 247, 1, 13, 238, 37, -24, 106, -100, -100, + 273, -100, 1109, -100, 265, -100, -100, 242, -4, 12, + 1109, 241, -100, -100, 234, -100, 245, -100, 3, 9, + 311, 190, 316, -100, 134, -100, -100, -100, 1380, 1020, + -100, -100, -100, -100, -100, 359, 2324, 1472, 15, 444, + 38, 394, 138, 1109, 2132, 36, 17, 397, 42, 23, + 840, 32, 29, -100, 1202, -100, 26, 35, 48, 1109, + 45, 25, 1109, 49, 1109, 27, 30, 314, 132, -100, + 7, 752, -100, -100, -100, -100, -100, 930, -100, -100, + -100, 752, -100, 253, -87, 617, -100, -100, 102, 290, + -100, 191, -100, 140, -100, -100, 275, -100, -100, 91, + -100, -100, -100, -100, -100, -100, + + -106, 12, -87, 18, 17, 212, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -53, + -106, -106, -106, -106, -106, -106, -106, -106, -106, 162, + -106, -106, -106, -4, -106, -106, -11, 24, 75, 76, + -106, 83, 55, -106, -106, 157, 158, -106, -106, -106, + -106, -106, 150, -106, 172, 176, -106, 168, 167, -106, + -106, -106, -106, 173, 154, 115, -106, -106, -106, -106, + 147, -106, 121, 113, 112, 125, -106, 128, 143, 146, + 140, 139, 136, -106, 122, 138, 130, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, 149, -106, + 153, -106, 110, 82, 46, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + 35, -106, -106, -106, -106, -106, 37, -106, -106, 45, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, 92, -106, 88, 58, -106, -106, 51, + -106, 209, 72, 78, -106, -106, -106, -106, -106, -106, + -106, -106, 27, -106, -106, -106, 63, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, 50, -106, -106, 28, -106, + 29, -106, 47, -106, 33, -106, -106, 66, -106, 73, + -106, -106, -106, 81, 53, -106, -106, -106, -106, -106, + -13, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, 9, -106, -106, -106, -106, 111, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + 3, 186, -106, 220, 228, 234, 204, -106, 90, 91, + 94, 97, 93, -106, -106, -106, -106, -106, -106, -106, + -106, 210, -106, 187, -106, 214, -106, -106, 208, -106, + 207, -106, -106, 155, -106, 8, -106, 4, -106, -1, + -106, 217, -106, 177, 185, -106, -106, 184, -106, -106, + -106, -106, -106, -106, 183, -106, 194, 105, -106, -106, + 99, -106, 71, -106, 74, -106, 65, -106, -106, 114, + -106, -106, -55, -106, -106, 64, -106, 44, -106, 30, + -106, 31, -106, -106, -106, -106, -106, -106, 57, -106, + 36, -106, 40, -106, 70, 59, -106, -106, 42, -106, + -106, 104, -106, -106, -106, 38, -106, -106, -106, -106, + 79, -106, 69, 108, -106, 84, -106, -106, 56, -106, + 68, -106, -106, -106, -106, -106, -106, -106, 52, -106, + -106, -106, -106, -106, -106, 109, -106, -106, 77, -106, + -106, -106, -106, 86, -106, 80, -106, -106, -106, -106, + -106, -59, -106, 43, -106, -63, -106, -106, -106, -106, + 98, -106, -106, 95, -106, -106, -106, -106, -106, 60, + -34, -106, -106, 32, -106, 41, -106, 39, -106, -106, + -106, -106, 49, -106, 61, -106, 62, -106, 48, -106, + -106, -106, -106, -106, -106, 23, -106, -106, 96, -106, + -106, -106, -106, 34, -106, -106, 133, -106, -106, 54, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, 67, -106, -106, -106, -106, + -106, 22, -106, -106, -106, -106, -106, -106, -106, -22, + -106, -106, -106, -106, -106, -106, 2, -106, -106, -106, + -106, -106, -106, -106, -19, -106, -106, -106, -106, -106, + -106, -106, 100, -106, -106, -106, -106, -21, -106, -106, + -3, -106, -106, -106, -106, -106, 13, -106, -106, -106, + 11, 14, 10, -106, -106, -106, -106, -106, 279, 283, + -106, -106, -106, -106, -106, -106, 19, 273, 15, 16, + -106, 21, -106, 224, 6, -106, -106, 25, -106, -106, + 85, -106, -106, -106, 26, -106, -106, -106, -106, 20, + -106, 7, 87, -106, 107, -106, -106, -106, -106, -106, + -106, 317, -106, -106, -106, -106, -106, 277, -106, -106, + -106, 0, -106, -106, -2, 271, -106, -106, -106, 1, + -106, -106, -106, -106, -106, -106, 5, -106, -106, -106, + -106, -106, -106, -106, -106, -106}; + +const short QmlJSGrammar::action_info [] = { + -97, -98, 452, 611, -116, 527, 456, -124, 415, -121, + 439, 551, -119, -108, 347, -94, 611, 388, 635, 540, + 351, 341, 344, 342, 390, 539, -127, 256, 398, 402, + 100, 98, 70, -97, 400, 163, -98, 465, 524, -116, + 559, 447, 530, -108, 439, -127, 509, 439, 559, -94, + 537, 544, -121, 256, 443, -119, -124, 514, 439, 347, + 445, 526, 423, 452, 423, 430, 456, 423, 70, 554, + 169, 415, 345, 311, 100, 163, 419, 140, 146, 408, + 271, 413, 347, 251, 295, 271, 256, 0, 186, 452, + 0, 311, 456, 140, 429, 317, 0, 0, 0, 324, + 407, 178, 291, 98, 305, 558, 0, 235, 476, 0, + 439, 415, 300, 442, 291, 0, 189, 171, 140, 426, + 140, 148, 339, 182, 433, 140, 140, 443, 140, 303, + 326, 559, 140, 0, 140, 57, 172, 250, 188, 140, + 601, 140, 330, 293, 165, 0, 58, 313, 166, 140, + 332, 314, 631, 630, 255, 254, 477, 241, 240, 57, + 246, 245, 412, 411, 427, 57, 141, 529, 528, 63, + 58, 61, 336, 171, 248, 247, 58, 516, 253, 0, + 417, 468, 62, 327, 309, 334, 458, 57, 602, 248, + 247, 487, 172, 454, 522, 556, 555, 176, 58, 248, + 247, 625, 624, 84, 84, 85, 85, 140, 84, 84, + 85, 85, 63, 84, 64, 85, 86, 86, 510, 510, + 65, 86, 86, 84, 171, 85, 86, 63, 84, 0, + 85, 517, 515, 140, 469, 467, 86, 84, 140, 85, + 512, 86, 84, 172, 85, 405, 84, 102, 85, 140, + 86, 511, 628, 627, 140, 86, 84, 64, 85, 86, + 437, 436, 171, 65, 512, 512, 103, 510, 104, 86, + 546, 510, 64, 140, 510, 511, 511, 84, 65, 85, + 532, 172, 626, 405, 34, 0, 234, 233, 0, 0, + 86, 520, 519, 0, 0, 547, 545, 84, 0, 85, + 621, 0, 543, 542, 34, 0, 349, 0, 0, 0, + 86, 72, 73, 512, 622, 620, 34, 512, 0, 34, + 512, 47, 49, 48, 511, 0, 536, 535, 511, 171, + 0, 511, 34, 0, 533, 531, 72, 73, 74, 75, + 34, 47, 49, 48, 619, 34, 171, -85, 172, 34, + 173, 0, 34, 47, 49, 48, 47, 49, 48, 34, + 0, 0, 34, 74, 75, 172, 34, 173, 0, 47, + 49, 48, 34, 0, 171, 34, 0, 47, 49, 48, + 0, 0, 47, 49, 48, 0, 47, 49, 48, 47, + 49, 48, -85, 172, 0, 173, 47, 49, 48, 47, + 49, 48, 0, 47, 49, 48, 278, 279, 0, 47, + 49, 48, 47, 49, 48, 280, 278, 279, 281, 0, + 282, 0, 0, 34, 0, 280, 34, 0, 281, 34, + 282, 273, 274, -339, 278, 279, -339, 34, 0, 0, + 0, 0, 0, 280, 0, 0, 281, 0, 282, 34, + 0, 0, 0, 0, 0, 244, 243, 0, 275, 276, + 47, 49, 48, 47, 49, 48, 47, 49, 48, 244, + 243, 77, 78, 34, 47, 49, 48, 0, 0, 79, + 80, 239, 238, 81, 0, 82, 47, 49, 48, 77, + 78, 34, 0, 0, 0, 0, 0, 79, 80, 0, + 0, 81, 0, 82, 0, 239, 238, 77, 78, 34, + 47, 49, 48, 278, 279, 79, 80, 0, 0, 81, + 0, 82, 280, 244, 243, 281, 0, 282, 47, 49, + 48, 6, 5, 4, 1, 3, 2, 0, 0, 150, + 0, 239, 238, 0, 0, 0, 47, 49, 48, 151, + 0, 0, 0, 152, 0, 0, 0, 150, 0, 0, + 0, 0, 153, 0, 154, 0, 0, 151, 0, 0, + 0, 152, 0, 0, 0, 155, 0, 156, 61, 0, + 153, 0, 154, 0, 0, 157, 0, 0, 158, 62, + 77, 78, 0, 155, 159, 156, 61, 0, 79, 80, + 160, 0, 81, 157, 82, 0, 158, 62, 0, 0, + 0, 0, 159, 0, 0, 0, 161, 0, 160, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 31, 0, 0, 0, 161, 0, 0, 0, 0, 33, + 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, + 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, + 501, 0, 0, 0, 44, 0, 0, 150, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 151, 0, 0, + 0, 152, 50, 47, 49, 48, 0, 51, 0, 0, + 153, 0, 154, 0, 0, 307, 0, 0, 43, 53, + 32, 0, 0, 155, 40, 156, 61, 0, 0, 0, + 0, 0, 0, 157, 0, 0, 158, 62, 0, 0, + 0, 0, 159, 0, 0, 0, 0, 0, 160, 0, + 0, 0, 0, 0, 0, 0, 30, 31, 0, 0, + 0, 0, 0, 0, 161, 0, 33, 0, 0, 0, + 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, + 37, 0, 0, 0, 30, 31, 0, 41, 0, 0, + 0, 44, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 34, 0, 0, 0, 35, 36, 0, 37, 50, + 47, 49, 48, 0, 51, 501, 0, 0, 0, 44, + 0, 0, 0, 0, 0, 43, 53, 32, 0, 0, + 0, 40, 0, 0, 0, 0, 0, 50, 47, 49, + 48, 0, 51, 0, 500, 0, 30, 31, 0, 0, + 0, 0, 0, 43, 53, 32, 214, 0, 0, 40, + 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, + 37, 0, 30, 31, 0, 0, 0, 501, 0, 0, + 0, 44, 33, 0, 0, 0, 0, 0, 0, 34, + 0, 0, 0, 35, 36, 0, 37, 0, 0, 50, + 502, 504, 503, 41, 51, 0, 0, 44, 0, 225, + 0, 0, 0, 0, 0, 43, 53, 32, 209, 0, + 0, 40, 0, 0, 0, 50, 47, 49, 48, 0, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 53, 32, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 500, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 214, 0, 0, 0, 0, 0, 0, 34, + 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, + 0, 0, 0, 501, 0, 0, 0, 44, 0, 0, + 0, 0, 0, 0, 0, 608, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 50, 502, 504, 503, 0, + 51, 0, 0, 0, 0, 225, 0, 0, 0, 0, + 0, 43, 53, 32, 209, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 500, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 214, 0, 0, 0, 0, 0, 0, 34, + 0, 0, 0, 35, 36, 0, 37, 0, 0, 0, + 0, 0, 0, 501, 0, 0, 0, 44, 0, 0, + 0, 0, 0, 0, 0, 605, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 50, 502, 504, 503, 0, + 51, 0, 0, 0, 0, 225, 0, 0, 0, 0, + 0, 43, 53, 32, 209, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, + 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, + 0, 0, 35, 36, 0, 37, 0, 0, 0, 38, + 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, + 45, 0, 46, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 50, 47, 49, 48, 0, 51, + 0, 52, 0, 54, 0, 55, 0, 0, 0, 0, + 43, 53, 32, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -117, + 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 50, 47, 49, + 48, 0, 51, 0, 52, 0, 54, 0, 55, 0, + 0, 0, 0, 43, 53, 32, 0, 0, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, + 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, + 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, + 0, 0, 45, 0, 46, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 50, 47, 49, 48, + 0, 51, 0, 52, 0, 54, 270, 55, 0, 0, + 0, 0, 43, 53, 32, 0, 0, 0, 40, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, + 216, 0, 0, 566, 567, 0, 37, 0, 0, 0, + 38, 0, 39, 41, 42, 0, 0, 44, 0, 0, + 0, 45, 0, 46, 0, 0, 0, 0, 0, 0, + 0, 220, 0, 0, 0, 50, 47, 49, 48, 0, + 51, 0, 52, 0, 54, 0, 55, 0, 0, 0, + 0, 43, 53, 32, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 474, 0, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 45, 0, 46, 0, 0, 475, 0, + 0, 0, 0, 0, 0, 0, 0, 50, 47, 49, + 48, 0, 51, 0, 52, 0, 54, 0, 55, 0, + 0, 0, 0, 43, 53, 32, 0, 0, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 474, 0, 0, 29, 30, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, + 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, + 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, + 0, 44, 0, 0, 0, 45, 0, 46, 0, 0, + 480, 0, 0, 0, 0, 0, 0, 0, 0, 50, + 47, 49, 48, 0, 51, 0, 52, 0, 54, 0, + 55, 0, 0, 0, 0, 43, 53, 32, 0, 0, + 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 482, 0, 0, 29, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, + 36, 0, 37, 0, 0, 0, 38, 0, 39, 41, + 42, 0, 0, 44, 0, 0, 0, 45, 0, 46, + 0, 0, 485, 0, 0, 0, 0, 0, 0, 0, + 0, 50, 47, 49, 48, 0, 51, 0, 52, 0, + 54, 0, 55, 0, 0, 0, 0, 43, 53, 32, + 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 482, 0, 0, 29, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, + 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, + 39, 41, 42, 0, 0, 44, 0, 0, 0, 45, + 0, 46, 0, 0, 483, 0, 0, 0, 0, 0, + 0, 0, 0, 50, 47, 49, 48, 0, 51, 0, + 52, 0, 54, 0, 55, 0, 0, 0, 0, 43, + 53, 32, 0, 0, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 109, + 110, 0, 0, 112, 114, 115, 0, 0, 116, 0, + 117, 0, 0, 0, 119, 120, 121, 0, 0, 0, + 0, 0, 0, 34, 122, 123, 124, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, + 47, 49, 48, 129, 130, 131, 0, 133, 134, 135, + 136, 137, 138, 0, 0, 126, 132, 118, 111, 113, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 108, 109, 110, 0, 0, 112, + 114, 115, 0, 0, 116, 0, 117, 0, 0, 0, + 119, 120, 121, 0, 0, 0, 0, 0, 0, 392, + 122, 123, 124, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 125, 0, 0, 0, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, + 0, 0, 0, 0, 0, 397, 394, 396, 0, 129, + 130, 131, 0, 133, 134, 135, 136, 137, 138, 0, + 0, 126, 132, 118, 111, 113, 127, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 108, 109, 110, 0, 0, 112, 114, 115, 0, 0, + 116, 0, 117, 0, 0, 0, 119, 120, 121, 0, + 0, 0, 0, 0, 0, 392, 122, 123, 124, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, + 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, + 0, 395, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 397, 394, 396, 0, 129, 130, 131, 0, 133, + 134, 135, 136, 137, 138, 0, 0, 126, 132, 118, + 111, 113, 127, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, + 0, 210, 0, 29, 30, 31, 212, 0, 0, 0, + 0, 0, 0, 213, 33, 0, 0, 0, 0, 0, + 0, 215, 216, 0, 0, 217, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, + 0, 219, 0, 220, 0, 0, 0, 50, 218, 221, + 48, 222, 51, 223, 52, 224, 54, 225, 55, 226, + 227, 0, 0, 43, 53, 32, 209, 211, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 208, 0, 0, 0, 0, 210, 0, 29, + 30, 31, 212, 0, 0, 0, 0, 0, 0, 213, + 214, 0, 0, 0, 0, 0, 0, 215, 216, 0, + 0, 217, 36, 0, 37, 0, 0, 0, 38, 0, + 39, 41, 42, 0, 0, 44, 0, 0, 0, 45, + 0, 46, 0, 0, 0, 0, 0, 219, 0, 220, + 0, 0, 0, 50, 218, 221, 48, 222, 51, 223, + 52, 224, 54, 225, 55, 226, 227, 0, 0, 43, + 53, 32, 209, 211, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 569, 109, + 110, 0, 0, 571, 114, 573, 30, 31, 574, 0, + 117, 0, 0, 0, 119, 576, 577, 0, 0, 0, + 0, 0, 0, 578, 579, 123, 124, 217, 36, 0, + 37, 0, 0, 0, 38, 0, 39, 580, 42, 0, + 0, 582, 0, 0, 0, 45, 0, 46, 0, 0, + 0, 0, 0, 584, 0, 220, 0, 0, 0, 586, + 583, 585, 48, 587, 588, 589, 52, 591, 592, 593, + 594, 595, 596, 0, 0, 581, 590, 575, 570, 572, + 127, 40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 360, 109, 110, 0, 0, 362, + 114, 364, 30, 31, 365, 0, 117, 0, 0, 0, + 119, 367, 368, 0, 0, 0, 0, 0, 0, 369, + 370, 123, 124, 217, 36, 0, 37, 0, 0, 0, + 38, 0, 39, 371, 42, 0, 0, 373, 0, 0, + 0, 45, 0, 46, 0, -263, 0, 0, 0, 375, + 0, 220, 0, 0, 0, 377, 374, 376, 48, 378, + 379, 380, 52, 382, 383, 384, 385, 386, 387, 0, + 0, 372, 381, 366, 361, 363, 127, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 541, 310, 460, 513, 538, 518, 525, 308, 249, 632, + 306, 181, 252, 618, 149, 16, 623, 495, 319, 497, + 629, 357, 496, 435, 471, 553, 557, 486, 438, 301, + 428, 237, 350, 352, 604, 521, 242, 424, 550, 552, + 181, 301, 185, 237, 242, 343, 432, 348, 338, 249, + 459, 237, 453, 449, 236, 242, 446, 181, 466, 401, + 448, 249, 357, 455, 444, 457, 346, 337, 357, 484, + 142, 236, 147, 333, 438, 175, 301, 335, 187, 409, + 162, 145, 435, 416, 435, 139, 170, 399, 414, 481, + 438, 389, 0, 168, 0, 0, 403, 357, 403, 59, + 357, 490, 301, 534, 391, 0, 0, 0, 301, 0, + 0, 460, 0, 145, 59, 0, 179, 403, 177, 59, + 59, 488, 489, 0, 404, 105, 404, 0, 59, 185, + 451, 59, 59, 450, 59, 59, 59, 59, 59, 283, + 284, 59, 287, 285, 145, 404, 286, 107, 167, 406, + 164, 59, 59, 451, 450, 265, 59, 59, 301, 59, + 269, 68, 96, 95, 479, 59, 59, 331, 478, 59, + 87, 76, 59, 329, 59, 97, 434, 83, 89, 431, + 59, 470, 59, 59, 59, 94, 88, 59, 93, 92, + 59, 59, 90, 59, 59, 91, 493, 59, 59, 71, + 67, 59, 59, 491, 492, 99, 59, 101, 179, 319, + 301, 59, 59, 340, 69, 60, 59, 59, 450, 66, + 59, 59, 451, 304, 105, 499, 269, 297, 297, 297, + 59, 59, 269, 269, 269, 269, 269, 0, 315, 272, + 498, 508, 294, 0, 0, 0, 107, 174, 59, 325, + 318, 316, 297, 269, 59, 290, 0, 269, 297, 269, + 0, 59, 0, 269, 59, 0, 269, 292, 59, 269, + 179, 277, 59, 0, 299, 302, 312, 269, 59, 288, + 296, 328, 609, 269, 499, 289, 597, 633, 606, 599, + 499, 600, 565, 600, 0, 0, 499, 0, 0, 568, + 561, 562, 563, 564, 0, 498, 508, 0, 471, 0, + 0, 498, 508, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 499, 0, 0, 603, 0, 0, 0, 600, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0}; + +const short QmlJSGrammar::action_check [] = { + 7, 7, 36, 90, 7, 29, 36, 7, 36, 7, + 33, 8, 7, 7, 36, 7, 90, 7, 0, 7, + 16, 60, 55, 33, 8, 29, 7, 36, 7, 55, + 79, 48, 1, 7, 55, 2, 7, 17, 37, 7, + 33, 60, 29, 7, 33, 7, 66, 33, 33, 7, + 66, 29, 7, 36, 20, 7, 7, 29, 33, 36, + 36, 24, 5, 36, 5, 7, 36, 5, 1, 60, + 7, 36, 7, 2, 79, 2, 33, 8, 8, 7, + 1, 7, 36, 36, 8, 1, 36, -1, 8, 36, + -1, 2, 36, 8, 55, 7, -1, -1, -1, 17, + 60, 60, 48, 48, 60, 7, -1, 55, 8, -1, + 33, 36, 61, 6, 48, -1, 33, 15, 8, 10, + 8, 60, 36, 36, 7, 8, 8, 20, 8, 61, + 8, 33, 8, -1, 8, 40, 34, 77, 60, 8, + 8, 8, 61, 79, 50, -1, 51, 50, 54, 8, + 60, 54, 61, 62, 61, 62, 56, 61, 62, 40, + 61, 62, 61, 62, 55, 40, 56, 61, 62, 12, + 51, 42, 60, 15, 61, 62, 51, 7, 60, -1, + 60, 8, 53, 61, 60, 31, 60, 40, 56, 61, + 62, 60, 34, 60, 29, 61, 62, 56, 51, 61, + 62, 61, 62, 25, 25, 27, 27, 8, 25, 25, + 27, 27, 12, 25, 57, 27, 38, 38, 29, 29, + 63, 38, 38, 25, 15, 27, 38, 12, 25, -1, + 27, 61, 62, 8, 61, 62, 38, 25, 8, 27, + 75, 38, 25, 34, 27, 36, 25, 15, 27, 8, + 38, 86, 61, 62, 8, 38, 25, 57, 27, 38, + 61, 62, 15, 63, 75, 75, 34, 29, 36, 38, + 36, 29, 57, 8, 29, 86, 86, 25, 63, 27, + 7, 34, 91, 36, 29, -1, 61, 62, -1, -1, + 38, 61, 62, -1, -1, 61, 62, 25, -1, 27, + 47, -1, 61, 62, 29, -1, 60, -1, -1, -1, + 38, 18, 19, 75, 61, 62, 29, 75, -1, 29, + 75, 66, 67, 68, 86, -1, 61, 62, 86, 15, + -1, 86, 29, -1, 61, 62, 18, 19, 45, 46, + 29, 66, 67, 68, 91, 29, 15, 33, 34, 29, + 36, -1, 29, 66, 67, 68, 66, 67, 68, 29, + -1, -1, 29, 45, 46, 34, 29, 36, -1, 66, + 67, 68, 29, -1, 15, 29, -1, 66, 67, 68, + -1, -1, 66, 67, 68, -1, 66, 67, 68, 66, + 67, 68, 33, 34, -1, 36, 66, 67, 68, 66, + 67, 68, -1, 66, 67, 68, 23, 24, -1, 66, + 67, 68, 66, 67, 68, 32, 23, 24, 35, -1, + 37, -1, -1, 29, -1, 32, 29, -1, 35, 29, + 37, 18, 19, 36, 23, 24, 36, 29, -1, -1, + -1, -1, -1, 32, -1, -1, 35, -1, 37, 29, + -1, -1, -1, -1, -1, 61, 62, -1, 45, 46, + 66, 67, 68, 66, 67, 68, 66, 67, 68, 61, + 62, 23, 24, 29, 66, 67, 68, -1, -1, 31, + 32, 61, 62, 35, -1, 37, 66, 67, 68, 23, + 24, 29, -1, -1, -1, -1, -1, 31, 32, -1, + -1, 35, -1, 37, -1, 61, 62, 23, 24, 29, + 66, 67, 68, 23, 24, 31, 32, -1, -1, 35, + -1, 37, 32, 61, 62, 35, -1, 37, 66, 67, + 68, 92, 93, 94, 95, 96, 97, -1, -1, 3, + -1, 61, 62, -1, -1, -1, 66, 67, 68, 13, + -1, -1, -1, 17, -1, -1, -1, 3, -1, -1, + -1, -1, 26, -1, 28, -1, -1, 13, -1, -1, + -1, 17, -1, -1, -1, 39, -1, 41, 42, -1, + 26, -1, 28, -1, -1, 49, -1, -1, 52, 53, + 23, 24, -1, 39, 58, 41, 42, -1, 31, 32, + 64, -1, 35, 49, 37, -1, 52, 53, -1, -1, + -1, -1, 58, -1, -1, -1, 80, -1, 64, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, + 13, -1, -1, -1, 80, -1, -1, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, + 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, + 43, -1, -1, -1, 47, -1, -1, 3, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, + -1, 17, 65, 66, 67, 68, -1, 70, -1, -1, + 26, -1, 28, -1, -1, 31, -1, -1, 81, 82, + 83, -1, -1, 39, 87, 41, 42, -1, -1, -1, + -1, -1, -1, 49, -1, -1, 52, 53, -1, -1, + -1, -1, 58, -1, -1, -1, -1, -1, 64, -1, + -1, -1, -1, -1, -1, -1, 12, 13, -1, -1, + -1, -1, -1, -1, 80, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 12, 13, -1, 43, -1, -1, + -1, 47, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, 65, + 66, 67, 68, -1, 70, 43, -1, -1, -1, 47, + -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, 87, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 10, -1, 12, 13, -1, -1, + -1, -1, -1, 81, 82, 83, 22, -1, -1, 87, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, 12, 13, -1, -1, -1, 43, -1, -1, + -1, 47, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, 65, + 66, 67, 68, 43, 70, -1, -1, 47, -1, 75, + -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, + -1, 87, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, + -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, + -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, + -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, + 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, + -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, + 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, + -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, + 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, + -1, 70, -1, 72, -1, 74, 75, 76, -1, -1, + -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, + -1, 61, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, + -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, + 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, + 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, + -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, + 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, + 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, + -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, + 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, + 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, + 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, + 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, + 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, + 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, + -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, + 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + -1, 55, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, 66, 67, -1, 69, 70, 71, -1, 73, + 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, + 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, + -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, + -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, -1, -1, 81, 82, 83, 84, 85, -1, 87, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 4, -1, -1, -1, -1, 9, -1, 11, + 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, + 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, + -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, + 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, + 6, -1, -1, 9, 10, 11, 12, 13, 14, -1, + 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, + -1, -1, -1, 29, 30, 31, 32, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, + 86, 87, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, + 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, + 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, 55, -1, -1, -1, 59, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, + -1, 81, 82, 83, 84, 85, 86, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + 3, 2, 15, 25, 25, 3, 25, 3, 2, 11, + 2, 15, 3, 13, 67, 3, 15, 104, 15, 2, + 15, 2, 4, 3, 35, 15, 15, 3, 21, 3, + 93, 15, 2, 2, 19, 13, 15, 96, 25, 25, + 15, 3, 15, 15, 15, 100, 3, 3, 15, 2, + 2, 15, 3, 21, 4, 15, 15, 15, 35, 2, + 21, 2, 2, 2, 98, 3, 2, 2, 2, 35, + 35, 4, 35, 2, 21, 3, 3, 3, 15, 2, + 35, 35, 3, 3, 3, 3, 35, 35, 2, 35, + 21, 35, -1, 35, -1, -1, 13, 2, 13, 44, + 2, 46, 3, 3, 36, -1, -1, -1, 3, -1, + -1, 15, -1, 35, 44, -1, 46, 13, 40, 44, + 44, 46, 46, -1, 41, 15, 41, -1, 44, 15, + 46, 44, 44, 46, 44, 44, 44, 44, 44, 49, + 49, 44, 49, 49, 35, 41, 49, 37, 60, 40, + 58, 44, 44, 46, 46, 44, 44, 44, 3, 44, + 49, 46, 50, 50, 31, 44, 44, 68, 35, 44, + 48, 50, 44, 68, 44, 50, 81, 49, 48, 81, + 44, 85, 44, 44, 44, 49, 48, 44, 49, 49, + 44, 44, 49, 44, 44, 49, 46, 44, 44, 52, + 46, 44, 44, 46, 46, 56, 44, 54, 46, 15, + 3, 44, 44, 99, 47, 47, 44, 44, 46, 46, + 44, 44, 46, 68, 15, 13, 49, 44, 44, 44, + 44, 44, 49, 49, 49, 49, 49, -1, 61, 53, + 28, 29, 55, -1, -1, -1, 37, 38, 44, 66, + 66, 66, 44, 49, 44, 51, -1, 49, 44, 49, + -1, 44, -1, 49, 44, -1, 49, 57, 44, 49, + 46, 51, 44, -1, 66, 68, 59, 49, 44, 51, + 66, 87, 5, 49, 13, 51, 13, 16, 5, 16, + 13, 20, 13, 20, -1, -1, 13, -1, -1, 20, + 21, 22, 23, 24, -1, 28, 29, -1, 35, -1, + -1, 28, 29, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 13, -1, -1, 16, -1, -1, -1, 20, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}; + +QT_END_NAMESPACE diff --git a/src/declarative/qml/parser/qmljsgrammar_p.h b/src/declarative/qml/parser/qmljsgrammar_p.h new file mode 100644 index 0000000..c2e2693 --- /dev/null +++ b/src/declarative/qml/parser/qmljsgrammar_p.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// This file was generated by qlalr - DO NOT EDIT! +#ifndef QMLJSGRAMMAR_P_H +#define QMLJSGRAMMAR_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlJSGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + REDUCE_HERE = 99, + SHIFT_THERE = 98, + T_AND = 1, + T_AND_AND = 2, + T_AND_EQ = 3, + T_AS = 91, + T_AUTOMATIC_SEMICOLON = 62, + T_BREAK = 4, + T_CASE = 5, + T_CATCH = 6, + T_COLON = 7, + T_COMMA = 8, + T_COMMENT = 88, + T_CONST = 84, + T_CONTINUE = 9, + T_DEBUGGER = 85, + T_DEFAULT = 10, + T_DELETE = 11, + T_DIVIDE_ = 12, + T_DIVIDE_EQ = 13, + T_DO = 14, + T_DOT = 15, + T_ELSE = 16, + T_EQ = 17, + T_EQ_EQ = 18, + T_EQ_EQ_EQ = 19, + T_FALSE = 83, + T_FEED_JS_EXPRESSION = 95, + T_FEED_JS_PROGRAM = 97, + T_FEED_JS_SOURCE_ELEMENT = 96, + T_FEED_JS_STATEMENT = 94, + T_FEED_UI_OBJECT_MEMBER = 93, + T_FEED_UI_PROGRAM = 92, + T_FINALLY = 20, + T_FOR = 21, + T_FUNCTION = 22, + T_GE = 23, + T_GT = 24, + T_GT_GT = 25, + T_GT_GT_EQ = 26, + T_GT_GT_GT = 27, + T_GT_GT_GT_EQ = 28, + T_IDENTIFIER = 29, + T_IF = 30, + T_IMPORT = 90, + T_IN = 31, + T_INSTANCEOF = 32, + T_LBRACE = 33, + T_LBRACKET = 34, + T_LE = 35, + T_LPAREN = 36, + T_LT = 37, + T_LT_LT = 38, + T_LT_LT_EQ = 39, + T_MINUS = 40, + T_MINUS_EQ = 41, + T_MINUS_MINUS = 42, + T_MULTILINE_STRING_LITERAL = 87, + T_NEW = 43, + T_NOT = 44, + T_NOT_EQ = 45, + T_NOT_EQ_EQ = 46, + T_NULL = 81, + T_NUMERIC_LITERAL = 47, + T_OR = 48, + T_OR_EQ = 49, + T_OR_OR = 50, + T_PLUS = 51, + T_PLUS_EQ = 52, + T_PLUS_PLUS = 53, + T_PROPERTY = 66, + T_PUBLIC = 89, + T_QUESTION = 54, + T_RBRACE = 55, + T_RBRACKET = 56, + T_READONLY = 68, + T_REMAINDER = 57, + T_REMAINDER_EQ = 58, + T_RESERVED_WORD = 86, + T_RETURN = 59, + T_RPAREN = 60, + T_SEMICOLON = 61, + T_SIGNAL = 67, + T_STAR = 63, + T_STAR_EQ = 64, + T_STRING_LITERAL = 65, + T_SWITCH = 69, + T_THIS = 70, + T_THROW = 71, + T_TILDE = 72, + T_TRUE = 82, + T_TRY = 73, + T_TYPEOF = 74, + T_VAR = 75, + T_VOID = 76, + T_WHILE = 77, + T_WITH = 78, + T_XOR = 79, + T_XOR_EQ = 80, + + ACCEPT_STATE = 635, + RULE_COUNT = 343, + STATE_COUNT = 636, + TERMINAL_COUNT = 100, + NON_TERMINAL_COUNT = 106, + + GOTO_INDEX_OFFSET = 636, + GOTO_INFO_OFFSET = 2520, + GOTO_CHECK_OFFSET = 2520 + }; + + static const char *const spell []; + static const short lhs []; + static const short rhs []; + static const short goto_default []; + static const short action_default []; + static const short action_index []; + static const short action_info []; + static const short action_check []; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +QT_END_NAMESPACE +#endif // QMLJSGRAMMAR_P_H + diff --git a/src/declarative/qml/parser/qmljslexer.cpp b/src/declarative/qml/parser/qmljslexer.cpp new file mode 100644 index 0000000..cf3ed34 --- /dev/null +++ b/src/declarative/qml/parser/qmljslexer.cpp @@ -0,0 +1,1161 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "qmljslexer_p.h" + +#include "qmljsglobal_p.h" +#include "qmljsengine_p.h" +#include "qmljsgrammar_p.h" + +#include <QtCore/qcoreapplication.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +QT_QML_BEGIN_NAMESPACE + +extern double qstrtod(const char *s00, char const **se, bool *ok); + +#define shiftWindowsLineBreak() \ + do { \ + if (((current == '\r') && (next1 == '\n')) \ + || ((current == '\n') && (next1 == '\r'))) { \ + shift(1); \ + } \ + } \ + while (0) + +namespace QmlJS { +extern double integerFromString(const char *buf, int size, int radix); +} + +using namespace QmlJS; + +Lexer::Lexer(Engine *eng, bool tokenizeComments) + : driver(eng), + yylineno(0), + done(false), + size8(128), size16(128), + pos8(0), pos16(0), + terminator(false), + restrKeyword(false), + delimited(false), + stackToken(-1), + state(Start), + pos(0), + code(0), length(0), + yycolumn(0), + startpos(0), + startlineno(0), startcolumn(0), + bol(true), + current(0), next1(0), next2(0), next3(0), + err(NoError), + wantRx(false), + check_reserved(true), + parenthesesState(IgnoreParentheses), + parenthesesCount(0), + prohibitAutomaticSemicolon(false), + tokenizeComments(tokenizeComments) +{ + driver->setLexer(this); + // allocate space for read buffers + buffer8 = new char[size8]; + buffer16 = new QChar[size16]; + pattern = 0; + flags = 0; + +} + +Lexer::~Lexer() +{ + delete [] buffer8; + delete [] buffer16; +} + +void Lexer::setCode(const QString &c, int lineno) +{ + errmsg = QString(); + yylineno = lineno; + yycolumn = 1; + restrKeyword = false; + delimited = false; + stackToken = -1; + pos = 0; + code = c.unicode(); + length = c.length(); + bol = true; + + // read first characters + current = (length > 0) ? code[0].unicode() : 0; + next1 = (length > 1) ? code[1].unicode() : 0; + next2 = (length > 2) ? code[2].unicode() : 0; + next3 = (length > 3) ? code[3].unicode() : 0; +} + +void Lexer::shift(uint p) +{ + while (p--) { + ++pos; + ++yycolumn; + current = next1; + next1 = next2; + next2 = next3; + next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; + } +} + +void Lexer::setDone(State s) +{ + state = s; + done = true; +} + +int Lexer::findReservedWord(const QChar *c, int size) const +{ + switch (size) { + case 2: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) + return QmlJSGrammar::T_DO; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) + return QmlJSGrammar::T_IF; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) + return QmlJSGrammar::T_IN; + else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s')) + return QmlJSGrammar::T_AS; + } break; + + case 3: { + if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) + return QmlJSGrammar::T_FOR; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) + return QmlJSGrammar::T_NEW; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) + return QmlJSGrammar::T_TRY; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) + return QmlJSGrammar::T_VAR; + else if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 4: { + if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QmlJSGrammar::T_CASE; + else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QmlJSGrammar::T_ELSE; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) + return QmlJSGrammar::T_THIS; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) + return QmlJSGrammar::T_VOID; + else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) + return QmlJSGrammar::T_WITH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) + return QmlJSGrammar::T_TRUE; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) + return QmlJSGrammar::T_NULL; + else if (check_reserved) { + if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 5: { + if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('k')) + return QmlJSGrammar::T_BREAK; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('h')) + return QmlJSGrammar::T_CATCH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('w')) + return QmlJSGrammar::T_THROW; + else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e')) + return QmlJSGrammar::T_WHILE; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('t')) + return QmlJSGrammar::T_CONST; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('e')) + return QmlJSGrammar::T_FALSE; + else if (check_reserved) { + if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r') + && c[4] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('r')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('l')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('s')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 6: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e')) + return QmlJSGrammar::T_DELETE; + else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n')) + return QmlJSGrammar::T_RETURN; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h')) + return QmlJSGrammar::T_SWITCH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f')) + return QmlJSGrammar::T_TYPEOF; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QmlJSGrammar::T_IMPORT; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l')) + return QmlJSGrammar::T_SIGNAL; + else if (check_reserved) { + if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b') + && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) + return QmlJSGrammar::T_PUBLIC; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i') + && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 7: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l') + && c[6] == QLatin1Char('t')) + return QmlJSGrammar::T_DEFAULT; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l') + && c[6] == QLatin1Char('y')) + return QmlJSGrammar::T_FINALLY; + else if (check_reserved) { + if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a') + && c[6] == QLatin1Char('n')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d') + && c[6] == QLatin1Char('s')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g') + && c[6] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t') + && c[6] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 8: { + if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e')) + return QmlJSGrammar::T_CONTINUE; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')) + return QmlJSGrammar::T_FUNCTION; + else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u') + && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r')) + return QmlJSGrammar::T_DEBUGGER; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r') + && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y')) + return QmlJSGrammar::T_PROPERTY; + else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d') + && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y')) + return QmlJSGrammar::T_READONLY; + else if (check_reserved) { + if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a') + && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 9: { + if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f') + && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c') + && c[8] == QLatin1Char('e')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n') + && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('t')) + return QmlJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c') + && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e') + && c[8] == QLatin1Char('d')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 10: { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e') + && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f')) + return QmlJSGrammar::T_INSTANCEOF; + else if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + case 12: { + if (check_reserved) { + if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r') + && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z') + && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d')) + return QmlJSGrammar::T_RESERVED_WORD; + } + } break; + + } // switch + + return -1; +} + +int Lexer::lex() +{ + int token = 0; + state = Start; + ushort stringType = 0; // either single or double quotes + bool multiLineString = false; + pos8 = pos16 = 0; + done = false; + terminator = false; + + // did we push a token on the stack previously ? + // (after an automatic semicolon insertion) + if (stackToken >= 0) { + setDone(Other); + token = stackToken; + stackToken = -1; + } + + while (!done) { + switch (state) { + case Start: + if (isWhiteSpace()) { + // do nothing + } else if (current == '/' && next1 == '/') { + recordStartPos(); + shift(1); + state = InSingleLineComment; + } else if (current == '/' && next1 == '*') { + recordStartPos(); + shift(1); + state = InMultiLineComment; + } else if (current == 0) { + syncProhibitAutomaticSemicolon(); + if (!terminator && !delimited && !prohibitAutomaticSemicolon) { + // automatic semicolon insertion if program incomplete + token = QmlJSGrammar::T_SEMICOLON; + stackToken = 0; + setDone(Other); + } else { + setDone(Eof); + } + } else if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + bol = true; + terminator = true; + syncProhibitAutomaticSemicolon(); + if (restrKeyword) { + token = QmlJSGrammar::T_SEMICOLON; + setDone(Other); + } + } else if (current == '"' || current == '\'') { + recordStartPos(); + state = InString; + multiLineString = false; + stringType = current; + } else if (isIdentLetter(current)) { + recordStartPos(); + record16(current); + state = InIdentifier; + } else if (current == '0') { + recordStartPos(); + record8(current); + state = InNum0; + } else if (isDecimalDigit(current)) { + recordStartPos(); + record8(current); + state = InNum; + } else if (current == '.' && isDecimalDigit(next1)) { + recordStartPos(); + record8(current); + state = InDecimal; + } else { + recordStartPos(); + token = matchPunctuator(current, next1, next2, next3); + if (token != -1) { + if (terminator && !delimited && !prohibitAutomaticSemicolon + && (token == QmlJSGrammar::T_PLUS_PLUS + || token == QmlJSGrammar::T_MINUS_MINUS)) { + // automatic semicolon insertion + stackToken = token; + token = QmlJSGrammar::T_SEMICOLON; + } + setDone(Other); + } + else { + setDone(Bad); + err = IllegalCharacter; + errmsg = QCoreApplication::translate("QmlParser", "Illegal character"); + } + } + break; + case InString: + if (current == stringType) { + shift(1); + setDone(String); + } else if (isLineTerminator()) { + multiLineString = true; + record16(current); + } else if (current == 0 || isLineTerminator()) { + setDone(Bad); + err = UnclosedStringLiteral; + errmsg = QCoreApplication::translate("QmlParser", "Unclosed string at end of line"); + } else if (current == '\\') { + state = InEscapeSequence; + } else { + record16(current); + } + break; + // Escape Sequences inside of strings + case InEscapeSequence: + if (isOctalDigit(current)) { + if (current >= '0' && current <= '3' && + isOctalDigit(next1) && isOctalDigit(next2)) { + record16(convertOctal(current, next1, next2)); + shift(2); + state = InString; + } else if (isOctalDigit(current) && + isOctalDigit(next1)) { + record16(convertOctal('0', current, next1)); + shift(1); + state = InString; + } else if (isOctalDigit(current)) { + record16(convertOctal('0', '0', current)); + state = InString; + } else { + setDone(Bad); + err = IllegalEscapeSequence; + errmsg = QCoreApplication::translate("QmlParser", "Illegal escape squence"); + } + } else if (current == 'x') + state = InHexEscape; + else if (current == 'u') + state = InUnicodeEscape; + else { + if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + bol = true; + } else { + record16(singleEscape(current)); + } + state = InString; + } + break; + case InHexEscape: + if (isHexDigit(current) && isHexDigit(next1)) { + state = InString; + record16(QLatin1Char(convertHex(current, next1))); + shift(1); + } else if (current == stringType) { + record16(QLatin1Char('x')); + shift(1); + setDone(String); + } else { + record16(QLatin1Char('x')); + record16(current); + state = InString; + } + break; + case InUnicodeEscape: + if (isHexDigit(current) && isHexDigit(next1) && + isHexDigit(next2) && isHexDigit(next3)) { + record16(convertUnicode(current, next1, next2, next3)); + shift(3); + state = InString; + } else if (current == stringType) { + record16(QLatin1Char('u')); + shift(1); + setDone(String); + } else { + setDone(Bad); + err = IllegalUnicodeEscapeSequence; + errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence"); + } + break; + case InSingleLineComment: + if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + terminator = true; + bol = true; + if (restrKeyword) { + token = QmlJSGrammar::T_SEMICOLON; + setDone(Other); + } else + state = Start; + driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + } else if (current == 0) { + driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + setDone(Eof); + } + + break; + case InMultiLineComment: + if (current == 0) { + setDone(Bad); + err = UnclosedComment; + errmsg = QCoreApplication::translate("QmlParser", "Unclosed comment at end of file"); + driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + } else if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + } else if (current == '*' && next1 == '/') { + state = Start; + shift(1); + driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + } + + break; + case InIdentifier: + if (isIdentLetter(current) || isDecimalDigit(current)) { + record16(current); + break; + } + setDone(Identifier); + break; + case InNum0: + if (current == 'x' || current == 'X') { + record8(current); + state = InHex; + } else if (current == '.') { + record8(current); + state = InDecimal; + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else if (isOctalDigit(current)) { + record8(current); + state = InOctal; + } else if (isDecimalDigit(current)) { + record8(current); + state = InDecimal; + } else { + setDone(Number); + } + break; + case InHex: + if (isHexDigit(current)) + record8(current); + else + setDone(Hex); + break; + case InOctal: + if (isOctalDigit(current)) { + record8(current); + } else if (isDecimalDigit(current)) { + record8(current); + state = InDecimal; + } else { + setDone(Octal); + } + break; + case InNum: + if (isDecimalDigit(current)) { + record8(current); + } else if (current == '.') { + record8(current); + state = InDecimal; + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else { + setDone(Number); + } + break; + case InDecimal: + if (isDecimalDigit(current)) { + record8(current); + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else { + setDone(Number); + } + break; + case InExponentIndicator: + if (current == '+' || current == '-') { + record8(current); + } else if (isDecimalDigit(current)) { + record8(current); + state = InExponent; + } else { + setDone(Bad); + err = IllegalExponentIndicator; + errmsg = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number"); + } + break; + case InExponent: + if (isDecimalDigit(current)) { + record8(current); + } else { + setDone(Number); + } + break; + default: + Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement"); + } + + // move on to the next character + if (!done) + shift(1); + if (state != Start && state != InSingleLineComment) + bol = false; + } + + // no identifiers allowed directly after numeric literal, e.g. "3in" is bad + if ((state == Number || state == Octal || state == Hex) + && isIdentLetter(current)) { + state = Bad; + err = IllegalIdentifier; + errmsg = QCoreApplication::translate("QmlParser", "Identifier cannot start with numeric literal"); + } + + // terminate string + buffer8[pos8] = '\0'; + + double dval = 0; + if (state == Number) { + dval = qstrtod(buffer8, 0, 0); + } else if (state == Hex) { // scan hex numbers + dval = integerFromString(buffer8, pos8, 16); + state = Number; + } else if (state == Octal) { // scan octal number + dval = integerFromString(buffer8, pos8, 8); + state = Number; + } + + restrKeyword = false; + delimited = false; + + switch (parenthesesState) { + case IgnoreParentheses: + break; + case CountParentheses: + if (token == QmlJSGrammar::T_RPAREN) { + --parenthesesCount; + if (parenthesesCount == 0) + parenthesesState = BalancedParentheses; + } else if (token == QmlJSGrammar::T_LPAREN) { + ++parenthesesCount; + } + break; + case BalancedParentheses: + parenthesesState = IgnoreParentheses; + break; + } + + switch (state) { + case Eof: + return 0; + case Other: + if (token == QmlJSGrammar::T_RBRACE || token == QmlJSGrammar::T_SEMICOLON) + delimited = true; + return token; + case Identifier: + if ((token = findReservedWord(buffer16, pos16)) < 0) { + /* TODO: close leak on parse error. same holds true for String */ + if (driver) + qsyylval.ustr = driver->intern(buffer16, pos16); + else + qsyylval.ustr = 0; + return QmlJSGrammar::T_IDENTIFIER; + } + if (token == QmlJSGrammar::T_CONTINUE || token == QmlJSGrammar::T_BREAK + || token == QmlJSGrammar::T_RETURN || token == QmlJSGrammar::T_THROW) { + restrKeyword = true; + } else if (token == QmlJSGrammar::T_IF || token == QmlJSGrammar::T_FOR + || token == QmlJSGrammar::T_WHILE || token == QmlJSGrammar::T_WITH) { + parenthesesState = CountParentheses; + parenthesesCount = 0; + } else if (token == QmlJSGrammar::T_DO) { + parenthesesState = BalancedParentheses; + } + return token; + case String: + if (driver) + qsyylval.ustr = driver->intern(buffer16, pos16); + else + qsyylval.ustr = 0; + return multiLineString?QmlJSGrammar::T_MULTILINE_STRING_LITERAL:QmlJSGrammar::T_STRING_LITERAL; + case Number: + qsyylval.dval = dval; + return QmlJSGrammar::T_NUMERIC_LITERAL; + case Bad: + return -1; + default: + Q_ASSERT(!"unhandled numeration value in switch"); + return -1; + } +} + +bool Lexer::isWhiteSpace() const +{ + return (current == ' ' || current == '\t' || + current == 0x0b || current == 0x0c); +} + +bool Lexer::isLineTerminator() const +{ + return (current == '\n' || current == '\r'); +} + +bool Lexer::isIdentLetter(ushort c) +{ + // ASCII-biased, since all reserved words are ASCII, aand hence the + // bulk of content to be parsed. + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || c == '$' + || c == '_') + return true; + if (c < 128) + return false; + return QChar(c).isLetterOrNumber(); +} + +bool Lexer::isDecimalDigit(ushort c) +{ + return (c >= '0' && c <= '9'); +} + +bool Lexer::isHexDigit(ushort c) const +{ + return ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')); +} + +bool Lexer::isOctalDigit(ushort c) const +{ + return (c >= '0' && c <= '7'); +} + +int Lexer::matchPunctuator(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { + shift(4); + return QmlJSGrammar::T_GT_GT_GT_EQ; + } else if (c1 == '=' && c2 == '=' && c3 == '=') { + shift(3); + return QmlJSGrammar::T_EQ_EQ_EQ; + } else if (c1 == '!' && c2 == '=' && c3 == '=') { + shift(3); + return QmlJSGrammar::T_NOT_EQ_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '>') { + shift(3); + return QmlJSGrammar::T_GT_GT_GT; + } else if (c1 == '<' && c2 == '<' && c3 == '=') { + shift(3); + return QmlJSGrammar::T_LT_LT_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '=') { + shift(3); + return QmlJSGrammar::T_GT_GT_EQ; + } else if (c1 == '<' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_LE; + } else if (c1 == '>' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_GE; + } else if (c1 == '!' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_NOT_EQ; + } else if (c1 == '+' && c2 == '+') { + shift(2); + return QmlJSGrammar::T_PLUS_PLUS; + } else if (c1 == '-' && c2 == '-') { + shift(2); + return QmlJSGrammar::T_MINUS_MINUS; + } else if (c1 == '=' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_EQ_EQ; + } else if (c1 == '+' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_PLUS_EQ; + } else if (c1 == '-' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_MINUS_EQ; + } else if (c1 == '*' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_STAR_EQ; + } else if (c1 == '/' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_DIVIDE_EQ; + } else if (c1 == '&' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_AND_EQ; + } else if (c1 == '^' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_XOR_EQ; + } else if (c1 == '%' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_REMAINDER_EQ; + } else if (c1 == '|' && c2 == '=') { + shift(2); + return QmlJSGrammar::T_OR_EQ; + } else if (c1 == '<' && c2 == '<') { + shift(2); + return QmlJSGrammar::T_LT_LT; + } else if (c1 == '>' && c2 == '>') { + shift(2); + return QmlJSGrammar::T_GT_GT; + } else if (c1 == '&' && c2 == '&') { + shift(2); + return QmlJSGrammar::T_AND_AND; + } else if (c1 == '|' && c2 == '|') { + shift(2); + return QmlJSGrammar::T_OR_OR; + } + + switch(c1) { + case '=': shift(1); return QmlJSGrammar::T_EQ; + case '>': shift(1); return QmlJSGrammar::T_GT; + case '<': shift(1); return QmlJSGrammar::T_LT; + case ',': shift(1); return QmlJSGrammar::T_COMMA; + case '!': shift(1); return QmlJSGrammar::T_NOT; + case '~': shift(1); return QmlJSGrammar::T_TILDE; + case '?': shift(1); return QmlJSGrammar::T_QUESTION; + case ':': shift(1); return QmlJSGrammar::T_COLON; + case '.': shift(1); return QmlJSGrammar::T_DOT; + case '+': shift(1); return QmlJSGrammar::T_PLUS; + case '-': shift(1); return QmlJSGrammar::T_MINUS; + case '*': shift(1); return QmlJSGrammar::T_STAR; + case '/': shift(1); return QmlJSGrammar::T_DIVIDE_; + case '&': shift(1); return QmlJSGrammar::T_AND; + case '|': shift(1); return QmlJSGrammar::T_OR; + case '^': shift(1); return QmlJSGrammar::T_XOR; + case '%': shift(1); return QmlJSGrammar::T_REMAINDER; + case '(': shift(1); return QmlJSGrammar::T_LPAREN; + case ')': shift(1); return QmlJSGrammar::T_RPAREN; + case '{': shift(1); return QmlJSGrammar::T_LBRACE; + case '}': shift(1); return QmlJSGrammar::T_RBRACE; + case '[': shift(1); return QmlJSGrammar::T_LBRACKET; + case ']': shift(1); return QmlJSGrammar::T_RBRACKET; + case ';': shift(1); return QmlJSGrammar::T_SEMICOLON; + + default: return -1; + } +} + +ushort Lexer::singleEscape(ushort c) const +{ + switch(c) { + case 'b': + return 0x08; + case 't': + return 0x09; + case 'n': + return 0x0A; + case 'v': + return 0x0B; + case 'f': + return 0x0C; + case 'r': + return 0x0D; + case '"': + return 0x22; + case '\'': + return 0x27; + case '\\': + return 0x5C; + default: + return c; + } +} + +ushort Lexer::convertOctal(ushort c1, ushort c2, + ushort c3) const +{ + return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); +} + +unsigned char Lexer::convertHex(ushort c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else + return (c - 'A' + 10); +} + +unsigned char Lexer::convertHex(ushort c1, ushort c2) +{ + return ((convertHex(c1) << 4) + convertHex(c2)); +} + +QChar Lexer::convertUnicode(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + return QChar((convertHex(c3) << 4) + convertHex(c4), + (convertHex(c1) << 4) + convertHex(c2)); +} + +void Lexer::record8(ushort c) +{ + Q_ASSERT(c <= 0xff); + + // enlarge buffer if full + if (pos8 >= size8 - 1) { + char *tmp = new char[2 * size8]; + memcpy(tmp, buffer8, size8 * sizeof(char)); + delete [] buffer8; + buffer8 = tmp; + size8 *= 2; + } + + buffer8[pos8++] = (char) c; +} + +void Lexer::record16(QChar c) +{ + // enlarge buffer if full + if (pos16 >= size16 - 1) { + QChar *tmp = new QChar[2 * size16]; + memcpy(tmp, buffer16, size16 * sizeof(QChar)); + delete [] buffer16; + buffer16 = tmp; + size16 *= 2; + } + + buffer16[pos16++] = c; +} + +void Lexer::recordStartPos() +{ + startpos = pos; + startlineno = yylineno; + startcolumn = yycolumn; +} + +bool Lexer::scanRegExp(RegExpBodyPrefix prefix) +{ + pos16 = 0; + bool lastWasEscape = false; + + if (prefix == EqualPrefix) + record16(QLatin1Char('=')); + + while (1) { + if (isLineTerminator() || current == 0) { + errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal"); + return false; + } + else if (current != '/' || lastWasEscape == true) + { + record16(current); + lastWasEscape = !lastWasEscape && (current == '\\'); + } + else { + if (driver) + pattern = driver->intern(buffer16, pos16); + else + pattern = 0; + pos16 = 0; + shift(1); + break; + } + shift(1); + } + + flags = 0; + while (isIdentLetter(current)) { + int flag = Ecma::RegExp::flagFromChar(current); + if (flag == 0) { + errmsg = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'") + .arg(QChar(current)); + return false; + } + flags |= flag; + record16(current); + shift(1); + } + + return true; +} + +void Lexer::syncProhibitAutomaticSemicolon() +{ + if (parenthesesState == BalancedParentheses) { + // we have seen something like "if (foo)", which means we should + // never insert an automatic semicolon at this point, since it would + // then be expanded into an empty statement (ECMA-262 7.9.1) + prohibitAutomaticSemicolon = true; + parenthesesState = IgnoreParentheses; + } else { + prohibitAutomaticSemicolon = false; + } +} + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qmljslexer_p.h b/src/declarative/qml/parser/qmljslexer_p.h new file mode 100644 index 0000000..b830071 --- /dev/null +++ b/src/declarative/qml/parser/qmljslexer_p.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSLEXER_P_H +#define QMLJSLEXER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsglobal_p.h" + +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Lexer +{ +public: + Lexer(Engine *eng, bool tokenizeComments = false); + ~Lexer(); + + void setCode(const QString &c, int lineno); + int lex(); + + int currentLineNo() const { return yylineno; } + int currentColumnNo() const { return yycolumn; } + + int tokenOffset() const { return startpos; } + int tokenLength() const { return pos - startpos; } + + int startLineNo() const { return startlineno; } + int startColumnNo() const { return startcolumn; } + + int endLineNo() const { return currentLineNo(); } + int endColumnNo() const + { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; } + + bool prevTerminator() const { return terminator; } + + enum State { Start, + Identifier, + InIdentifier, + InSingleLineComment, + InMultiLineComment, + InNum, + InNum0, + InHex, + InOctal, + InDecimal, + InExponentIndicator, + InExponent, + Hex, + Octal, + Number, + String, + Eof, + InString, + InEscapeSequence, + InHexEscape, + InUnicodeEscape, + Other, + Bad }; + + enum Error { + NoError, + IllegalCharacter, + UnclosedStringLiteral, + IllegalEscapeSequence, + IllegalUnicodeEscapeSequence, + UnclosedComment, + IllegalExponentIndicator, + IllegalIdentifier + }; + + enum ParenthesesState { + IgnoreParentheses, + CountParentheses, + BalancedParentheses + }; + + enum RegExpBodyPrefix { + NoPrefix, + EqualPrefix + }; + + bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); + + NameId *pattern; + int flags; + + State lexerState() const + { return state; } + + QString errorMessage() const + { return errmsg; } + void setErrorMessage(const QString &err) + { errmsg = err; } + void setErrorMessage(const char *err) + { setErrorMessage(QString::fromLatin1(err)); } + + Error error() const + { return err; } + void clearError() + { err = NoError; } + +private: + Engine *driver; + int yylineno; + bool done; + char *buffer8; + QChar *buffer16; + uint size8, size16; + uint pos8, pos16; + bool terminator; + bool restrKeyword; + // encountered delimiter like "'" and "}" on last run + bool delimited; + int stackToken; + + State state; + void setDone(State s); + uint pos; + void shift(uint p); + int lookupKeyword(const char *); + + bool isWhiteSpace() const; + bool isLineTerminator() const; + bool isHexDigit(ushort c) const; + bool isOctalDigit(ushort c) const; + + int matchPunctuator(ushort c1, ushort c2, + ushort c3, ushort c4); + ushort singleEscape(ushort c) const; + ushort convertOctal(ushort c1, ushort c2, + ushort c3) const; +public: + static unsigned char convertHex(ushort c1); + static unsigned char convertHex(ushort c1, ushort c2); + static QChar convertUnicode(ushort c1, ushort c2, + ushort c3, ushort c4); + static bool isIdentLetter(ushort c); + static bool isDecimalDigit(ushort c); + + inline int ival() const { return qsyylval.ival; } + inline double dval() const { return qsyylval.dval; } + inline NameId *ustr() const { return qsyylval.ustr; } + + const QChar *characterBuffer() const { return buffer16; } + int characterCount() const { return pos16; } + +private: + void record8(ushort c); + void record16(QChar c); + void recordStartPos(); + + int findReservedWord(const QChar *buffer, int size) const; + + void syncProhibitAutomaticSemicolon(); + + const QChar *code; + uint length; + int yycolumn; + int startpos; + int startlineno; + int startcolumn; + int bol; // begin of line + + union { + int ival; + double dval; + NameId *ustr; + } qsyylval; + + // current and following unicode characters + ushort current, next1, next2, next3; + + struct keyword { + const char *name; + int token; + }; + + QString errmsg; + Error err; + + bool wantRx; + bool check_reserved; + + ParenthesesState parenthesesState; + int parenthesesCount; + bool prohibitAutomaticSemicolon; + bool tokenizeComments; +}; + +} // namespace QmlJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qmljsmemorypool_p.h b/src/declarative/qml/parser/qmljsmemorypool_p.h new file mode 100644 index 0000000..3da2678 --- /dev/null +++ b/src/declarative/qml/parser/qmljsmemorypool_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSMEMORYPOOL_P_H +#define QMLJSMEMORYPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsglobal_p.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> + +#include <string.h> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class QML_PARSER_EXPORT MemoryPool : public QSharedData +{ +public: + enum { maxBlockCount = -1 }; + enum { defaultBlockSize = 1 << 12 }; + + MemoryPool() { + m_blockIndex = maxBlockCount; + m_currentIndex = 0; + m_storage = 0; + m_currentBlock = 0; + m_currentBlockSize = 0; + } + + virtual ~MemoryPool() { + for (int index = 0; index < m_blockIndex + 1; ++index) + qFree(m_storage[index]); + + qFree(m_storage); + } + + char *allocate(int bytes) { + bytes += (8 - bytes) & 7; // ensure multiple of 8 bytes (maintain alignment) + if (m_currentBlock == 0 || m_currentBlockSize < m_currentIndex + bytes) { + ++m_blockIndex; + m_currentBlockSize = defaultBlockSize << m_blockIndex; + + m_storage = reinterpret_cast<char**>(qRealloc(m_storage, sizeof(char*) * (1 + m_blockIndex))); + m_currentBlock = m_storage[m_blockIndex] = reinterpret_cast<char*>(qMalloc(m_currentBlockSize)); + ::memset(m_currentBlock, 0, m_currentBlockSize); + + m_currentIndex = (8 - quintptr(m_currentBlock)) & 7; // ensure first chunk is 64-bit aligned + Q_ASSERT(m_currentIndex + bytes <= m_currentBlockSize); + } + + char *p = reinterpret_cast<char *> + (m_currentBlock + m_currentIndex); + + m_currentIndex += bytes; + + return p; + } + + int bytesAllocated() const { + int bytes = 0; + for (int index = 0; index < m_blockIndex; ++index) + bytes += (defaultBlockSize << index); + bytes += m_currentIndex; + return bytes; + } + +private: + int m_blockIndex; + int m_currentIndex; + char *m_currentBlock; + int m_currentBlockSize; + char **m_storage; + +private: + Q_DISABLE_COPY(MemoryPool) +}; + +} // namespace QmlJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qmljsnodepool_p.h b/src/declarative/qml/parser/qmljsnodepool_p.h new file mode 100644 index 0000000..abe4cc8 --- /dev/null +++ b/src/declarative/qml/parser/qmljsnodepool_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSNODEPOOL_P_H +#define QMLJSNODEPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmljsglobal_p.h" +#include "qmljsmemorypool_p.h" + +#include <QtCore/QHash> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +namespace AST { +class Node; +} // namespace AST + +class Code; +class CompilationUnit; +class Engine; + +template <typename NodeType> +inline NodeType *makeAstNode(MemoryPool *storage) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(); + return node; +} + +template <typename NodeType, typename Arg1> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2, typename Arg3> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3, arg4); + return node; +} + +class QML_PARSER_EXPORT NodePool : public MemoryPool +{ +public: + NodePool(const QString &fileName, Engine *engine); + virtual ~NodePool(); + + Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation); + + inline QString fileName() const { return m_fileName; } + inline Engine *engine() const { return m_engine; } +#ifndef J_SCRIPT_NO_EVENT_NOTIFY + inline qint64 id() const { return m_id; } +#endif + +private: + QHash<AST::Node*, Code*> m_codeCache; + QString m_fileName; + Engine *m_engine; +#ifndef J_SCRIPT_NO_EVENT_NOTIFY + qint64 m_id; +#endif + +private: + Q_DISABLE_COPY(NodePool) +}; + +} // namespace QmlJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qmljsparser.cpp b/src/declarative/qml/parser/qmljsparser.cpp new file mode 100644 index 0000000..856d06d --- /dev/null +++ b/src/declarative/qml/parser/qmljsparser.cpp @@ -0,0 +1,1843 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtDebug> +#include <QtGui/QApplication> + +#include <string.h> + +#include "qmljsengine_p.h" +#include "qmljslexer_p.h" +#include "qmljsast_p.h" +#include "qmljsnodepool_p.h" + + + +#include "qmljsparser_p.h" +#include <QVarLengthArray> + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QmlJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); +} + +inline static bool automatic(Engine *driver, int token) +{ + return token == QmlJSGrammar::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +Parser::Parser(Engine *engine): + driver(engine), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse(int startToken) +{ + Lexer *lexer = driver->lexer(); + bool hadErrors = false; + int yytoken = -1; + int action = 0; + + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + tos = -1; + program = 0; + + do { + if (++tos == stack_size) + reallocateStack(); + + state_stack[tos] = action; + + _Lcheck_token: + if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { + yyprevlloc = yylloc; + + if (first_token == last_token) { + yytoken = lexer->lex(); + yylval = lexer->dval(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + loc(1) = yylloc; + } else { + --tos; + return ! hadErrors; + } + } else if (action < 0) { + const int r = -action - 1; + tos -= rhs[r]; + + switch (r) { + +case 0: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 1: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 2: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 3: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 4: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 5: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 6: { + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; + +case 8: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; + +case 9: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; + +case 10: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), + sym(1).UiImportList, sym(2).UiImport); +} break; + +case 13: { + sym(1).UiImport->semicolonToken = loc(2); +} break; + +case 15: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->semicolonToken = loc(3); +} break; + +case 17: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->asToken = loc(3); + sym(1).UiImport->importIdToken = loc(4); + sym(1).UiImport->importId = sym(4).sval; + sym(1).UiImport->semicolonToken = loc(5); +} break; + +case 19: { + sym(1).UiImport->asToken = loc(2); + sym(1).UiImport->importIdToken = loc(3); + sym(1).UiImport->importId = sym(3).sval; + sym(1).UiImport->semicolonToken = loc(4); +} break; + +case 20: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + QString text; + for (AST::UiQualifiedId *q = qualifiedId; q; q = q->next) { + text += q->name->asString(); + if (q->next) text += QLatin1String("."); + } + node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId); + node->fileNameToken = loc(2); + } + + sym(1).Node = node; + + if (! node) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id or a string literal"))); + + return false; // ### remove me + } +} break; + +case 21: { + sym(1).Node = 0; +} break; + +case 22: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 23: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 24: { + AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; + +case 25: { + sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 26: { + AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 27: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0); + node->lbraceToken = loc(1); + node->rbraceToken = loc(2); + sym(1).Node = node; +} break; + +case 28: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 29: { + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; + +case 31: { + AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); + node->colonToken = loc(2); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; + +case 32: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +case 33:case 34:case 35:case 36: +{ + AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 37: + +case 38: { + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); + break; +} + +case 40: { + sym(1).Node = 0; +} break; + +case 41: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; + +case 42: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; + +case 43: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); + node->commaToken = loc(2); + node->identifierToken = loc(4); + sym(1).Node = node; +} break; + +case 45: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->parameters = sym(4).UiParameterList; + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; + +case 47: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 49: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 51: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); + sym(1).Node = node; +} break; + +case 53: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); + sym(1).Node = node; +} break; + +case 55: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, + sym(5).Expression); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->colonToken = loc(4); + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; + +case 57: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 59: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 60: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 61: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 63: { + QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 64: { + QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 65: { + QString s = QLatin1String(QmlJSGrammar::spell[T_READONLY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 66: { + AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); + node->thisToken = loc(1); + sym(1).Node = node; +} break; + +case 67: { + AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 68: { + AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); + node->nullToken = loc(1); + sym(1).Node = node; +} break; + +case 69: { + AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); + node->trueToken = loc(1); + sym(1).Node = node; +} break; + +case 70: { + AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); + node->falseToken = loc(1); + sym(1).Node = node; +} break; + +case 71: { + AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +case 72: +case 73: { + AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 74: { + bool rx = lexer->scanRegExp(Lexer::NoPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; // ### remove me + } + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 75: { + bool rx = lexer->scanRegExp(Lexer::EqualPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; + } + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 76: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; + +case 77: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 78: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 79: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 80: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; + +case 81: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + else + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); + node->lbraceToken = loc(1); + node->lbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 82: { + AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + node->lbraceToken = loc(1); + node->lbraceToken = loc(4); + sym(1).Node = node; +} break; + +case 83: { + AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); + node->lparenToken = loc(1); + node->rparenToken = loc(3); + sym(1).Node = node; +} break; + +case 84: { + if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, + QLatin1String("Ignored annotation"))); + + sym(1).Expression = mem->base; + } + + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { + sym(1).UiQualifiedId = qualifiedId; + } else { + sym(1).UiQualifiedId = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id"))); + + return false; // ### recover + } +} break; + +case 85: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); +} break; + +case 86: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; + +case 87: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 88: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 89: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; +} break; + +case 90: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 91: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 92: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + node->commaToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 93: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +case 94: +case 95: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 96: { + AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 97: { + AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 98: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 99: + +case 100: + +case 101: + +case 102: + +case 103: + +case 104: + +case 105: + +case 106: + +case 107: + +case 108: + +case 109: + +case 110: + +case 111: + +case 112: + +case 113: + +case 114: + +case 115: + +case 116: + +case 117: + +case 118: + +case 119: + +case 120: + +case 121: + +case 122: + +case 123: + +case 124: + +case 125: + +case 126: + +case 127: + +case 128: + +case 129: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; + +case 134: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 135: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 136: { + AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); + node->newToken = loc(1); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + sym(1).Node = node; +} break; + +case 138: { + AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; + +case 139: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 140: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 141: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 142: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 143: { + sym(1).Node = 0; +} break; + +case 144: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; + +case 145: { + sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); +} break; + +case 146: { + AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 150: { + AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; + +case 151: { + AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; + +case 153: { + AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; + +case 154: { + AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; + +case 155: { + AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; + +case 156: { + AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; + +case 157: { + AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; + +case 158: { + AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; + +case 159: { + AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; + +case 160: { + AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; + +case 161: { + AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; + +case 163: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mul, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 164: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Div, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 165: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mod, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 167: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Add, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 168: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Sub, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 170: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::LShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 171: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::RShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 172: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::URShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 174: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 175: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 176: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 177: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 178: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 179: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::In, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 181: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 182: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 183: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 184: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 185: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 187: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 188: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 189: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 190: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 192: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 193: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 194: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 195: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 197: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 199: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 201: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 203: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 205: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 207: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 209: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 211: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 213: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 215: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 217: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 219: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 221: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 223: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 224: { + sym(1).ival = QSOperator::Assign; +} break; + +case 225: { + sym(1).ival = QSOperator::InplaceMul; +} break; + +case 226: { + sym(1).ival = QSOperator::InplaceDiv; +} break; + +case 227: { + sym(1).ival = QSOperator::InplaceMod; +} break; + +case 228: { + sym(1).ival = QSOperator::InplaceAdd; +} break; + +case 229: { + sym(1).ival = QSOperator::InplaceSub; +} break; + +case 230: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; + +case 231: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; + +case 232: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; + +case 233: { + sym(1).ival = QSOperator::InplaceAnd; +} break; + +case 234: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 235: { + sym(1).ival = QSOperator::InplaceOr; +} break; + +case 237: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 238: { + sym(1).Node = 0; +} break; + +case 241: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 242: { + sym(1).Node = 0; +} break; + +case 259: { + AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 260: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); +} break; + +case 261: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); +} break; + +case 262: { + sym(1).Node = 0; +} break; + +case 263: { + sym(1).Node = sym(1).StatementList->finish (); +} break; + +case 265: { + AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), + sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + node->declarationKindToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 266: { + sym(1).ival = T_CONST; +} break; + +case 267: { + sym(1).ival = T_VAR; +} break; + +case 268: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 269: { + AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 270: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 271: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; + +case 272: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 273: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 274: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 275: { + sym(1).Node = 0; +} break; + +case 277: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 278: { + sym(1).Node = 0; +} break; + +case 280: { + AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; + +case 282: { + AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 283: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(5); + sym(1).Node = node; +} break; + +case 284: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 286: { + AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + node->doToken = loc(1); + node->whileToken = loc(3); + node->lparenToken = loc(4); + node->rparenToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 287: { + AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->whileToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 288: { + AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Expression, sym(9).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->firstSemicolonToken = loc(4); + node->secondSemicolonToken = loc(6); + node->rparenToken = loc(8); + sym(1).Node = node; +} break; + +case 289: { + AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), + sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(8).Expression, sym(10).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->firstSemicolonToken = loc(5); + node->secondSemicolonToken = loc(7); + node->rparenToken = loc(9); + sym(1).Node = node; +} break; + +case 290: { + AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->inToken = loc(4); + node->rparenToken = loc(6); + sym(1).Node = node; +} break; + +case 291: { + AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), + sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->inToken = loc(5); + node->rparenToken = loc(7); + sym(1).Node = node; +} break; + +case 293: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 295: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + node->continueToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 297: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 299: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); + node->breakToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 301: { + AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + node->returnToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 302: { + AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->withToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 303: { + AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + node->switchToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 304: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 305: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(5); + sym(1).Node = node; +} break; + +case 306: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); +} break; + +case 307: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); +} break; + +case 308: { + sym(1).Node = 0; +} break; + +case 309: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; + +case 310: { + AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + node->caseToken = loc(1); + node->colonToken = loc(3); + sym(1).Node = node; +} break; + +case 311: { + AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + node->defaultToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +case 312: +case 313: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 314: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 316: { + AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + node->throwToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 317: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 318: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 319: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 320: { + AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); + node->catchToken = loc(1); + node->lparenToken = loc(2); + node->identifierToken = loc(3); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 321: { + AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; + +case 323: { + AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 324: { + AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; + +case 325: { + AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (sym(2).sval) + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; + +case 326: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 327: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + node->commaToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 328: { + sym(1).Node = 0; +} break; + +case 329: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; + +case 330: { + sym(1).Node = 0; +} break; + +case 332: { + sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; + +case 333: { + sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; + +case 334: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); +} break; + +case 335: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); +} break; + +case 336: { + sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); +} break; + +case 337: { + sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); +} break; + +case 338: { + sym(1).sval = 0; +} break; + +case 340: { + sym(1).Node = 0; +} break; + + } // switch + action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); + } // if + } while (action != 0); + + if (first_token == last_token) { + const int errorState = state_stack[tos]; + + // automatic insertion of `;' + if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QmlParser", "Missing `;'"); + //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); + + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + yytoken = T_SEMICOLON; + yylval = 0; + + action = errorState; + + goto _Lcheck_token; + } + + hadErrors = true; + + token_buffer[0].token = yytoken; + token_buffer[0].dval = yylval; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->dval(); + token_buffer[1].loc = yylloc = location(lexer); + + if (t_action(errorState, yytoken)) { + QString msg; + int token = token_buffer[0].token; + if (token < 0 || token >= TERMINAL_COUNT) + msg = qApp->translate("QmlParser", "Syntax error"); + else + msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + action = errorState; + goto _Lcheck_token; + } + + static int tokens[] = { + T_PLUS, + T_EQ, + + T_COMMA, + T_COLON, + T_SEMICOLON, + + T_RPAREN, T_RBRACKET, T_RBRACE, + + T_NUMERIC_LITERAL, + T_IDENTIFIER, + + T_LPAREN, T_LBRACKET, T_LBRACE, + + EOF_SYMBOL + }; + + for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { + int a = t_action(errorState, *tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = *tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + first_token = &token_buffer[0]; + last_token = &token_buffer[2]; + + action = errorState; + goto _Lcheck_token; + } + } + + for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || + tk == T_FEED_JS_SOURCE_ELEMENT) + continue; + + int a = t_action(errorState, tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + action = errorState; + goto _Lcheck_token; + } + } + + const QString msg = qApp->translate("QmlParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qmljsparser_p.h b/src/declarative/qml/parser/qmljsparser_p.h new file mode 100644 index 0000000..42fb422 --- /dev/null +++ b/src/declarative/qml/parser/qmljsparser_p.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +#ifndef QMLJSPARSER_P_H +#define QMLJSPARSER_P_H + +#include "qmljsglobal_p.h" +#include "qmljsgrammar_p.h" +#include "qmljsast_p.h" +#include "qmljsengine_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Parser: protected QmlJSGrammar +{ +public: + union Value { + int ival; + double dval; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiParameterList *UiParameterList; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiArrayMemberList *UiArrayMemberList; + AST::UiQualifiedId *UiQualifiedId; + AST::UiSignature *UiSignature; + AST::UiFormalList *UiFormalList; + AST::UiFormal *UiFormal; + }; + +public: + Parser(Engine *engine); + ~Parser(); + + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } + bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; + + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } + + AST::UiObjectMember *uiObjectMember() const + { + if (! program) + return 0; + + return program->uiObjectMemberCast(); + } + + AST::Node *rootNode() const + { return program; } + + QList<DiagnosticMessage> diagnosticMessages() const + { return diagnostic_messages; } + + inline DiagnosticMessage diagnosticMessage() const + { + foreach (const DiagnosticMessage &d, diagnostic_messages) { + if (! d.kind == DiagnosticMessage::Warning) + return d; + } + + return DiagnosticMessage(); + } + + inline QString errorMessage() const + { return diagnosticMessage().message; } + + inline int errorLineNumber() const + { return diagnosticMessage().loc.startLine; } + + inline int errorColumnNumber() const + { return diagnosticMessage().loc.startColumn; } + +protected: + bool parse(int startToken); + + void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline AST::SourceLocation &loc(int index) + { return location_stack [tos + index - 1]; } + + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + +protected: + Engine *driver; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + }; + + double yylval; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList<DiagnosticMessage> diagnostic_messages; +}; + +} // end of namespace QmlJS + + + +#define J_SCRIPT_REGEXPLITERAL_RULE1 74 + +#define J_SCRIPT_REGEXPLITERAL_RULE2 75 + +QT_QML_END_NAMESPACE + + + +#endif // QMLJSPARSER_P_H diff --git a/src/declarative/qml/qbitfield_p.h b/src/declarative/qml/qbitfield_p.h new file mode 100644 index 0000000..8b3afdb --- /dev/null +++ b/src/declarative/qml/qbitfield_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBITFIELD_P_H +#define QBITFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QBitField +{ +public: + inline QBitField(); + inline QBitField(const quint32 *, int bits); + inline QBitField(const QBitField &); + inline ~QBitField(); + + inline QBitField &operator=(const QBitField &); + + inline quint32 size() const; + inline QBitField united(const QBitField &); + inline bool testBit(int) const; + +private: + quint32 bits:31; + quint32 *ownData; + const quint32 *data; +}; + +QBitField::QBitField() +: bits(0), ownData(0), data(0) +{ +} + +QBitField::QBitField(const quint32 *bitData, int bitCount) +: bits((quint32)bitCount), ownData(0), data(bitData) +{ +} + +QBitField::QBitField(const QBitField &other) +: bits(other.bits), ownData(other.ownData), data(other.data) +{ + if (ownData) + ++(*ownData); +} + +QBitField::~QBitField() +{ + if (ownData) + if(0 == --(*ownData)) delete [] ownData; +} + +QBitField &QBitField::operator=(const QBitField &other) +{ + if (other.data == data) + return *this; + + if (ownData) + if(0 == --(*ownData)) delete [] ownData; + + bits = other.bits; + ownData = other.ownData; + data = other.data; + + if (ownData) + ++(*ownData); + + return *this; +} + +inline quint32 QBitField::size() const +{ + return bits; +} + +QBitField QBitField::united(const QBitField &o) +{ + if (o.bits == 0) { + return *this; + } else if (bits == 0) { + return o; + } else { + int max = (bits > o.bits)?bits:o.bits; + int length = (max + 31) / 32; + QBitField rv; + rv.bits = max; + rv.ownData = new quint32[length + 1]; + *(rv.ownData) = 1; + rv.data = rv.ownData + 1; + if (bits > o.bits) { + ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= o.data[ii]; + } else { + ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= data[ii]; + } + return rv; + } +} + +bool QBitField::testBit(int b) const +{ + Q_ASSERT(b >= 0); + if ((quint32)b < bits) { + return data[b / 32] & (1 << (b % 32)); + } else { + return false; + } +} + +QT_END_NAMESPACE + +#endif // QBITFIELD_P_H diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp new file mode 100644 index 0000000..11b9f80 --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder.cpp @@ -0,0 +1,2575 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmetaobjectbuilder_p.h" + +#ifndef Q_OS_WIN +#include <stdint.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QMetaObjectBuilder + \internal + \brief The QMetaObjectBuilder class supports building QMetaObject objects at runtime. + +*/ + +/*! + \enum QMetaObjectBuilder::AddMember + This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject() + + \value ClassName Add the class name. + \value SuperClass Add the super class. + \value Methods Add methods that aren't signals or slots. + \value Signals Add signals. + \value Slots Add slots. + \value Constructors Add constructors. + \value Properties Add properties. + \value Enumerators Add enumerators. + \value ClassInfos Add items of class information. + \value RelatedMetaObjects Add related meta objects. + \value StaticMetacall Add the static metacall function. + \value PublicMethods Add public methods (ignored for signals). + \value ProtectedMethods Add protected methods (ignored for signals). + \value PrivateMethods All private methods (ignored for signals). + \value AllMembers Add all members. + \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function. +*/ + +// copied from moc's generator.cpp +uint qvariant_nameToType(const char* name) +{ + if (!name) + return 0; + + if (strcmp(name, "QVariant") == 0) + return 0xffffffff; + if (strcmp(name, "QCString") == 0) + return QMetaType::QByteArray; + if (strcmp(name, "Q_LLONG") == 0) + return QMetaType::LongLong; + if (strcmp(name, "Q_ULLONG") == 0) + return QMetaType::ULongLong; + if (strcmp(name, "QIconSet") == 0) + return QMetaType::QIcon; + + uint tp = QMetaType::type(name); + return tp < QMetaType::User ? tp : 0; +} + +/* + Returns true if the type is a QVariant types. +*/ +bool isVariantType(const char* type) +{ + return qvariant_nameToType(type) != 0; +} + +// copied from qmetaobject.cpp +// do not touch without touching the moc as well +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Dynamic = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; + int flags; +}; + +static inline const QMetaObjectPrivate *priv(const uint* data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } +// end of copied lines from qmetaobject.cpp + +class QMetaMethodBuilderPrivate +{ +public: + QMetaMethodBuilderPrivate + (QMetaMethod::MethodType _methodType, + const QByteArray& _signature, + const QByteArray& _returnType = QByteArray(), + QMetaMethod::Access _access = QMetaMethod::Public) + : signature(QMetaObject::normalizedSignature(_signature.constData())), + returnType(QMetaObject::normalizedType(_returnType)), + attributes(((int)_access) | (((int)_methodType) << 2)) + { + } + + QByteArray signature; + QByteArray returnType; + QList<QByteArray> parameterNames; + QByteArray tag; + int attributes; + + QMetaMethod::MethodType methodType() const + { + return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2); + } + + QMetaMethod::Access access() const + { + return (QMetaMethod::Access)(attributes & AccessMask); + } + + void setAccess(QMetaMethod::Access value) + { + attributes = ((attributes & ~AccessMask) | (int)value); + } +}; + +class QMetaPropertyBuilderPrivate +{ +public: + QMetaPropertyBuilderPrivate + (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1) + : name(_name), + type(QMetaObject::normalizedType(_type.constData())), + flags(Readable | Writable), notifySignal(-1) + { + if (notifierIdx >= 0) { + flags |= Notify; + notifySignal = notifierIdx; + } + } + + QByteArray name; + QByteArray type; + int flags; + int notifySignal; + + bool flag(int f) const + { + return ((flags & f) != 0); + } + + void setFlag(int f, bool value) + { + if (value) + flags |= f; + else + flags &= ~f; + } +}; + +class QMetaEnumBuilderPrivate +{ +public: + QMetaEnumBuilderPrivate(const QByteArray& _name) + : name(_name), isFlag(false) + { + } + + QByteArray name; + bool isFlag; + QList<QByteArray> keys; + QList<int> values; +}; + +class QMetaObjectBuilderPrivate +{ +public: + QMetaObjectBuilderPrivate() + : flags(0) + { + superClass = &QObject::staticMetaObject; + staticMetacallFunction = 0; + } + + QByteArray className; + const QMetaObject *superClass; + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction; + QList<QMetaMethodBuilderPrivate> methods; + QList<QMetaMethodBuilderPrivate> constructors; + QList<QMetaPropertyBuilderPrivate> properties; + QList<QByteArray> classInfoNames; + QList<QByteArray> classInfoValues; + QList<QMetaEnumBuilderPrivate> enumerators; +#ifdef Q_NO_DATA_RELOCATION + QList<QMetaObjectAccessor> relatedMetaObjects; +#else + QList<const QMetaObject *> relatedMetaObjects; +#endif + int flags; +}; + +/*! + Constructs a new QMetaObjectBuilder. +*/ +QMetaObjectBuilder::QMetaObjectBuilder() +{ + d = new QMetaObjectBuilderPrivate(); +} + +/*! + Constructs a new QMetaObjectBuilder which is a copy of the + meta object information in \a prototype. Note: the super class + contents for \a prototype are not copied, only the immediate + class that is defined by \a prototype. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. + + \sa addMetaObject() +*/ +QMetaObjectBuilder::QMetaObjectBuilder + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + d = new QMetaObjectBuilderPrivate(); + addMetaObject(prototype, members); +} + +/*! + Destroys this meta object builder. +*/ +QMetaObjectBuilder::~QMetaObjectBuilder() +{ + delete d; +} + +/*! + Returns the name of the class being constructed by this + meta object builder. The default value is an empty QByteArray. + + \sa setClassName(), superClass() +*/ +QByteArray QMetaObjectBuilder::className() const +{ + return d->className; +} + +/*! + Sets the \a name of the class being constructed by this + meta object builder. + + \sa className(), setSuperClass() +*/ +void QMetaObjectBuilder::setClassName(const QByteArray& name) +{ + d->className = name; +} + +/*! + Returns the superclass meta object of the class being constructed + by this meta object builder. The default value is the meta object + for QObject. + + \sa setSuperClass(), className() +*/ +const QMetaObject *QMetaObjectBuilder::superClass() const +{ + return d->superClass; +} + +/*! + Sets the superclass meta object of the class being constructed + by this meta object builder to \a meta. The \a meta parameter + must not be null. + + \sa superClass(), setClassName() +*/ +void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta) +{ + Q_ASSERT(meta); + d->superClass = meta; +} + +/*! + Returns the flags of the class being constructed by this meta object + builder. + + \sa setFlags() +*/ +QMetaObjectBuilder::MetaObjectFlags QMetaObjectBuilder::flags() const +{ + return (QMetaObjectBuilder::MetaObjectFlags)d->flags; +} + +/*! + Sets the \a flags of the class being constructed by this meta object + builder. + + \sa flags() +*/ +void QMetaObjectBuilder::setFlags(MetaObjectFlags flags) +{ + d->flags = flags; +} + +/*! + Returns the number of methods in this class, excluding the number + of methods in the base class. These include signals and slots + as well as normal member functions. + + \sa addMethod(), method(), removeMethod(), indexOfMethod() +*/ +int QMetaObjectBuilder::methodCount() const +{ + return d->methods.size(); +} + +/*! + Returns the number of constructors in this class. + + \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor() +*/ +int QMetaObjectBuilder::constructorCount() const +{ + return d->constructors.size(); +} + +/*! + Returns the number of properties in this class, excluding the number + of properties in the base class. + + \sa addProperty(), property(), removeProperty(), indexOfProperty() +*/ +int QMetaObjectBuilder::propertyCount() const +{ + return d->properties.size(); +} + +/*! + Returns the number of enumerators in this class, excluding the + number of enumerators in the base class. + + \sa addEnumerator(), enumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +int QMetaObjectBuilder::enumeratorCount() const +{ + return d->enumerators.size(); +} + +/*! + Returns the number of items of class information in this class, + exclusing the number of items of class information in the base class. + + \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::classInfoCount() const +{ + return d->classInfoNames.size(); +} + +/*! + Returns the number of related meta objects that are associated + with this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa addRelatedMetaObject(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +int QMetaObjectBuilder::relatedMetaObjectCount() const +{ + return d->relatedMetaObjects.size(); +} + +/*! + Adds a new public method to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the method. The \a signature will be normalized before it is + added to the class. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class with the specified + \a signature and \a returnType. Returns an object that can be + used to adjust the other attributes of the method. The \a signature + and \a returnType will be normalized before they are added to + the class. If \a returnType is empty, then it indicates that + the method has \c{void} as its return type. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod + (const QByteArray& signature, const QByteArray& returnType) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Method, signature, returnType)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class that has the same information as + \a prototype. This is used to clone the methods of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the method. + + This function will detect if \a prototype is an ordinary method, + signal, slot, or constructor and act accordingly. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype) +{ + QMetaMethodBuilder method; + if (prototype.methodType() == QMetaMethod::Method) + method = addMethod(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Signal) + method = addSignal(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Slot) + method = addSlot(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Constructor) + method = addConstructor(prototype.signature()); + method.setReturnType(prototype.typeName()); + method.setParameterNames(prototype.parameterNames()); + method.setTag(prototype.tag()); + method.setAccess(prototype.access()); + method.setAttributes(prototype.attributes()); + return method; +} + +/*! + Adds a new public slot to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the slot. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSignal(), indexOfSlot() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new signal to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the signal. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSlot(), indexOfSignal() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new constructor to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the constructor. The \a signature will be normalized before it is + added to the class. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature) +{ + int index = d->constructors.size(); + d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature)); + return QMetaMethodBuilder(this, -(index + 1)); +} + +/*! + Adds a new constructor to this class that has the same information as + \a prototype. This is used to clone the constructors of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the constructor. + + This function requires that \a prototype be a constructor. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype) +{ + Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor); + QMetaMethodBuilder ctor = addConstructor(prototype.signature()); + ctor.setReturnType(prototype.typeName()); + ctor.setParameterNames(prototype.parameterNames()); + ctor.setTag(prototype.tag()); + ctor.setAccess(prototype.access()); + ctor.setAttributes(prototype.attributes()); + return ctor; +} + +/*! + Adds a new readable/writable property to this class with the + specified \a name and \a type. Returns an object that can be used + to adjust the other attributes of the property. The \a type will + be normalized before it is added to the class. \a notifierId will + be registered as the property's \e notify signal. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty + (const QByteArray& name, const QByteArray& type, int notifierId) +{ + int index = d->properties.size(); + d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId)); + return QMetaPropertyBuilder(this, index); +} + +/*! + Adds a new property to this class that has the same information as + \a prototype. This is used to clone the properties of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the property. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype) +{ + QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName()); + property.setReadable(prototype.isReadable()); + property.setWritable(prototype.isWritable()); + property.setResettable(prototype.isResettable()); + property.setDesignable(prototype.isDesignable()); + property.setScriptable(prototype.isScriptable()); + property.setStored(prototype.isStored()); + property.setEditable(prototype.isEditable()); + property.setUser(prototype.isUser()); + property.setStdCppSet(prototype.hasStdCppSet()); + property.setEnumOrFlag(prototype.isEnumType()); + if (prototype.hasNotifySignal()) { + // Find an existing method for the notify signal, or add a new one. + QMetaMethod method = prototype.notifySignal(); + int index = indexOfMethod(method.signature()); + if (index == -1) + index = addMethod(method).index(); + d->properties[property._index].notifySignal = index; + d->properties[property._index].setFlag(Notify, true); + } + return property; +} + +/*! + Adds a new enumerator to this class with the specified + \a name. Returns an object that can be used to adjust + the other attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name) +{ + int index = d->enumerators.size(); + d->enumerators.append(QMetaEnumBuilderPrivate(name)); + return QMetaEnumBuilder(this, index); +} + +/*! + Adds a new enumerator to this class that has the same information as + \a prototype. This is used to clone the enumerators of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype) +{ + QMetaEnumBuilder en = addEnumerator(prototype.name()); + en.setIsFlag(prototype.isFlag()); + int count = prototype.keyCount(); + for (int index = 0; index < count; ++index) + en.addKey(prototype.key(index), prototype.value(index)); + return en; +} + +/*! + Adds \a name and \a value as an item of class information to this class. + Returns the index of the new item of class information. + + \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value) +{ + int index = d->classInfoNames.size(); + d->classInfoNames += name; + d->classInfoValues += value; + return index; +} + +/*! + Adds \a meta to this class as a related meta object. Returns + the index of the new related meta object entry. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +#ifdef Q_NO_DATA_RELOCATION +int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObjectAccessor &meta) +#else +int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta) +#endif +{ + Q_ASSERT(meta); + int index = d->relatedMetaObjects.size(); + d->relatedMetaObjects.append(meta); + return index; +} + +/*! + Adds the contents of \a prototype to this meta object builder. + This function is useful for cloning the contents of an existing QMetaObject. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. +*/ +void QMetaObjectBuilder::addMetaObject + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + Q_ASSERT(prototype); + int index; + + if ((members & ClassName) != 0) + d->className = prototype->className(); + + if ((members & SuperClass) != 0) + d->superClass = prototype->superClass(); + + if ((members & (Methods | Signals | Slots)) != 0) { + for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) { + QMetaMethod method = prototype->method(index); + if (method.methodType() != QMetaMethod::Signal) { + if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0) + continue; + if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0) + continue; + if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0) + continue; + } + if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Signal && + (members & Signals) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Slot && + (members & Slots) != 0) { + addMethod(method); + } + } + } + + if ((members & Constructors) != 0) { + for (index = 0; index < prototype->constructorCount(); ++index) + addConstructor(prototype->constructor(index)); + } + + if ((members & Properties) != 0) { + for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index) + addProperty(prototype->property(index)); + } + + if ((members & Enumerators) != 0) { + for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index) + addEnumerator(prototype->enumerator(index)); + } + + if ((members & ClassInfos) != 0) { + for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) { + QMetaClassInfo ci = prototype->classInfo(index); + addClassInfo(ci.name(), ci.value()); + } + } + + if ((members & RelatedMetaObjects) != 0) { +#ifdef Q_NO_DATA_RELOCATION + const QMetaObjectAccessor *objects = 0; +#else + const QMetaObject **objects; + if (priv(prototype->d.data)->revision < 2) { + objects = (const QMetaObject **)(prototype->d.extradata); + } else +#endif + { + const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra) + objects = extra->objects; + else + objects = 0; + } + if (objects) { + while (*objects != 0) { + addRelatedMetaObject(*objects); + ++objects; + } + } + } + + if ((members & StaticMetacall) != 0) { + if (priv(prototype->d.data)->revision >= 2) { + const QMetaObjectExtraData *extra = + (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra && extra->static_metacall) + setStaticMetacallFunction(extra->static_metacall); + } + } +} + +/*! + Returns the method at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::method(int index) const +{ + if (index >= 0 && index < d->methods.size()) + return QMetaMethodBuilder(this, index); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the constructor at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const +{ + if (index >= 0 && index < d->constructors.size()) + return QMetaMethodBuilder(this, -(index + 1)); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the property at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const +{ + if (index >= 0 && index < d->properties.size()) + return QMetaPropertyBuilder(this, index); + else + return QMetaPropertyBuilder(); +} + +/*! + Returns the enumerator at \a index in this class. + + \sa enumeratorCount(), addEnumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const +{ + if (index >= 0 && index < d->enumerators.size()) + return QMetaEnumBuilder(this, index); + else + return QMetaEnumBuilder(); +} + +/*! + Returns the related meta object at \a index in this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa removeRelatedMetaObject() +*/ +const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) +#ifdef Q_NO_DATA_RELOCATION + return &((*(d->relatedMetaObjects[index]))()); +#else + return d->relatedMetaObjects[index]; +#endif + else + return 0; +} + +/*! + Returns the name of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoName(int index) const +{ + if (index >= 0 && index < d->classInfoNames.size()) + return d->classInfoNames[index]; + else + return QByteArray(); +} + +/*! + Returns the value of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoValue(int index) const +{ + if (index >= 0 && index < d->classInfoValues.size()) + return d->classInfoValues[index]; + else + return QByteArray(); +} + +/*! + Removes the method at \a index from this class. The indices of + all following methods will be adjusted downwards by 1. If the + method is registered as a notify signal on a property, then the + notify signal will be removed from the property. + + \sa methodCount(), addMethod(), method(), indexOfMethod() +*/ +void QMetaObjectBuilder::removeMethod(int index) +{ + if (index >= 0 && index < d->methods.size()) { + d->methods.removeAt(index); + for (int prop = 0; prop < d->properties.size(); ++prop) { + // Adjust the indices of property notify signal references. + if (d->properties[prop].notifySignal == index) { + d->properties[prop].notifySignal = -1; + d->properties[prop].setFlag(Notify, false); + } else if (d->properties[prop].notifySignal > index) + (d->properties[prop].notifySignal)--; + } + } +} + +/*! + Removes the constructor at \a index from this class. The indices of + all following constructors will be adjusted downwards by 1. + + \sa constructorCount(), addConstructor(), constructor() + \sa indexOfConstructor() +*/ +void QMetaObjectBuilder::removeConstructor(int index) +{ + if (index >= 0 && index < d->constructors.size()) + d->constructors.removeAt(index); +} + +/*! + Removes the property at \a index from this class. The indices of + all following properties will be adjusted downwards by 1. + + \sa propertyCount(), addProperty(), property(), indexOfProperty() +*/ +void QMetaObjectBuilder::removeProperty(int index) +{ + if (index >= 0 && index < d->properties.size()) + d->properties.removeAt(index); +} + +/*! + Removes the enumerator at \a index from this class. The indices of + all following enumerators will be adjusted downwards by 1. + + \sa enumertorCount(), addEnumerator(), enumerator() + \sa indexOfEnumerator() +*/ +void QMetaObjectBuilder::removeEnumerator(int index) +{ + if (index >= 0 && index < d->enumerators.size()) + d->enumerators.removeAt(index); +} + +/*! + Removes the item of class information at \a index from this class. + The indices of all following items will be adjusted downwards by 1. + + \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue() + \sa indexOfClassInfo() +*/ +void QMetaObjectBuilder::removeClassInfo(int index) +{ + if (index >= 0 && index < d->classInfoNames.size()) { + d->classInfoNames.removeAt(index); + d->classInfoValues.removeAt(index); + } +} + +/*! + Removes the related meta object at \a index from this class. + The indices of all following related meta objects will be adjusted + downwards by 1. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa relatedMetaObject() +*/ +void QMetaObjectBuilder::removeRelatedMetaObject(int index) +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) + d->relatedMetaObjects.removeAt(index); +} + +/*! + Finds a method with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa method(), methodCount(), addMethod(), removeMethod() +*/ +int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature) + return index; + } + return -1; +} + +/*! + Finds a signal with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSlot() +*/ +int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Signal) + return index; + } + return -1; +} + +/*! + Finds a slot with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSignal() +*/ +int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Slot) + return index; + } + return -1; +} + +/*! + Finds a constructor with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa constructor(), constructorCount(), addConstructor(), removeConstructor() +*/ +int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->constructors.size(); ++index) { + if (sig == d->constructors[index].signature) + return index; + } + return -1; +} + +/*! + Finds a property with the specified \a name and returns its index; + otherwise returns -1. + + \sa property(), propertyCount(), addProperty(), removeProperty() +*/ +int QMetaObjectBuilder::indexOfProperty(const QByteArray& name) +{ + for (int index = 0; index < d->properties.size(); ++index) { + if (name == d->properties[index].name) + return index; + } + return -1; +} + +/*! + Finds an enumerator with the specified \a name and returns its index; + otherwise returns -1. + + \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator() +*/ +int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name) +{ + for (int index = 0; index < d->enumerators.size(); ++index) { + if (name == d->enumerators[index].name) + return index; + } + return -1; +} + +/*! + Finds an item of class information with the specified \a name and + returns its index; otherwise returns -1. + + \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo() + \sa removeClassInfo() +*/ +int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name) +{ + for (int index = 0; index < d->classInfoNames.size(); ++index) { + if (name == d->classInfoNames[index]) + return index; + } + return -1; +} + +// Align on a specific type boundary. +#define ALIGN(size,type) \ + (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1) + +// Build a string into a QMetaObject representation. Returns the +// position in the string table where the string was placed. +static int buildString + (char *buf, char *str, int *offset, const QByteArray& value, int empty) +{ + if (value.size() == 0 && empty >= 0) + return empty; + if (buf) { + memcpy(str + *offset, value.constData(), value.size()); + str[*offset + value.size()] = '\0'; + } + int posn = *offset; + *offset += value.size() + 1; + return posn; +} + +// Build the parameter array string for a method. +static QByteArray buildParameterNames + (const QByteArray& signature, const QList<QByteArray>& parameterNames) +{ + // If the parameter name list is specified, then concatenate them. + if (!parameterNames.isEmpty()) { + QByteArray names; + bool first = true; + foreach (QByteArray name, parameterNames) { + if (first) + first = false; + else + names += (char)','; + names += name; + } + return names; + } + + // Count commas in the signature, excluding those inside template arguments. + int index = signature.indexOf('('); + if (index < 0) + return QByteArray(); + ++index; + if (index >= signature.size()) + return QByteArray(); + if (signature[index] == ')') + return QByteArray(); + int count = 1; + int brackets = 0; + while (index < signature.size() && signature[index] != ',') { + char ch = signature[index++]; + if (ch == '<') + ++brackets; + else if (ch == '>') + --brackets; + else if (ch == ',' && brackets <= 0) + ++count; + } + return QByteArray(count - 1, ','); +} + +// Build a QMetaObject in "buf" based on the information in "d". +// If "buf" is null, then return the number of bytes needed to +// build the QMetaObject. Returns -1 if the metaobject if +// relocatable is set, but the metaobject contains extradata. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, + bool relocatable) +{ + int size = 0; + int dataIndex; + int enumIndex; + int index; + bool hasNotifySignals = false; + + if (relocatable && + (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction)) + return -1; + + // Create the main QMetaObject structure at the start of the buffer. + QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf); + size += sizeof(QMetaObject); + ALIGN(size, int); + if (buf) { + if (!relocatable) meta->d.superdata = d->superClass; + meta->d.extradata = 0; + } + + // Populate the QMetaObjectPrivate structure. + QMetaObjectPrivate *pmeta + = reinterpret_cast<QMetaObjectPrivate *>(buf + size); + int pmetaSize = size; + dataIndex = 13; // Number of fields in the QMetaObjectPrivate. + for (index = 0; index < d->properties.size(); ++index) { + if (d->properties[index].notifySignal != -1) { + hasNotifySignals = true; + break; + } + } + if (buf) { + pmeta->revision = 3; + pmeta->flags = d->flags; + pmeta->className = 0; // Class name is always the first string. + + pmeta->classInfoCount = d->classInfoNames.size(); + pmeta->classInfoData = dataIndex; + dataIndex += 2 * d->classInfoNames.size(); + + pmeta->methodCount = d->methods.size(); + pmeta->methodData = dataIndex; + dataIndex += 5 * d->methods.size(); + + pmeta->propertyCount = d->properties.size(); + pmeta->propertyData = dataIndex; + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + + pmeta->enumeratorCount = d->enumerators.size(); + pmeta->enumeratorData = dataIndex; + dataIndex += 4 * d->enumerators.size(); + + pmeta->constructorCount = d->constructors.size(); + pmeta->constructorData = dataIndex; + dataIndex += 5 * d->constructors.size(); + } else { + dataIndex += 2 * d->classInfoNames.size(); + dataIndex += 5 * d->methods.size(); + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + dataIndex += 4 * d->enumerators.size(); + dataIndex += 5 * d->constructors.size(); + } + + // Allocate space for the enumerator key names and values. + enumIndex = dataIndex; + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + dataIndex += 2 * enumerator->keys.size(); + } + + // Zero terminator at the end of the data offset table. + ++dataIndex; + + // Find the start of the data and string tables. + int *data = reinterpret_cast<int *>(pmeta); + size += dataIndex * sizeof(int); + char *str = reinterpret_cast<char *>(buf + size); + if (buf) { + if (relocatable) { + meta->d.stringdata = reinterpret_cast<const char *>((intptr_t)size); + meta->d.data = reinterpret_cast<uint *>((intptr_t)pmetaSize); + } else { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast<uint *>(data); + } + } + + // Reset the current data position to just past the QMetaObjectPrivate. + dataIndex = 13; + + // Add the class name to the string table. + int offset = 0; + buildString(buf, str, &offset, d->className, -1); + + // Add a common empty string, which is used to indicate "void" + // method returns, empty tag strings, etc. + int empty = buildString(buf, str, &offset, QByteArray(), -1); + + // Output the class infos, + for (index = 0; index < d->classInfoNames.size(); ++index) { + int name = buildString(buf, str, &offset, d->classInfoNames[index], empty); + int value = buildString(buf, str, &offset, d->classInfoValues[index], empty); + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = value; + } + dataIndex += 2; + } + + // Output the methods in the class. + for (index = 0; index < d->methods.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // Output the properties in the class. + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + int name = buildString(buf, str, &offset, prop->name, empty); + int type = buildString(buf, str, &offset, prop->type, empty); + int flags = prop->flags; + + if (!isVariantType(prop->type)) { + flags |= EnumOrFlag; + } else { + flags |= qvariant_nameToType(prop->type) << 24; + } + + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = type; + data[dataIndex + 2] = flags; + } + dataIndex += 3; + } + if (hasNotifySignals) { + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + if (buf) { + if (prop->notifySignal != -1) + data[dataIndex] = prop->notifySignal; + else + data[dataIndex] = 0; + } + ++dataIndex; + } + } + + // Output the enumerators in the class. + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + int name = buildString(buf, str, &offset, enumerator->name, empty); + int isFlag = (int)(enumerator->isFlag); + int count = enumerator->keys.size(); + int enumOffset = enumIndex; + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = isFlag; + data[dataIndex + 2] = count; + data[dataIndex + 3] = enumOffset; + } + for (int key = 0; key < count; ++key) { + int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty); + if (buf) { + data[enumOffset++] = keyIndex; + data[enumOffset++] = enumerator->values[key]; + } + } + dataIndex += 4; + enumIndex += 2 * count; + } + + // Output the constructors in the class. + for (index = 0; index < d->constructors.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // One more empty string to act as a terminator. + buildString(buf, str, &offset, QByteArray(), -1); + size += offset; + + // Output the zero terminator in the data array. + if (buf) + data[enumIndex] = 0; + + // Create the extradata block if we need one. + if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) { + ALIGN(size, QMetaObject **); + ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction); + QMetaObjectExtraData *extra = + reinterpret_cast<QMetaObjectExtraData *>(buf + size); + size += sizeof(QMetaObjectExtraData); + ALIGN(size, QMetaObject *); +#ifdef Q_NO_DATA_RELOCATION + QMetaObjectAccessor *objects = + reinterpret_cast<QMetaObjectAccessor *>(buf + size); +#else + const QMetaObject **objects = + reinterpret_cast<const QMetaObject **>(buf + size); +#endif + if (buf) { + if (d->relatedMetaObjects.size() > 0) { + extra->objects = objects; + for (index = 0; index < d->relatedMetaObjects.size(); ++index) + objects[index] = d->relatedMetaObjects[index]; + objects[index] = 0; + } else { + extra->objects = 0; + } + extra->static_metacall = d->staticMetacallFunction; + meta->d.extradata = reinterpret_cast<void *>(extra); + } + if (d->relatedMetaObjects.size() > 0) + size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1); + } + + // Align the final size and return it. + ALIGN(size, void *); + return size; +} + +/*! + Converts this meta object builder into a concrete QMetaObject. + The return value should be deallocated using qFree() once it + is no longer needed. + + The returned meta object is a snapshot of the state of the + QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder + will not be reflected in previous meta objects returned by + this method. +*/ +QMetaObject *QMetaObjectBuilder::toMetaObject() const +{ + int size = buildMetaObject(d, 0, false); + char *buf = reinterpret_cast<char *>(qMalloc(size)); + buildMetaObject(d, buf, false); + return reinterpret_cast<QMetaObject *>(buf); +} + +/* + \internal + + Converts this meta object builder into relocatable data. This data can + be stored, copied and later passed to fromRelocatableData() to create a + concrete QMetaObject. + + The data is specific to the architecture on which it was created, but is not + specific to the process that created it. Not all meta object builder's can + be converted to data in this way. If \a ok is provided, it will be set to + true if the conversion succeeds, and false otherwise. If a + staticMetacallFunction() or any relatedMetaObject()'s are specified the + conversion to relocatable data will fail. +*/ +QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const +{ + int size = buildMetaObject(d, 0, true); + if (size == -1) { + if (ok) *ok = false; + return QByteArray(); + } + + QByteArray data; + data.resize(size); + char *buf = data.data(); + buildMetaObject(d, buf, true); + if (ok) *ok = true; + return data; +} + +/* + \internal + + Sets the \a data returned from toRelocatableData() onto a concrete + QMetaObject instance, \a output. As the meta object's super class is not + saved in the relocatable data, it must be passed as \a superClass. +*/ +void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output, + const QMetaObject *superclass, + const QByteArray &data) +{ + if (!output) + return; + + const char *buf = data.constData(); + const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf); + + intptr_t stringdataOffset = (intptr_t)dataMo->d.stringdata; + intptr_t dataOffset = (intptr_t)dataMo->d.data; + + output->d.superdata = superclass; + output->d.stringdata = buf + stringdataOffset; + output->d.data = reinterpret_cast<const uint *>(buf + dataOffset); +} + +/*! + \typedef QMetaObjectBuilder::StaticMetacallFunction + + Typedef for static metacall functions. The three parameters are + the call type value, the constructor index, and the + array of parameters. +*/ + +/*! + Returns the static metacall function to use to construct objects + of this class. The default value is null. + + \sa setStaticMetacallFunction() +*/ +QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const +{ + return d->staticMetacallFunction; +} + +/*! + Sets the static metacall function to use to construct objects + of this class to \a value. The default value is null. + + \sa staticMetacallFunction() +*/ +void QMetaObjectBuilder::setStaticMetacallFunction + (QMetaObjectBuilder::StaticMetacallFunction value) +{ + d->staticMetacallFunction = value; +} + +#ifndef QT_NO_DATASTREAM + +/*! + Serializes the contents of the meta object builder onto \a stream. + + \sa deserialize() +*/ +void QMetaObjectBuilder::serialize(QDataStream& stream) const +{ + int index; + + // Write the class and super class names. + stream << d->className; + if (d->superClass) + stream << QByteArray(d->superClass->className()); + else + stream << QByteArray(); + + // Write the counts for each type of class member. + stream << d->classInfoNames.size(); + stream << d->methods.size(); + stream << d->properties.size(); + stream << d->enumerators.size(); + stream << d->constructors.size(); + stream << d->relatedMetaObjects.size(); + + // Write the items of class information. + for (index = 0; index < d->classInfoNames.size(); ++index) { + stream << d->classInfoNames[index]; + stream << d->classInfoValues[index]; + } + + // Write the methods. + for (index = 0; index < d->methods.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the properties. + for (index = 0; index < d->properties.size(); ++index) { + const QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream << property->name; + stream << property->type; + stream << property->flags; + stream << property->notifySignal; + } + + // Write the enumerators. + for (index = 0; index < d->enumerators.size(); ++index) { + const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream << enumerator->name; + stream << enumerator->isFlag; + stream << enumerator->keys; + stream << enumerator->values; + } + + // Write the constructors. + for (index = 0; index < d->constructors.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the related meta objects. +#ifdef Q_NO_DATA_RELOCATION + //### What do we do here? +#else + for (index = 0; index < d->relatedMetaObjects.size(); ++index) { + const QMetaObject *meta = d->relatedMetaObjects[index]; + stream << QByteArray(meta->className()); + } +#endif + + // Add an extra empty QByteArray for additional data in future versions. + // This should help maintain backwards compatibility, allowing older + // versions to read newer data. + stream << QByteArray(); +} + +// Resolve a class name using the name reference map. +static const QMetaObject *resolveClassName + (const QMap<QByteArray, const QMetaObject *>& references, + const QByteArray& name) +{ + if (name == QByteArray("QObject")) + return &QObject::staticMetaObject; + else + return references.value(name, 0); +} + +/*! + Deserializes a meta object builder from \a stream into + this meta object builder. + + The \a references parameter specifies a mapping from class names + to QMetaObject instances for resolving the super class name and + related meta objects in the object that is deserialized. + The meta object for QObject is implicitly added to \a references + and does not need to be supplied. + + The QDataStream::status() value on \a stream will be set to + QDataStream::ReadCorruptData if the input data is corrupt. + The status will be set to QDataStream::ReadPastEnd if the + input was exhausted before the full meta object was read. + + \sa serialize() +*/ +void QMetaObjectBuilder::deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references) +{ + QByteArray name; + const QMetaObject *cl; + int index; + + // Clear all members in the builder to their default states. + d->className.clear(); + d->superClass = &QObject::staticMetaObject; + d->classInfoNames.clear(); + d->classInfoValues.clear(); + d->methods.clear(); + d->properties.clear(); + d->enumerators.clear(); + d->constructors.clear(); + d->relatedMetaObjects.clear(); + d->staticMetacallFunction = 0; + + // Read the class and super class names. + stream >> d->className; + stream >> name; + if (name.isEmpty()) { + d->superClass = 0; + } else if ((cl = resolveClassName(references, name)) != 0) { + d->superClass = cl; + } else { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the counts for each type of class member. + int classInfoCount, methodCount, propertyCount; + int enumeratorCount, constructorCount, relatedMetaObjectCount; + stream >> classInfoCount; + stream >> methodCount; + stream >> propertyCount; + stream >> enumeratorCount; + stream >> constructorCount; + stream >> relatedMetaObjectCount; + if (classInfoCount < 0 || methodCount < 0 || + propertyCount < 0 || enumeratorCount < 0 || + constructorCount < 0 || relatedMetaObjectCount < 0) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the items of class information. + for (index = 0; index < classInfoCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray value; + stream >> name; + stream >> value; + addClassInfo(name, value); + } + + // Read the member methods. + for (index = 0; index < methodCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addMethod(name); + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() == QMetaMethod::Constructor) { + // Cannot add a constructor in this set of methods. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the properties. + for (index = 0; index < propertyCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray type; + stream >> name; + stream >> type; + addProperty(name, type); + QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream >> property->flags; + stream >> property->notifySignal; + if (property->notifySignal < -1 || + property->notifySignal >= d->methods.size()) { + // Notify signal method index is out of range. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + if (property->notifySignal >= 0 && + d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) { + // Notify signal method index does not refer to a signal. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the enumerators. + for (index = 0; index < enumeratorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addEnumerator(name); + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream >> enumerator->isFlag; + stream >> enumerator->keys; + stream >> enumerator->values; + if (enumerator->keys.size() != enumerator->values.size()) { + // Mismatch between number of keys and number of values. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the constructor methods. + for (index = 0; index < constructorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addConstructor(name); + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() != QMetaMethod::Constructor) { + // The type must be Constructor. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the related meta objects. +#ifdef Q_NO_DATA_RELOCATION + //### What do we do here +#else + for (index = 0; index < relatedMetaObjectCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + cl = resolveClassName(references, name); + if (!cl) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + addRelatedMetaObject(cl); + } +#endif + + // Read the extra data block, which is reserved for future use. + stream >> name; +} + +#endif // !QT_NO_DATASTREAM + +/*! + \class QMetaMethodBuilder + \internal + \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder. +*/ + +QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const +{ + // Positive indices indicate methods, negative indices indicate constructors. + if (_mobj && _index >= 0 && _index < _mobj->d->methods.size()) + return &(_mobj->d->methods[_index]); + else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size()) + return &(_mobj->d->constructors[(-_index) - 1]); + else + return 0; +} + +/*! + \fn QMetaMethodBuilder::QMetaMethodBuilder() + \internal +*/ + +/*! + Returns the index of this method within its QMetaObjectBuilder. +*/ +int QMetaMethodBuilder::index() const +{ + if (_index >= 0) + return _index; // Method, signal, or slot + else + return (-_index) - 1; // Constructor +} + +/*! + Returns the type of this method (signal, slot, method, or constructor). +*/ +QMetaMethod::MethodType QMetaMethodBuilder::methodType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->methodType(); + else + return QMetaMethod::Method; +} + +/*! + Returns the signature of this method. + + \sa parameterNames(), returnType() +*/ +QByteArray QMetaMethodBuilder::signature() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->signature; + else + return QByteArray(); +} + +/*! + Returns the return type for this method; empty if the method's + return type is \c{void}. + + \sa setReturnType(), signature() +*/ +QByteArray QMetaMethodBuilder::returnType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->returnType; + else + return QByteArray(); +} + +/*! + Sets the return type for this method to \a value. If \a value + is empty, then the method's return type is \c{void}. The \a value + will be normalized before it is added to the method. + + \sa returnType(), signature() +*/ +void QMetaMethodBuilder::setReturnType(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->returnType = QMetaObject::normalizedType(value); +} + +/*! + Returns the list of parameter names for this method. + + \sa setParameterNames() +*/ +QList<QByteArray> QMetaMethodBuilder::parameterNames() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->parameterNames; + else + return QList<QByteArray>(); +} + +/*! + Sets the list of parameter names for this method to \a value. + + \sa parameterNames() +*/ +void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->parameterNames = value; +} + +/*! + Returns the tag associated with this method. + + \sa setTag() +*/ +QByteArray QMetaMethodBuilder::tag() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->tag; + else + return QByteArray(); +} + +/*! + Sets the tag associated with this method to \a value. + + \sa setTag() +*/ +void QMetaMethodBuilder::setTag(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->tag = value; +} + +/*! + Returns the access specification of this method (private, protected, + or public). The default value is QMetaMethod::Public for methods, + slots, and constructors. The default value is QMetaMethod::Protected + for signals. + + \sa setAccess() +*/ +QMetaMethod::Access QMetaMethodBuilder::access() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->access(); + else + return QMetaMethod::Public; +} + +/*! + Sets the access specification of this method (private, protected, + or public) to \a value. If the method is a signal, this function + will be ignored. + + \sa access() +*/ +void QMetaMethodBuilder::setAccess(QMetaMethod::Access value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d && d->methodType() != QMetaMethod::Signal) + d->setAccess(value); +} + +/*! + Returns the additional attributes for this method. + + \sa setAttributes() +*/ +int QMetaMethodBuilder::attributes() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return (d->attributes >> 4); + else + return 0; +} + +/*! + Sets the additional attributes for this method to \a value. + + \sa attributes() +*/ +void QMetaMethodBuilder::setAttributes(int value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->attributes = ((d->attributes & 0x0f) | (value << 4)); +} + +/*! + \class QMetaPropertyBuilder + \internal + \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder. +*/ + +QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->properties.size()) + return &(_mobj->d->properties[_index]); + else + return 0; +} + +/*! + \fn QMetaPropertyBuilder::QMetaPropertyBuilder() + \internal +*/ + +/*! + \fn int QMetaPropertyBuilder::index() const + + Returns the index of this property within its QMetaObjectBuilder. +*/ + +/*! + Returns the name associated with this property. + + \sa type() +*/ +QByteArray QMetaPropertyBuilder::name() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns the type associated with this property. + + \sa name() +*/ +QByteArray QMetaPropertyBuilder::type() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->type; + else + return QByteArray(); +} + +/*! + Returns true if this property has a notify signal; false otherwise. + + \sa notifySignal(), setNotifySignal(), removeNotifySignal() +*/ +bool QMetaPropertyBuilder::hasNotifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Notify); + else + return false; +} + +/*! + Returns the notify signal associated with this property. + + \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal() +*/ +QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d && d->notifySignal >= 0) + return QMetaMethodBuilder(_mobj, d->notifySignal); + else + return QMetaMethodBuilder(); +} + +/*! + Sets the notify signal associated with this property to \a value. + + \sa hasNotifySignal(), notifySignal(), removeNotifySignal() +*/ +void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + if (value._mobj) { + d->notifySignal = value._index; + d->setFlag(Notify, true); + } else { + d->notifySignal = -1; + d->setFlag(Notify, false); + } + } +} + +/*! + Removes the notify signal from this property. + + \sa hasNotifySignal(), notifySignal(), setNotifySignal() +*/ +void QMetaPropertyBuilder::removeNotifySignal() +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + d->notifySignal = -1; + d->setFlag(Notify, false); + } +} + +/*! + Returns true if this property is readable; otherwise returns false. + The default value is true. + + \sa setReadable(), isWritable() +*/ +bool QMetaPropertyBuilder::isReadable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Readable); + else + return false; +} + +/*! + Returns true if this property is writable; otherwise returns false. + The default value is true. + + \sa setWritable(), isReadable() +*/ +bool QMetaPropertyBuilder::isWritable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Writable); + else + return false; +} + +/*! + Returns true if this property can be reset to a default value; otherwise + returns false. The default value is false. + + \sa setResettable() +*/ +bool QMetaPropertyBuilder::isResettable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Resettable); + else + return false; +} + +/*! + Returns true if this property is designable; otherwise returns false. + This default value is false. + + \sa setDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isDesignable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Designable); + else + return false; +} + +/*! + Returns true if the property is scriptable; otherwise returns false. + This default value is false. + + \sa setScriptable(), isDesignable(), isStored() +*/ +bool QMetaPropertyBuilder::isScriptable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Scriptable); + else + return false; +} + +/*! + Returns true if the property is stored; otherwise returns false. + This default value is false. + + \sa setStored(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isStored() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Stored); + else + return false; +} + +/*! + Returns true if the property is editable; otherwise returns false. + This default value is false. + + \sa setEditable(), isDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isEditable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Editable); + else + return false; +} + +/*! + Returns true if this property is designated as the \c USER + property, i.e., the one that the user can edit or that is + significant in some other way. Otherwise it returns + false. This default value is false. + + \sa setUser(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isUser() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(User); + else + return false; +} + +/*! + Returns true if the property has a C++ setter function that + follows Qt's standard "name" / "setName" pattern. Designer and uic + query hasStdCppSet() in order to avoid expensive + QObject::setProperty() calls. All properties in Qt [should] follow + this pattern. The default value is false. + + \sa setStdCppSet() +*/ +bool QMetaPropertyBuilder::hasStdCppSet() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(StdCppSet); + else + return false; +} + +/*! + Returns true if the property is an enumerator or flag type; + otherwise returns false. This default value is false. + + \sa setEnumOrFlag() +*/ +bool QMetaPropertyBuilder::isEnumOrFlag() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(EnumOrFlag); + else + return false; +} + +/*! + Returns true if the property has the dynamic flag set; + otherwise returns false. The default value is false. + + \sa setDynamic() +*/ +bool QMetaPropertyBuilder::isDynamic() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Dynamic); + else + return false; +} + +/*! + Sets this property to readable if \a value is true. + + \sa isReadable(), setWritable() +*/ +void QMetaPropertyBuilder::setReadable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Readable, value); +} + +/*! + Sets this property to writable if \a value is true. + + \sa isWritable(), setReadable() +*/ +void QMetaPropertyBuilder::setWritable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Writable, value); +} + +/*! + Sets this property to resettable if \a value is true. + + \sa isResettable() +*/ +void QMetaPropertyBuilder::setResettable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Resettable, value); +} + +/*! + Sets this property to designable if \a value is true. + + \sa isDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setDesignable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Designable, value); +} + +/*! + Sets this property to scriptable if \a value is true. + + \sa isScriptable(), setDesignable(), setStored() +*/ +void QMetaPropertyBuilder::setScriptable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Scriptable, value); +} + +/*! + Sets this property to storable if \a value is true. + + \sa isStored(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setStored(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Stored, value); +} + +/*! + Sets this property to editable if \a value is true. + + \sa isEditable(), setDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setEditable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Editable, value); +} + +/*! + Sets the \c USER flag on this property to \a value. + + \sa isUser(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setUser(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(User, value); +} + +/*! + Sets the C++ setter flag on this property to \a value, which is + true if the property has a C++ setter function that follows Qt's + standard "name" / "setName" pattern. + + \sa hasStdCppSet() +*/ +void QMetaPropertyBuilder::setStdCppSet(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(StdCppSet, value); +} + +/*! + Sets this property to be of an enumerator or flag type if + \a value is true. + + \sa isEnumOrFlag() +*/ +void QMetaPropertyBuilder::setEnumOrFlag(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(EnumOrFlag, value); +} + +/*! + Sets this property to have the dynamic flag if \a value is + true. + + \sa isDynamic() +*/ +void QMetaPropertyBuilder::setDynamic(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Dynamic, value); +} + +/*! + \class QMetaEnumBuilder + \internal + \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder. +*/ + +QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size()) + return &(_mobj->d->enumerators[_index]); + else + return 0; +} + +/*! + \fn QMetaEnumBuilder::QMetaEnumBuilder() + \internal +*/ + +/*! + \fn int QMetaEnumBuilder::index() const + + Returns the index of this enumerator within its QMetaObjectBuilder. +*/ + +/*! + Returns the name of the enumerator (without the scope). +*/ +QByteArray QMetaEnumBuilder::name() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns true if this enumerator is used as a flag; otherwise returns + false. + + \sa setIsFlag() +*/ +bool QMetaEnumBuilder::isFlag() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->isFlag; + else + return false; +} + +/*! + Sets this enumerator to be used as a flag if \a value is true. + + \sa isFlag() +*/ +void QMetaEnumBuilder::setIsFlag(bool value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + d->isFlag = value; +} + +/*! + Returns the number of keys. + + \sa key(), addKey() +*/ +int QMetaEnumBuilder::keyCount() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->keys.size(); + else + return 0; +} + +/*! + Returns the key with the given \a index, or an empty QByteArray + if no such key exists. + + \sa keyCount(), addKey(), value() +*/ +QByteArray QMetaEnumBuilder::key(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->keys[index]; + else + return QByteArray(); +} + +/*! + Returns the value with the given \a index; or returns -1 if there + is no such value. + + \sa keyCount(), addKey(), key() +*/ +int QMetaEnumBuilder::value(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->values[index]; + else + return -1; +} + +/*! + Adds a new key called \a name to this enumerator, associated + with \a value. Returns the index of the new key. + + \sa keyCount(), key(), value(), removeKey() +*/ +int QMetaEnumBuilder::addKey(const QByteArray& name, int value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) { + int index = d->keys.size(); + d->keys += name; + d->values += value; + return index; + } else { + return -1; + } +} + +/*! + Removes the key at \a index from this enumerator. + + \sa addKey() +*/ +void QMetaEnumBuilder::removeKey(int index) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) { + d->keys.removeAt(index); + d->values.removeAt(index); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h new file mode 100644 index 0000000..3eff4ff --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder_p.h @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETAOBJECTBUILDER_H +#define QMETAOBJECTBUILDER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qmap.h> + +QT_BEGIN_NAMESPACE + +class QMetaObjectBuilderPrivate; +class QMetaMethodBuilder; +class QMetaMethodBuilderPrivate; +class QMetaPropertyBuilder; +class QMetaPropertyBuilderPrivate; +class QMetaEnumBuilder; +class QMetaEnumBuilderPrivate; + +class Q_DECLARATIVE_EXPORT QMetaObjectBuilder +{ +public: + enum AddMember + { + ClassName = 0x00000001, + SuperClass = 0x00000002, + Methods = 0x00000004, + Signals = 0x00000008, + Slots = 0x00000010, + Constructors = 0x00000020, + Properties = 0x00000040, + Enumerators = 0x00000080, + ClassInfos = 0x00000100, + RelatedMetaObjects = 0x00000200, + StaticMetacall = 0x00000400, + PublicMethods = 0x00000800, + ProtectedMethods = 0x00001000, + PrivateMethods = 0x00002000, + AllMembers = 0x7FFFFFFF, + AllPrimaryMembers = 0x7FFFFBFC + }; + Q_DECLARE_FLAGS(AddMembers, AddMember) + + enum MetaObjectFlag { + DynamicMetaObject = 0x01 + }; + Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag) + + QMetaObjectBuilder(); + explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + virtual ~QMetaObjectBuilder(); + + QByteArray className() const; + void setClassName(const QByteArray& name); + + const QMetaObject *superClass() const; + void setSuperClass(const QMetaObject *meta); + + MetaObjectFlags flags() const; + void setFlags(MetaObjectFlags); + + int methodCount() const; + int constructorCount() const; + int propertyCount() const; + int enumeratorCount() const; + int classInfoCount() const; + int relatedMetaObjectCount() const; + + QMetaMethodBuilder addMethod(const QByteArray& signature); + QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType); + QMetaMethodBuilder addMethod(const QMetaMethod& prototype); + + QMetaMethodBuilder addSlot(const QByteArray& signature); + QMetaMethodBuilder addSignal(const QByteArray& signature); + + QMetaMethodBuilder addConstructor(const QByteArray& signature); + QMetaMethodBuilder addConstructor(const QMetaMethod& prototype); + + QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1); + QMetaPropertyBuilder addProperty(const QMetaProperty& prototype); + + QMetaEnumBuilder addEnumerator(const QByteArray& name); + QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype); + + int addClassInfo(const QByteArray& name, const QByteArray& value); + +#ifdef Q_NO_DATA_RELOCATION + int addRelatedMetaObject(const QMetaObjectAccessor &meta); +#else + int addRelatedMetaObject(const QMetaObject *meta); +#endif + + void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + + QMetaMethodBuilder method(int index) const; + QMetaMethodBuilder constructor(int index) const; + QMetaPropertyBuilder property(int index) const; + QMetaEnumBuilder enumerator(int index) const; + const QMetaObject *relatedMetaObject(int index) const; + + QByteArray classInfoName(int index) const; + QByteArray classInfoValue(int index) const; + + void removeMethod(int index); + void removeConstructor(int index); + void removeProperty(int index); + void removeEnumerator(int index); + void removeClassInfo(int index); + void removeRelatedMetaObject(int index); + + int indexOfMethod(const QByteArray& signature); + int indexOfSignal(const QByteArray& signature); + int indexOfSlot(const QByteArray& signature); + int indexOfConstructor(const QByteArray& signature); + int indexOfProperty(const QByteArray& name); + int indexOfEnumerator(const QByteArray& name); + int indexOfClassInfo(const QByteArray& name); + + typedef int (*StaticMetacallFunction)(QMetaObject::Call, int, void **); + + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const; + void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); + + QMetaObject *toMetaObject() const; + QByteArray toRelocatableData(bool * = 0) const; + static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &); + +#ifndef QT_NO_DATASTREAM + void serialize(QDataStream& stream) const; + void deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references); +#endif + +private: + Q_DISABLE_COPY(QMetaObjectBuilder) + + QMetaObjectBuilderPrivate *d; + + friend class QMetaMethodBuilder; + friend class QMetaPropertyBuilder; + friend class QMetaEnumBuilder; +}; + +class Q_DECLARATIVE_EXPORT QMetaMethodBuilder +{ +public: + QMetaMethodBuilder() : _mobj(0), _index(0) {} + + int index() const; + + QMetaMethod::MethodType methodType() const; + QByteArray signature() const; + + QByteArray returnType() const; + void setReturnType(const QByteArray& value); + + QList<QByteArray> parameterNames() const; + void setParameterNames(const QList<QByteArray>& value); + + QByteArray tag() const; + void setTag(const QByteArray& value); + + QMetaMethod::Access access() const; + void setAccess(QMetaMethod::Access value); + + int attributes() const; + void setAttributes(int value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + friend class QMetaPropertyBuilder; + + QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaMethodBuilderPrivate *d_func() const; +}; + +class Q_DECLARATIVE_EXPORT QMetaPropertyBuilder +{ +public: + QMetaPropertyBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + QByteArray type() const; + + bool hasNotifySignal() const; + QMetaMethodBuilder notifySignal() const; + void setNotifySignal(const QMetaMethodBuilder& value); + void removeNotifySignal(); + + bool isReadable() const; + bool isWritable() const; + bool isResettable() const; + bool isDesignable() const; + bool isScriptable() const; + bool isStored() const; + bool isEditable() const; + bool isUser() const; + bool hasStdCppSet() const; + bool isEnumOrFlag() const; + bool isDynamic() const; + + void setReadable(bool value); + void setWritable(bool value); + void setResettable(bool value); + void setDesignable(bool value); + void setScriptable(bool value); + void setStored(bool value); + void setEditable(bool value); + void setUser(bool value); + void setStdCppSet(bool value); + void setEnumOrFlag(bool value); + void setDynamic(bool value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaPropertyBuilderPrivate *d_func() const; +}; + +class Q_DECLARATIVE_EXPORT QMetaEnumBuilder +{ +public: + QMetaEnumBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + + bool isFlag() const; + void setIsFlag(bool value); + + int keyCount() const; + QByteArray key(int index) const; + int value(int index) const; + + int addKey(const QByteArray& name, int value); + void removeKey(int index); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaEnumBuilderPrivate *d_func() const; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers) +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags) + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h new file mode 100644 index 0000000..c009093 --- /dev/null +++ b/src/declarative/qml/qml.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QML_H +#define QML_H + +#include "qmlmetatype.h" +#include "qmlmetaproperty.h" +#include "qmlparserstatus.h" +#include "qmlpropertyvaluesource.h" +#include "qmllist.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qurl.h> +#include <QtCore/qmetaobject.h> + +QT_BEGIN_HEADER + +QT_MODULE(Declarative) + +#define QML_DECLARE_TYPE(TYPE) \ + Q_DECLARE_METATYPE(TYPE *) \ + Q_DECLARE_METATYPE(QList<TYPE *> *) \ + Q_DECLARE_METATYPE(QmlList<TYPE *> *) + +#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \ + Q_DECLARE_METATYPE(QList<TYPE *> *) \ + Q_DECLARE_METATYPE(QmlList<TYPE *> *) + +#define QML_DECLARE_INTERFACE(INTERFACE) \ + QML_DECLARE_TYPE(INTERFACE) + +#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \ + QML_DECLARE_TYPE_HASMETATYPE(INTERFACE) + +enum { /* TYPEINFO flags */ + QML_HAS_ATTACHED_PROPERTIES = 0x01, +}; + +#define QML_DECLARE_TYPEINFO(TYPE, FLAGS) \ +template <> \ +class QmlTypeInfo<TYPE > \ +{ \ +public: \ + enum { \ + hasAttachedProperties = (((FLAGS) & QML_HAS_ATTACHED_PROPERTIES) == QML_HAS_ATTACHED_PROPERTIES) \ + }; \ +}; + +QT_BEGIN_NAMESPACE + +#if defined(Q_OS_SYMBIAN) +#define QML_DEFINE_INTERFACE(INTERFACE) \ + static int defineInterface##INTERFACE = qmlRegisterInterface<INTERFACE>(#INTERFACE); + +#define QML_DEFINE_EXTENDED_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, EXTENSION) \ + static int registerExtended##TYPE = qmlRegisterExtendedType<TYPE,EXTENSION>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE); + +#define QML_DEFINE_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE) \ + static int defineType##TYPE = qmlRegisterType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE); + +#define QML_DEFINE_EXTENDED_NOCREATE_TYPE(TYPE, EXTENSION) \ + static int registerExtendedNoCreate##TYPE = qmlRegisterExtendedType<TYPE,EXTENSION>(#TYPE); + +#define QML_DEFINE_NOCREATE_TYPE(TYPE) \ + static int registerNoCreate##TYPE = qmlRegisterType<TYPE>(#TYPE); + +#else + +#define QML_DEFINE_INTERFACE(INTERFACE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<INTERFACE *,0,0>::instance(qmlRegisterInterface<INTERFACE>(#INTERFACE)); + +#define QML_DEFINE_EXTENDED_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN)>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE)); + +#define QML_DEFINE_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN)>::instance(qmlRegisterType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE)); + +#define QML_DEFINE_EXTENDED_NOCREATE_TYPE(TYPE, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,0,0>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#TYPE)); + +#define QML_DEFINE_NOCREATE_TYPE(TYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,0,0>::instance(qmlRegisterType<TYPE>(#TYPE)); + +#endif + +class QmlContext; +class QmlEngine; +Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); +Q_DECLARATIVE_EXPORT QmlContext *qmlContext(const QObject *); +Q_DECLARATIVE_EXPORT QmlEngine *qmlEngine(const QObject *); +Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); + +template<typename T> +QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) +{ + // ### is this threadsafe? + static int idx = -1; + + if (idx == -1) + idx = QmlMetaType::attachedPropertiesFuncId(&T::staticMetaObject); + + if (idx == -1 || !obj) + return 0; + + return qmlAttachedPropertiesObjectById(idx, obj, create); +} + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QObject) +Q_DECLARE_METATYPE(QVariant) + +QT_END_HEADER + +#endif // QML_H diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri new file mode 100644 index 0000000..cd2fbff --- /dev/null +++ b/src/declarative/qml/qml.pri @@ -0,0 +1,123 @@ +INCLUDEPATH += $$PWD +SOURCES += \ + $$PWD/qmlparser.cpp \ + $$PWD/qmlinstruction.cpp \ + $$PWD/qmlvmemetaobject.cpp \ + $$PWD/qmlengine.cpp \ + $$PWD/qmlexpression.cpp \ + $$PWD/qmlbinding.cpp \ + $$PWD/qmlmetaproperty.cpp \ + $$PWD/qmlmoduleplugin.cpp \ + $$PWD/qmlcomponent.cpp \ + $$PWD/qmlcontext.cpp \ + $$PWD/qmlcustomparser.cpp \ + $$PWD/qmlpropertyvaluesource.cpp \ + $$PWD/qmlpropertyvalueinterceptor.cpp \ + $$PWD/qmlproxymetaobject.cpp \ + $$PWD/qmlvme.cpp \ + $$PWD/qmlcompiler.cpp \ + $$PWD/qmlcompileddata.cpp \ + $$PWD/qmlboundsignal.cpp \ + $$PWD/qmldom.cpp \ + $$PWD/qmlrefcount.cpp \ + $$PWD/qmlprivate.cpp \ + $$PWD/qmlmetatype.cpp \ + $$PWD/qmlstringconverters.cpp \ + $$PWD/qmlclassfactory.cpp \ + $$PWD/qmlparserstatus.cpp \ + $$PWD/qmlcompositetypemanager.cpp \ + $$PWD/qmlinfo.cpp \ + $$PWD/qmlerror.cpp \ + $$PWD/qmlscriptparser.cpp \ + $$PWD/qmlenginedebug.cpp \ + $$PWD/qmlrewrite.cpp \ + $$PWD/qmlvaluetype.cpp \ + $$PWD/qmlcompiledbindings.cpp \ + $$PWD/qmlxmlhttprequest.cpp \ + $$PWD/qmlsqldatabase.cpp \ + $$PWD/qmetaobjectbuilder.cpp \ + $$PWD/qmlwatcher.cpp \ + $$PWD/qmlscript.cpp \ + $$PWD/qmlcleanup.cpp \ + $$PWD/qmlpropertycache.cpp \ + $$PWD/qmlintegercache.cpp \ + $$PWD/qmltypenamecache.cpp \ + $$PWD/qmlscriptstring.cpp \ + $$PWD/qmlobjectscriptclass.cpp \ + $$PWD/qmlcontextscriptclass.cpp \ + $$PWD/qmlglobalscriptclass.cpp \ + $$PWD/qmlvaluetypescriptclass.cpp \ + $$PWD/qmltypenamescriptclass.cpp \ + $$PWD/qmllistscriptclass.cpp \ + $$PWD/qmlworkerscript.cpp \ + $$PWD/qmlnetworkaccessmanagerfactory.cpp +HEADERS += \ + $$PWD/qmlparser_p.h \ + $$PWD/qmlglobal_p.h \ + $$PWD/qmlinstruction_p.h \ + $$PWD/qmlvmemetaobject_p.h \ + $$PWD/qml.h \ + $$PWD/qmlbinding.h \ + $$PWD/qmlbinding_p.h \ + $$PWD/qmlmetaproperty.h \ + $$PWD/qmlmoduleplugin.h \ + $$PWD/qmlcomponent.h \ + $$PWD/qmlcomponent_p.h \ + $$PWD/qmlcustomparser_p.h \ + $$PWD/qmlcustomparser_p_p.h \ + $$PWD/qmlpropertyvaluesource.h \ + $$PWD/qmlpropertyvalueinterceptor.h \ + $$PWD/qmlboundsignal_p.h \ + $$PWD/qmlparserstatus.h \ + $$PWD/qmlproxymetaobject_p.h \ + $$PWD/qmlvme_p.h \ + $$PWD/qmlcompiler_p.h \ + $$PWD/qmlengine_p.h \ + $$PWD/qmlexpression_p.h \ + $$PWD/qmlprivate.h \ + $$PWD/qmldom.h \ + $$PWD/qmldom_p.h \ + $$PWD/qmlrefcount_p.h \ + $$PWD/qmlmetatype.h \ + $$PWD/qmlengine.h \ + $$PWD/qmlcontext.h \ + $$PWD/qmlexpression.h \ + $$PWD/qmlstringconverters_p.h \ + $$PWD/qmlclassfactory_p.h \ + $$PWD/qmlinfo.h \ + $$PWD/qmlmetaproperty_p.h \ + $$PWD/qmlcontext_p.h \ + $$PWD/qmlcompositetypedata_p.h \ + $$PWD/qmlcompositetypemanager_p.h \ + $$PWD/qmllist.h \ + $$PWD/qmldeclarativedata_p.h \ + $$PWD/qmlerror.h \ + $$PWD/qmlscriptparser_p.h \ + $$PWD/qmlenginedebug_p.h \ + $$PWD/qmlrewrite_p.h \ + $$PWD/qpodvector_p.h \ + $$PWD/qbitfield_p.h \ + $$PWD/qmlvaluetype_p.h \ + $$PWD/qmlcompiledbindings_p.h \ + $$PWD/qmlxmlhttprequest_p.h \ + $$PWD/qmlsqldatabase_p.h \ + $$PWD/qmetaobjectbuilder_p.h \ + $$PWD/qmlwatcher_p.h \ + $$PWD/qmlcleanup_p.h \ + $$PWD/qmlpropertycache_p.h \ + $$PWD/qmlintegercache_p.h \ + $$PWD/qmltypenamecache_p.h \ + $$PWD/qmlscriptstring.h \ + $$PWD/qmlobjectscriptclass_p.h \ + $$PWD/qmlcontextscriptclass_p.h \ + $$PWD/qmlglobalscriptclass_p.h \ + $$PWD/qmlvaluetypescriptclass_p.h \ + $$PWD/qmltypenamescriptclass_p.h \ + $$PWD/qmllistscriptclass_p.h \ + $$PWD/qmlworkerscript_p.h \ + $$PWD/qmlscriptclass_p.h \ + $$PWD/qmlguard_p.h \ + $$PWD/qmlnetworkaccessmanagerfactory.h +QT += sql +include(parser/parser.pri) +include(rewriter/rewriter.pri) diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp new file mode 100644 index 0000000..3e29a3c --- /dev/null +++ b/src/declarative/qml/qmlbinding.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlbinding.h" +#include "qmlbinding_p.h" + +#include "qml.h" +#include "qmlcontext.h" +#include "qmlinfo.h" +#include "qmlcontext_p.h" +#include "qmldeclarativedata_p.h" +#include "qmlstringconverters_p.h" + +#include <qfxperf_p_p.h> + +#include <QVariant> +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +QML_DEFINE_NOCREATE_TYPE(QmlBinding); + +QmlBindingData::QmlBindingData() +: updating(false), enabled(false) +{ +} + +QmlBindingData::~QmlBindingData() +{ + removeError(); +} + +void QmlBindingData::refresh() +{ + if (enabled && !updating && q) { + QmlBinding *b = static_cast<QmlBinding *>(QmlExpressionPrivate::get(q)); + b->update(); + } +} + +QmlBindingPrivate::QmlBindingPrivate() +: QmlExpressionPrivate(new QmlBindingData) +{ +} + +QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, const QString &url, int lineNumber, QObject *parent) +: QmlExpression(ctxt, data, rc, obj, url, lineNumber, *new QmlBindingPrivate) +{ + setParent(parent); +} + +QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent) +: QmlExpression(ctxt, str, obj, *new QmlBindingPrivate) +{ + setParent(parent); +} + +QmlBinding::~QmlBinding() +{ +} + +void QmlBinding::setTarget(const QmlMetaProperty &prop) +{ + Q_D(QmlBinding); + d->bindingData()->property = prop; + + update(); +} + +QmlMetaProperty QmlBinding::property() const +{ + Q_D(const QmlBinding); + return d->bindingData()->property; +} + +void QmlBinding::update(QmlMetaProperty::WriteFlags flags) +{ + Q_D(QmlBinding); + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QmlPerfTimer<QmlPerf::BindableValueUpdate> bu; +#endif + QmlBindingData *data = d->bindingData(); + + if (!data->enabled) + return; + + data->addref(); + + if (!data->updating) { + data->updating = true; + + if (data->property.propertyCategory() == QmlMetaProperty::Bindable) { + + int idx = data->property.coreIndex(); + Q_ASSERT(idx != -1); + + + QmlBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(data->property.object(), + QMetaObject::WriteProperty, + idx, a); + + } else { + bool isUndefined = false; + QVariant value = this->value(&isUndefined); + + if (isUndefined && !data->error.isValid() && data->property.isResettable()) { + + data->property.reset(); + + } else if (isUndefined && !data->error.isValid()) { + + QUrl url = QUrl(data->url); + int line = data->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + data->error.setUrl(url); + data->error.setLine(line); + data->error.setColumn(-1); + data->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(data->property.propertyType()))); + + } else if (!isUndefined && data->property.object() && + !data->property.write(value, flags)) { + + QUrl url = QUrl(data->url); + int line = data->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + const char *valueType = 0; + if (value.userType() == QVariant::Invalid) valueType = "null"; + else valueType = QMetaType::typeName(value.userType()); + + data->error.setUrl(url); + data->error.setLine(line); + data->error.setColumn(-1); + data->error.setDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(QMetaType::typeName(data->property.propertyType()))); + } + + if (data->error.isValid()) { + QmlEnginePrivate *p = (data->context() && data->context()->engine())? + QmlEnginePrivate::get(data->context()->engine()):0; + if (!data->addError(p)) + qWarning().nospace() << qPrintable(this->error().toString()); + } else { + data->removeError(); + } + } + + data->updating = false; + } else { + qmlInfo(data->property.object()) << tr("Binding loop detected for property \"%1\"").arg(data->property.name()); + } + + data->release(); +} + +void QmlBinding::emitValueChanged() +{ + update(); + // don't bother calling valueChanged() +} + +void QmlBinding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +{ + Q_D(QmlBinding); + d->bindingData()->enabled = e; + setTrackChange(e); + + QmlAbstractBinding::setEnabled(e, flags); + + if (e) { + addToObject(d->bindingData()->property.object()); + update(flags); + } else { + removeFromObject(); + } +} + +int QmlBinding::propertyIndex() +{ + Q_D(QmlBinding); + return d->bindingData()->property.coreIndex(); +} + +bool QmlBinding::enabled() const +{ + Q_D(const QmlBinding); + + return d->bindingData()->enabled; +} + +QString QmlBinding::expression() const +{ + return QmlExpression::expression(); +} + +QmlAbstractBinding::QmlAbstractBinding() +: m_object(0), m_mePtr(0), m_prevBinding(0), m_nextBinding(0) +{ +} + +QmlAbstractBinding::~QmlAbstractBinding() +{ + removeFromObject(); + if (m_mePtr) + *m_mePtr = 0; +} + +void QmlAbstractBinding::destroy() +{ + delete this; +} + +void QmlAbstractBinding::addToObject(QObject *object) +{ + Q_ASSERT(object); + + removeFromObject(); + + Q_ASSERT(!m_prevBinding); + + QmlDeclarativeData *data = QmlDeclarativeData::get(object, true); + m_nextBinding = data->bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &data->bindings; + data->bindings = this; + m_object = object; + + data->setBindingBit(m_object, propertyIndex()); +} + +void QmlAbstractBinding::removeFromObject() +{ + if (m_prevBinding) { + Q_ASSERT(m_object); + + *m_prevBinding = m_nextBinding; + if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding; + m_prevBinding = 0; + m_nextBinding = 0; + + QmlDeclarativeData *data = QmlDeclarativeData::get(m_object, false); + if (data) data->clearBindingBit(propertyIndex()); + m_object = 0; + } +} + +QString QmlAbstractBinding::expression() const +{ + return QLatin1String("<Unknown>"); +} + +void QmlAbstractBinding::setEnabled(bool e, QmlMetaProperty::WriteFlags) +{ + if (e) m_mePtr = 0; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h new file mode 100644 index 0000000..cefb4fe --- /dev/null +++ b/src/declarative/qml/qmlbinding.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDING_H +#define QMLBINDING_H + +#include "qml.h" +#include "qmlpropertyvaluesource.h" +#include "qmlexpression.h" + +#include <QtCore/QObject> +#include <QtCore/QMetaProperty> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlAbstractBinding +{ +public: + QmlAbstractBinding(); + virtual ~QmlAbstractBinding(); + + virtual void destroy(); + + virtual QString expression() const; + + void setEnabled(bool e) { setEnabled(e, QmlMetaProperty::DontRemoveBinding); } + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags) = 0; + virtual int propertyIndex() = 0; + + void update() { update(QmlMetaProperty::DontRemoveBinding); } + virtual void update(QmlMetaProperty::WriteFlags) = 0; + + void addToObject(QObject *); + void removeFromObject(); + +private: + friend class QmlDeclarativeData; + friend class QmlMetaProperty; + friend class QmlMetaPropertyPrivate; + friend class QmlVME; + + QObject *m_object; + QmlAbstractBinding **m_mePtr; + QmlAbstractBinding **m_prevBinding; + QmlAbstractBinding *m_nextBinding; +}; + +class QmlContext; +class QmlBindingPrivate; +class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression, + public QmlAbstractBinding +{ +Q_OBJECT +public: + QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0); + QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, const QString &, int, + QObject *parent); + ~QmlBinding(); + + void setTarget(const QmlMetaProperty &); + QmlMetaProperty property() const; + + bool enabled() const; + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + virtual QString expression() const; + +public Q_SLOTS: + void update() { update(QmlMetaProperty::DontRemoveBinding); } + +protected: + void emitValueChanged(); + +private: + Q_DECLARE_PRIVATE(QmlBinding) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlBinding); + +QT_END_HEADER + +#endif // QMLBINDING_H diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h new file mode 100644 index 0000000..c6c1935 --- /dev/null +++ b/src/declarative/qml/qmlbinding_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDING_P_H +#define QMLBINDING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlbinding.h" + +#include "qmlmetaproperty.h" +#include "qmlexpression_p.h" + +QT_BEGIN_NAMESPACE + +class QmlBindingData : public QmlExpressionData +{ +public: + QmlBindingData(); + virtual ~QmlBindingData(); + + bool updating:1; + bool enabled:1; + + QmlMetaProperty property; + + virtual void refresh(); +}; + +class QmlBindingPrivate : public QmlExpressionPrivate +{ + Q_DECLARE_PUBLIC(QmlBinding) +public: + QmlBindingPrivate(); + + QmlBindingData *bindingData() { return static_cast<QmlBindingData *>(data); } + const QmlBindingData *bindingData() const { return static_cast<const QmlBindingData *>(data); } +}; + +QT_END_NAMESPACE + +#endif // QMLBINDING_P_H diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp new file mode 100644 index 0000000..110a56c --- /dev/null +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlboundsignal_p.h" + +#include "qmetaobjectbuilder_p.h" +#include "qmlengine_p.h" +#include "qmlexpression_p.h" +#include "qmlcontext_p.h" +#include "qmlmetatype.h" +#include "qml.h" +#include "qmlcontext.h" +#include "qmlglobal_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +class QmlBoundSignalParameters : public QObject +{ +Q_OBJECT +public: + QmlBoundSignalParameters(const QMetaMethod &, QObject * = 0); + ~QmlBoundSignalParameters(); + + void setValues(void **); + void clearValues(); + +private: + friend class MetaObject; + int metaCall(QMetaObject::Call, int _id, void **); + struct MetaObject : public QAbstractDynamicMetaObject { + MetaObject(QmlBoundSignalParameters *b) + : parent(b) {} + + int metaCall(QMetaObject::Call c, int id, void **a) { + return parent->metaCall(c, id, a); + } + QmlBoundSignalParameters *parent; + }; + + int *types; + void **values; + QMetaObject *myMetaObject; +}; + +static int evaluateIdx = -1; + +QmlAbstractBoundSignal::QmlAbstractBoundSignal(QObject *parent) +: QObject(parent) +{ +} + +QmlAbstractBoundSignal::~QmlAbstractBoundSignal() +{ +} + +QmlBoundSignal::QmlBoundSignal(QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_params(0) +{ + // A cached evaluation of the QmlExpression::value() slot index. + // + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QmlGraphics_setParent_noEvent(this, parent); + QMetaObject::connect(scope, m_signal.methodIndex(), this, evaluateIdx); +} + +QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val, + QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_params(0) +{ + // A cached evaluation of the QmlExpression::value() slot index. + // + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QmlGraphics_setParent_noEvent(this, parent); + QMetaObject::connect(scope, m_signal.methodIndex(), this, evaluateIdx); + + m_expression = new QmlExpression(ctxt, val, scope); + m_expression->setTrackChange(false); +} + +QmlBoundSignal::~QmlBoundSignal() +{ + delete m_expression; + m_expression = 0; +} + +int QmlBoundSignal::index() const +{ + return m_signal.methodIndex(); +} + +/*! + Returns the signal expression. +*/ +QmlExpression *QmlBoundSignal::expression() const +{ + return m_expression; +} + +/*! + Sets the signal expression to \a e. Returns the current signal expression, + or null if there is no signal expression. + + The QmlBoundSignal instance takes ownership of \a e. The caller is + assumes ownership of the returned QmlExpression. +*/ +QmlExpression *QmlBoundSignal::setExpression(QmlExpression *e) +{ + QmlExpression *rv = m_expression; + m_expression = e; + if (m_expression) m_expression->setTrackChange(false); + return rv; +} + +QmlBoundSignal *QmlBoundSignal::cast(QObject *o) +{ + QmlAbstractBoundSignal *s = qobject_cast<QmlAbstractBoundSignal*>(o); + return static_cast<QmlBoundSignal *>(s); +} + +int QmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) +{ + if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { + if (!m_paramsValid) { + if (!m_signal.parameterTypes().isEmpty()) + m_params = new QmlBoundSignalParameters(m_signal, this); + m_paramsValid = true; + } + + if (m_params) m_params->setValues(a); + if (m_expression) { + QmlExpressionPrivate::get(m_expression)->value(m_params); + if (m_expression && m_expression->hasError()) + qWarning().nospace() << qPrintable(m_expression->error().toString()); + } + if (m_params) m_params->clearValues(); + return -1; + } else { + return QObject::qt_metacall(c, id, a); + } +} + +QmlBoundSignalParameters::QmlBoundSignalParameters(const QMetaMethod &method, + QObject *parent) +: QObject(parent), types(0), values(0) +{ + MetaObject *mo = new MetaObject(this); + + // ### Optimize! + // ### Ensure only supported types are allowed, otherwise it might crash + QMetaObjectBuilder mob; + mob.setSuperClass(&QmlBoundSignalParameters::staticMetaObject); + mob.setClassName("QmlBoundSignalParameters"); + + QList<QByteArray> paramTypes = method.parameterTypes(); + QList<QByteArray> paramNames = method.parameterNames(); + types = new int[paramTypes.count()]; + for (int ii = 0; ii < paramTypes.count(); ++ii) { + const QByteArray &type = paramTypes.at(ii); + const QByteArray &name = paramNames.at(ii); + + if (name.isEmpty() || type.isEmpty()) { + types[ii] = 0; + continue; + } + + QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData()); + if (QmlMetaType::isObject(t)) { + types[ii] = QMetaType::QObjectStar; + QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); + prop.setWritable(false); + } else { + types[ii] = t; + QMetaPropertyBuilder prop = mob.addProperty(name, type); + prop.setWritable(false); + } + } + myMetaObject = mob.toMetaObject(); + *static_cast<QMetaObject *>(mo) = *myMetaObject; + + d_ptr->metaObject = mo; +} + +QmlBoundSignalParameters::~QmlBoundSignalParameters() +{ + delete [] types; + qFree(myMetaObject); +} + +void QmlBoundSignalParameters::setValues(void **v) +{ + values = v; +} + +void QmlBoundSignalParameters::clearValues() +{ + values = 0; +} + +int QmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) +{ + if (!values) + return -1; + + if (c == QMetaObject::ReadProperty && id >= 1) { + QmlMetaType::copy(types[id - 1], a[0], values[id]); + return -1; + } else { + return qt_metacall(c, id, a); + } +} + +QT_END_NAMESPACE + +#include <qmlboundsignal.moc> diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h new file mode 100644 index 0000000..971fc89 --- /dev/null +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBOUNDSIGNAL_P_H +#define QMLBOUNDSIGNAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlexpression.h" + +#include <QtCore/qmetaobject.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QmlAbstractBoundSignal : public QObject +{ + Q_OBJECT +public: + QmlAbstractBoundSignal(QObject *parent = 0); + virtual ~QmlAbstractBoundSignal() = 0; +}; + +class QmlBoundSignalParameters; +class QmlBoundSignal : public QmlAbstractBoundSignal +{ +public: + QmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent); + QmlBoundSignal(QmlContext *ctxt, const QString &val, QObject *scope, + const QMetaMethod &signal, QObject *parent); + virtual ~QmlBoundSignal(); + + int index() const; + + QmlExpression *expression() const; + QmlExpression *setExpression(QmlExpression *); + + static QmlBoundSignal *cast(QObject *); + +protected: + virtual int qt_metacall(QMetaObject::Call c, int id, void **a); + +private: + QmlExpression *m_expression; + QMetaMethod m_signal; + bool m_paramsValid; + QmlBoundSignalParameters *m_params; +}; + +QT_END_NAMESPACE + +#endif // QMLBOUNDSIGNAL_P_H diff --git a/src/declarative/qml/qmlclassfactory.cpp b/src/declarative/qml/qmlclassfactory.cpp new file mode 100644 index 0000000..3c19c2f --- /dev/null +++ b/src/declarative/qml/qmlclassfactory.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlclassfactory_p.h" + +QT_BEGIN_NAMESPACE + +QmlClassFactory::~QmlClassFactory() +{ +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlclassfactory_p.h b/src/declarative/qml/qmlclassfactory_p.h new file mode 100644 index 0000000..91f616e --- /dev/null +++ b/src/declarative/qml/qmlclassfactory_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCLASSFACTORY_P_H +#define QMLCLASSFACTORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QByteArray; +class QUrl; +class QmlComponent; + +class QmlClassFactory +{ +public: + virtual ~QmlClassFactory(); + virtual QmlComponent *create(const QByteArray &, const QUrl& baseUrl, QmlEngine*) = 0; +}; + +QT_END_NAMESPACE + +#endif // QMLCLASSFACTORY_P_H diff --git a/src/declarative/qml/qmlcleanup.cpp b/src/declarative/qml/qmlcleanup.cpp new file mode 100644 index 0000000..599e4e7 --- /dev/null +++ b/src/declarative/qml/qmlcleanup.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcleanup_p.h" + +#include "qmlengine_p.h" + +/*! +\internal +\class QmlCleanup +\brief The QmlCleanup provides a callback when a QmlEngine is deleted. + +Any object that needs cleanup to occur before the QmlEngine's QScriptEngine is +destroyed should inherit from QmlCleanup. The clear() virtual method will be +called by QmlEngine just before it deletes the QScriptEngine. +*/ + +/*! +\internal + +Create a QmlCleanup for \a engine +*/ +QmlCleanup::QmlCleanup(QmlEngine *engine) +: prev(0), next(0) +{ + if (!engine) + return; + + QmlEnginePrivate *p = QmlEnginePrivate::get(engine); + + if (p->cleanup) next = p->cleanup; + p->cleanup = this; + prev = &p->cleanup; + if (next) next->prev = &next; +} + +/*! +\internal +*/ +QmlCleanup::~QmlCleanup() +{ + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} + diff --git a/src/declarative/qml/qmlcleanup_p.h b/src/declarative/qml/qmlcleanup_p.h new file mode 100644 index 0000000..c140e43 --- /dev/null +++ b/src/declarative/qml/qmlcleanup_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCLEANUP_P_H +#define QMLCLEANUP_P_H + +#include <QtCore/qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlCleanup +{ +public: + QmlCleanup(QmlEngine *); + virtual ~QmlCleanup(); + +protected: + virtual void clear() = 0; + +private: + friend class QmlEnginePrivate; + QmlCleanup **prev; + QmlCleanup *next; +}; + +QT_END_NAMESPACE + +#endif // QMLCLEANUP_P_H + diff --git a/src/declarative/qml/qmlcompiledbindings.cpp b/src/declarative/qml/qmlcompiledbindings.cpp new file mode 100644 index 0000000..cdea96f --- /dev/null +++ b/src/declarative/qml/qmlcompiledbindings.cpp @@ -0,0 +1,2720 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiledbindings_p.h" + +#include <QtDeclarative/qmlinfo.h> +#include <private/qmlcontext_p.h> +#include <private/qmljsast_p.h> +#include <private/qmljsengine_p.h> +#include <private/qmlexpression_p.h> +#include <QtCore/qdebug.h> +#include <QtCore/qnumeric.h> +#include <private/qmlgraphicsanchors_p_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QmlJS; + +namespace { +// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool +struct Register { + void setUndefined() { type = 0; } + void setUnknownButDefined() { type = -1; } + void setNaN() { setqreal(qSNaN()); } + bool isUndefined() const { return type == 0; } + + void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; } + QObject *getQObject() const { return *((QObject **)data); } + + void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; } + qreal getqreal() const { return *((qreal *)data); } + + void setint(int v) { *((int *)data) = v; type = QMetaType::Int; } + int getint() const { return *((int *)data); } + + void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; } + bool getbool() const { return *((bool *)data); } + + QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } + QString *getstringptr() { return (QString *)typeDataPtr(); } + QUrl *geturlptr() { return (QUrl *)typeDataPtr(); } + const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); } + const QString *getstringptr() const { return (QString *)typeDataPtr(); } + const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); } + + void *typeDataPtr() { return (void *)&data; } + void *typeMemory() { return (void *)data; } + const void *typeDataPtr() const { return (void *)&data; } + const void *typeMemory() const { return (void *)data; } + + int gettype() const { return type; } + void settype(int t) { type = t; } + + int type; // Optional type + void *data[2]; // Object stored here +}; +} + +class QmlCompiledBindingsPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlCompiledBindings) + +public: + QmlCompiledBindingsPrivate(); + virtual ~QmlCompiledBindingsPrivate(); + + struct Binding : public QmlAbstractBinding, public QmlDelayedError { + Binding() : enabled(false), updating(0), property(0), + scope(0), target(0), parent(0) {} + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + virtual void destroy(); + + int index:30; + bool enabled:1; + bool updating:1; + int property; + QObject *scope; + QObject *target; + + QmlCompiledBindingsPrivate *parent; + }; + + struct Subscription { + struct Signal { + QmlGuard<QObject> source; + int notifyIndex; + }; + + enum { InvalidType, SignalType, IdType } type; + inline Subscription(); + inline ~Subscription(); + bool isSignal() const { return type == SignalType; } + bool isId() const { return type == IdType; } + inline Signal *signal(); + inline QmlContextPrivate::IdNotifier *id(); + union { + char signalData[sizeof(Signal)]; + char idData[sizeof(QmlContextPrivate::IdNotifier)]; + }; + }; + Subscription *subscriptions; + QScriptDeclarativeClass::PersistentIdentifier *identifiers; + + void run(Binding *); + + const char *programData; + Binding *m_bindings; + quint32 *m_signalTable; + + static int methodCount; + + void init(); + void run(int instr, QmlContextPrivate *context, + QmlDelayedError *error, QObject *scope, QObject *output); + + + inline void unsubscribe(int subIndex); + inline void subscribeId(QmlContextPrivate *p, int idIndex, int subIndex); + inline void subscribe(QObject *o, int notifyIndex, int subIndex); + + QmlPropertyCache::Data *findproperty(QObject *obj, + const QScriptDeclarativeClass::Identifier &name, + QmlEnginePrivate *enginePriv, + QmlPropertyCache::Data &local); + bool findproperty(QObject *obj, + Register *output, + QmlEnginePrivate *enginePriv, + int subIdx, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); + void findgeneric(Register *output, // value output + int subIdx, // Subscription index in config + QmlContextPrivate *context, // Context to search in + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); +}; + +QmlCompiledBindingsPrivate::QmlCompiledBindingsPrivate() +: subscriptions(0), identifiers(0) +{ +} + +QmlCompiledBindingsPrivate::~QmlCompiledBindingsPrivate() +{ + delete [] subscriptions; subscriptions = 0; + delete [] identifiers; identifiers = 0; +} + +QmlCompiledBindingsPrivate::Subscription::Subscription() +: type(InvalidType) +{ +} + +QmlCompiledBindingsPrivate::Subscription::~Subscription() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + else if (type == IdType) ((QmlContextPrivate::IdNotifier *)idData)->~IdNotifier(); +} + + +int QmlCompiledBindingsPrivate::methodCount = -1; + +QmlCompiledBindings::QmlCompiledBindings(const char *program, QmlContext *context) +: QObject(*(new QmlCompiledBindingsPrivate)) +{ + Q_D(QmlCompiledBindings); + + if (d->methodCount == -1) + d->methodCount = QmlCompiledBindings::staticMetaObject.methodCount(); + + d->programData = program; + + d->init(); + + QmlAbstractExpression::setContext(context); +} + +QmlCompiledBindings::~QmlCompiledBindings() +{ + Q_D(QmlCompiledBindings); + + delete [] d->m_bindings; +} + +QmlAbstractBinding *QmlCompiledBindings::configBinding(int index, QObject *target, + QObject *scope, int property) +{ + Q_D(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Binding *rv = d->m_bindings + index; + + rv->index = index; + rv->property = property; + rv->target = target; + rv->scope = scope; + rv->parent = d; + + addref(); // This is decremented in Binding::destroy() + + return rv; +} + +void QmlCompiledBindingsPrivate::Binding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +{ + if (e) { + addToObject(target); + update(flags); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e, flags); + + if (enabled != e) { + enabled = e; + + if (e) update(flags); + } +} + +int QmlCompiledBindingsPrivate::Binding::propertyIndex() +{ + return property & 0xFFFF; +} + +void QmlCompiledBindingsPrivate::Binding::update(QmlMetaProperty::WriteFlags) +{ + parent->run(this); +} + +void QmlCompiledBindingsPrivate::Binding::destroy() +{ + enabled = false; + removeFromObject(); + parent->q_func()->release(); +} + +int QmlCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **) +{ + Q_D(QmlCompiledBindings); + + if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) { + id -= d->methodCount; + + quint32 *reeval = d->m_signalTable + d->m_signalTable[id]; + quint32 count = *reeval; + ++reeval; + for (quint32 ii = 0; ii < count; ++ii) { + d->run(d->m_bindings + reeval[ii]); + } + } + return -1; +} + +void QmlCompiledBindingsPrivate::run(Binding *binding) +{ + Q_Q(QmlCompiledBindings); + + if (!binding->enabled) + return; + if (binding->updating) + qWarning("ERROR: Circular binding"); + + QmlContext *context = q->QmlAbstractExpression::context(); + if (!context) { + qWarning("QmlCompiledBindings: Attempted to evaluate an expression in an invalid context"); + return; + } + QmlContextPrivate *cp = QmlContextPrivate::get(context); + + if (binding->property & 0xFFFF0000) { + QmlEnginePrivate *ep = QmlEnginePrivate::get(cp->engine); + + QmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; + Q_ASSERT(vt); + vt->read(binding->target, binding->property & 0xFFFF); + + QObject *target = vt; + run(binding->index, cp, binding, binding->scope, target); + + vt->write(binding->target, binding->property & 0xFFFF, + QmlMetaProperty::DontRemoveBinding); + } else { + run(binding->index, cp, binding, binding->scope, binding->target); + } +} + +QmlCompiledBindingsPrivate::Subscription::Signal *QmlCompiledBindingsPrivate::Subscription::signal() +{ + if (type == IdType) ((QmlContextPrivate::IdNotifier *)idData)->~IdNotifier(); + if (type != SignalType) new (signalData) Signal; + type = SignalType; + return (Signal *)signalData; +} + +QmlContextPrivate::IdNotifier *QmlCompiledBindingsPrivate::Subscription::id() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + if (type != IdType) new (idData) QmlContextPrivate::IdNotifier; + type = IdType; + return (QmlContextPrivate::IdNotifier *)idData; +} + +namespace { +// This structure is exactly 8-bytes in size +struct Instr { + enum { + Noop, + + Subscribe, // subscribe + SubscribeId, // subscribe + + LoadId, // load + LoadScope, // load + LoadRoot, // load + LoadAttached, // attached + + ConvertIntToReal, // unaryop + ConvertRealToInt, // unaryop + + Real, // real_value + Int, // int_value + Bool, // bool_value + String, // string_value + + AddReal, // binaryop + AddInt, // binaryop + AddString, // binaryop + + MinusReal, // binaryop + MinusInt, // binaryop + + CompareReal, // binaryop + CompareString, // binaryop + + NotCompareReal, // binaryop + NotCompareString, // binaryop + + GreaterThanReal, // binaryop + MaxReal, // binaryop + MinReal, // binaryop + + NewString, // construct + NewUrl, // construct + + CleanupUrl, // cleanup + CleanupString, // cleanup + + Copy, // copy + Fetch, // fetch + Store, // store + + Skip, // skip + + Done, + + // Speculative property resolution + InitString, // initstring + FindGeneric, // find + FindGenericTerminal, // find + FindProperty, // find + FindPropertyTerminal, // find + CleanupGeneric, // cleanup + ConvertGenericToReal, // unaryop + ConvertGenericToBool, // unaryop + ConvertGenericToString, // unaryop + ConvertGenericToUrl, // unaryop + }; + + union { + struct { + quint8 type; + quint8 packing[7]; + } common; + struct { + quint8 type; + quint8 packing[3]; + quint16 subscriptions; + quint16 identifiers; + } init; + struct { + quint8 type; + qint8 reg; + quint16 offset; + quint32 index; + } subscribe; + struct { + quint8 type; + qint8 reg; + quint8 packing[2]; + quint32 index; + } load; + struct { + quint8 type; + qint8 output; + qint8 reg; + quint8 exceptionId; + quint32 index; + } attached; + struct { + quint8 type; + qint8 output; + qint8 reg; + quint8 exceptionId; + quint32 index; + } store; + struct { + quint8 type; + qint8 output; + qint8 objectReg; + quint8 exceptionId; + quint32 index; + } fetch; + struct { + quint8 type; + qint8 reg; + qint8 src; + quint8 packing[5]; + } copy; + struct { + quint8 type; + qint8 reg; + quint8 packing[6]; + } construct; + struct { + quint8 type; + qint8 reg; + quint8 packing[2]; + float value; + } real_value; + struct { + quint8 type; + qint8 reg; + quint8 packing[2]; + int value; + } int_value; + struct { + quint8 type; + qint8 reg; + bool value; + quint8 packing[5]; + } bool_value; + struct { + quint8 type; + qint8 reg; + quint16 length; + quint32 offset; + } string_value; + struct { + quint8 type; + qint8 output; + qint8 src1; + qint8 src2; + quint8 packing[4]; + } binaryop; + struct { + quint8 type; + qint8 output; + qint8 src; + quint8 packing[5]; + } unaryop; + struct { + quint8 type; + qint8 reg; + quint8 packing[2]; + quint32 count; + } skip; + struct { + quint8 type; + qint8 reg; + qint8 src; + quint8 exceptionId; + quint16 name; + quint16 subscribeIndex; + } find; + struct { + quint8 type; + qint8 reg; + quint8 packing[6]; + } cleanup; + struct { + quint8 type; + quint8 packing[1]; + quint16 offset; + quint32 dataIdx; + } initstring; + }; +}; + +struct Program { + quint32 bindings; + quint32 dataLength; + quint32 signalTableOffset; + quint32 exceptionDataOffset; + quint16 subscriptions; + quint16 identifiers; + quint16 instructionCount; + quint16 dummy; + + const char *data() const { return ((const char *)this) + sizeof(Program); } + const Instr *instructions() const { return (const Instr *)(data() + dataLength); } +}; +} + +struct QmlBindingCompilerPrivate +{ + struct Result { + Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {} + bool operator==(const Result &o) const { + return unknownType == o.unknownType && + metaObject == o.metaObject && + type == o.type && + reg == o.reg; + } + bool operator!=(const Result &o) const { + return !(*this == o); + } + bool unknownType; + const QMetaObject *metaObject; + int type; + int reg; + + QSet<QString> subscriptionSet; + }; + + QmlBindingCompilerPrivate() : registers(0) {} + + void resetInstanceState(); + int commitCompile(); + + QmlParser::Object *context; + QmlParser::Object *component; + QmlParser::Property *destination; + QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; + QmlEnginePrivate *engine; + + QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((intptr_t)context, 16); } + + bool compile(QmlJS::AST::Node *); + + bool parseExpression(QmlJS::AST::Node *, Result &); + + bool tryName(QmlJS::AST::Node *); + bool parseName(QmlJS::AST::Node *, Result &); + + bool tryArith(QmlJS::AST::Node *); + bool parseArith(QmlJS::AST::Node *, Result &); + bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op); + bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op); + + bool tryLogic(QmlJS::AST::Node *); + bool parseLogic(QmlJS::AST::Node *, Result &); + + bool tryConditional(QmlJS::AST::Node *); + bool parseConditional(QmlJS::AST::Node *, Result &); + + bool tryConstant(QmlJS::AST::Node *); + bool parseConstant(QmlJS::AST::Node *, Result &); + + bool tryMethod(QmlJS::AST::Node *); + bool parseMethod(QmlJS::AST::Node *, Result &); + + bool buildName(QStringList &, QmlJS::AST::Node *, QList<QmlJS::AST::ExpressionNode *> *nodes = 0); + bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QmlJS::AST::ExpressionNode *); + + quint32 registers; + QHash<int, QPair<int, int> > registerCleanups; + int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0); + void registerCleanup(int reg, int cleanup, int cleanupType = 0); + void releaseReg(int); + + int registerLiteralString(const QString &); + int registerString(const QString &); + QHash<QString, QPair<int, int> > registeredStrings; + QByteArray data; + + bool subscription(const QStringList &, Result *); + int subscriptionIndex(const QStringList &); + bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs); + + quint8 exceptionId(QmlJS::AST::ExpressionNode *); + QVector<quint64> exceptions; + + QSet<int> usedSubscriptionIds; + QSet<QString> subscriptionSet; + QHash<QString, int> subscriptionIds; + QVector<Instr> bytecode; + + // Committed binding data + struct { + QList<int> offsets; + QList<QSet<int> > dependencies; + + QVector<Instr> bytecode; + QByteArray data; + QHash<QString, int> subscriptionIds; + QVector<quint64> exceptions; + + QHash<QString, QPair<int, int> > registeredStrings; + + int count() const { return offsets.count(); } + } committed; + + QByteArray buildSignalTable() const; + QByteArray buildExceptionData() const; +}; + +void QmlCompiledBindingsPrivate::unsubscribe(int subIndex) +{ + Q_Q(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + if (sub->isSignal()) { + QmlCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); + if (s->source) +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(s->source, s->notifyIndex, + q, methodCount + subIndex); +#else + // QTBUG-6781 + QMetaObject::disconnect(s->source, s->notifyIndex, + q, methodCount + subIndex); +#endif + } else if (sub->isId()) { + sub->id()->clear(); + } +} + +void QmlCompiledBindingsPrivate::subscribeId(QmlContextPrivate *p, int idIndex, int subIndex) +{ + Q_Q(QmlCompiledBindings); + + unsubscribe(subIndex); + + if (p->idValues[idIndex]) { + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + QmlContextPrivate::IdNotifier *i = sub->id(); + + i->next = p->idValues[idIndex].bindings; + i->prev = &p->idValues[idIndex].bindings; + p->idValues[idIndex].bindings = i; + if (i->next) i->next->prev = &i->next; + + i->target = q; + i->methodIndex = methodCount + subIndex; + } +} + +void QmlCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex) +{ + Q_Q(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + + if (sub->isId()) + unsubscribe(subIndex); + + QmlCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); + if (o != s->source || notifyIndex != s->notifyIndex) { + if (s->source) +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(s->source, s->notifyIndex, + q, methodCount + subIndex); +#else + // QTBUG-6781 + QMetaObject::disconnect(s->source, s->notifyIndex, + q, methodCount + subIndex); +#endif + s->source = o; + s->notifyIndex = notifyIndex; + if (s->source && s->notifyIndex != -1) + QMetaObject::connect(s->source, s->notifyIndex, q, + methodCount + subIndex, Qt::DirectConnection); + } +} + +// Conversion functions - these MUST match the QtScript expression path +inline static qreal toReal(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::QReal) { + return reg->getqreal(); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toReal(); + } else { + if (ok) *ok = false; + return 0; + } +} + +inline static QString toString(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::QReal) { + return QString::number(reg->getqreal()); + } else if (type == QMetaType::Int) { + return QString::number(reg->getint()); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toString(); + } else if (type == QMetaType::QString) { + return *reg->getstringptr(); + } else { + if (ok) *ok = false; + return QString(); + } +} + +inline static bool toBool(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::Bool) { + return reg->getbool(); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toBool(); + } else { + if (ok) *ok = false; + return false; + } +} + +inline static QUrl toUrl(Register *reg, int type, QmlContextPrivate *context, bool *ok = 0) +{ + if (ok) *ok = true; + + QUrl base; + if (type == qMetaTypeId<QVariant>()) { + QVariant *var = reg->getvariantptr(); + int vt = var->type(); + if (vt == QVariant::Url) { + base = var->toUrl(); + } else if (vt == QVariant::ByteArray) { + base = QUrl(QString::fromUtf8(var->toByteArray())); + } else if (vt == QVariant::String) { + base = QUrl(var->toString()); + } else { + if (ok) *ok = false; + return QUrl(); + } + } else if (type == QMetaType::QString) { + base = QUrl(*reg->getstringptr()); + } else { + if (ok) *ok = false; + return QUrl(); + } + + if (!base.isEmpty() && base.isRelative()) + return context->url.resolved(base); + else + return base; +} + +static QObject *variantToQObject(const QVariant &value, bool *ok) +{ + if (ok) *ok = true; + + if (value.userType() == QMetaType::QObjectStar) { + return qvariant_cast<QObject*>(value); + } else { + if (ok) *ok = false; + return 0; + } +} + +bool QmlCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, + QmlEnginePrivate *enginePriv, + int subIdx, const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) +{ + if (!obj) { + output->setUndefined(); + return false; + } + + QmlPropertyCache::Data local; + QmlPropertyCache::Data *property = + QmlPropertyCache::property(QmlEnginePrivate::get(enginePriv), obj, name, local); + + if (property) { + if (subIdx != -1) + subscribe(obj, property->notifyIndex, subIdx); + + if (property->flags & QmlPropertyCache::Data::IsQObjectDerived) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QObjectStar); + } else if (property->propType == qMetaTypeId<QVariant>()) { + QVariant v; + void *args[] = { &v, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + + if (isTerminal) { + new (output->typeDataPtr()) QVariant(v); + output->settype(qMetaTypeId<QVariant>()); + } else { + bool ok; + output->setQObject(variantToQObject(v, &ok)); + if (!ok) + output->setUndefined(); + else + output->settype(QMetaType::QObjectStar); + } + + } else { + if (!isTerminal) { + output->setUndefined(); + } else if (property->propType == QMetaType::QReal) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QReal); + } else if (property->propType == QMetaType::Int) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::Int); + } else if (property->propType == QMetaType::Bool) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::Bool); + } else if (property->propType == QMetaType::QString) { + new (output->typeDataPtr()) QString(); + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QString); + } else { + new (output->typeDataPtr()) + QVariant(obj->metaObject()->property(property->coreIndex).read(obj)); + output->settype(qMetaTypeId<QVariant>()); + } + } + + return true; + } else { + output->setUndefined(); + return false; + } +} + +void QmlCompiledBindingsPrivate::findgeneric(Register *output, + int subIdx, + QmlContextPrivate *context, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) +{ + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(context->engine); + + while (context) { + + int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1; + + + if (contextPropertyIndex != -1) { + + if (subIdx != -1) + subscribe(QmlContextPrivate::get(context), contextPropertyIndex + context->notifyIndex, subIdx); + + if (contextPropertyIndex < context->idValueCount) { + output->setQObject(context->idValues[contextPropertyIndex]); + output->settype(QMetaType::QObjectStar); + } else { + const QVariant &value = context->propertyValues.at(contextPropertyIndex); + if (isTerminal) { + new (output->typeDataPtr()) QVariant(value); + output->settype(qMetaTypeId<QVariant>()); + } else { + bool ok; + output->setQObject(variantToQObject(value, &ok)); + if (!ok) { output->setUndefined(); } + else { output->settype(QMetaType::QObjectStar); } + return; + } + } + + return; + } + + for (int ii = 0; ii < context->scripts.count(); ++ii) { + QScriptValue function = QScriptDeclarativeClass::function(context->scripts.at(ii), name); + if (function.isValid()) { + qFatal("Binding optimizer resolved name to QScript method"); + } + } + + if (QObject *root = context->defaultObjects.isEmpty()?0:context->defaultObjects.first()) { + + if (findproperty(root, output, enginePriv, subIdx, name, isTerminal)) + return; + + } + + if (context->parent) { + context = QmlContextPrivate::get(context->parent); + } else { + context = 0; + } + } + + output->setUndefined(); +} + +void QmlCompiledBindingsPrivate::init() +{ + Program *program = (Program *)programData; + if (program->subscriptions) + subscriptions = new QmlCompiledBindingsPrivate::Subscription[program->subscriptions]; + if (program->identifiers) + identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; + + m_signalTable = (quint32 *)(program->data() + program->signalTableOffset); + m_bindings = new QmlCompiledBindingsPrivate::Binding[program->bindings]; +} + +static void throwException(int id, QmlDelayedError *error, + Program *program, QmlContextPrivate *context, + const QString &description = QString()) +{ + error->error.setUrl(context->url); + if (description.isEmpty()) + error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object")); + else + error->error.setDescription(description); + if (id != 0xFF) { + quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); + error->error.setLine((e >> 32) & 0xFFFFFFFF); + error->error.setColumn(e & 0xFFFFFFFF); + } else { + error->error.setLine(-1); + error->error.setColumn(-1); + } + if (!context->engine || !error->addError(QmlEnginePrivate::get(context->engine))) + qWarning() << error->error; +} + +void QmlCompiledBindingsPrivate::run(int instrIndex, + QmlContextPrivate *context, QmlDelayedError *error, + QObject *scope, QObject *output) +{ + error->removeError(); + + Register registers[32]; + int storeFlags = 0; + + QmlEnginePrivate *engine = QmlEnginePrivate::get(context->engine); + Program *program = (Program *)programData; + const Instr *instr = program->instructions(); + instr += instrIndex; + const char *data = program->data(); + + while (instr) { + + switch (instr->common.type) { + case Instr::Noop: + break; + + case Instr::SubscribeId: + subscribeId(context, instr->subscribe.index, instr->subscribe.offset); + break; + + case Instr::Subscribe: + { + QObject *o = 0; + const Register &object = registers[instr->subscribe.reg]; + if (!object.isUndefined()) o = object.getQObject(); + subscribe(o, instr->subscribe.index, instr->subscribe.offset); + } + break; + + case Instr::LoadId: + registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data()); + break; + + case Instr::LoadScope: + registers[instr->load.reg].setQObject(scope); + break; + + case Instr::LoadRoot: + registers[instr->load.reg].setQObject(context->defaultObjects.at(0)); + break; + + case Instr::LoadAttached: + { + const Register &input = registers[instr->attached.reg]; + Register &output = registers[instr->attached.output]; + if (input.isUndefined()) { + throwException(instr->attached.exceptionId, error, program, context); + return; + } + + QObject *object = registers[instr->attached.reg].getQObject(); + if (!object) { + output.setUndefined(); + } else { + QObject *attached = + qmlAttachedPropertiesObjectById(instr->attached.index, + registers[instr->attached.reg].getQObject(), + true); + Q_ASSERT(attached); + output.setQObject(attached); + } + } + break; + + case Instr::ConvertIntToReal: + { + const Register &input = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (input.isUndefined()) output.setUndefined(); + else output.setqreal(qreal(input.getint())); + } + break; + + case Instr::ConvertRealToInt: + { + const Register &input = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (input.isUndefined()) output.setUndefined(); + else output.setint(int(input.getqreal())); + } + break; + + case Instr::Real: + registers[instr->real_value.reg].setqreal(instr->real_value.value); + break; + + case Instr::Int: + registers[instr->int_value.reg].setint(instr->int_value.value); + break; + + case Instr::Bool: + registers[instr->bool_value.reg].setbool(instr->bool_value.value); + break; + + case Instr::String: + { + Register &output = registers[instr->string_value.reg]; + new (output.getstringptr()) + QString((QChar *)(data + instr->string_value.offset), instr->string_value.length); + output.settype(QMetaType::QString); + } + break; + + case Instr::AddReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(lhs.getqreal() + rhs.getqreal()); + } + break; + + case Instr::AddInt: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setint(lhs.getint() + rhs.getint()); + } + break; + + case Instr::AddString: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); } + else { + if (lhs.isUndefined()) + new (output.getstringptr()) + QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr()); + else if (rhs.isUndefined()) + new (output.getstringptr()) + QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined")); + else + new (output.getstringptr()) + QString(*registers[instr->binaryop.src1].getstringptr() + + *registers[instr->binaryop.src2].getstringptr()); + output.settype(QMetaType::QString); + } + } + break; + + case Instr::MinusReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(lhs.getqreal() - rhs.getqreal()); + } + break; + + case Instr::MinusInt: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setint(lhs.getint() - rhs.getint()); + } + break; + + case Instr::CompareReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined()); + else output.setbool(lhs.getqreal() == rhs.getqreal()); + } + break; + + case Instr::CompareString: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined()); + else output.setbool(*lhs.getstringptr() == *rhs.getstringptr()); + } + break; + + case Instr::NotCompareReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined()); + else output.setbool(lhs.getqreal() != rhs.getqreal()); + } + break; + + case Instr::NotCompareString: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined()); + else output.setbool(*lhs.getstringptr() != *rhs.getstringptr()); + } + break; + + case Instr::GreaterThanReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false); + else output.setbool(lhs.getqreal() > rhs.getqreal()); + } + break; + + case Instr::MaxReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal())); + } + break; + + case Instr::MinReal: + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal())); + } + break; + + case Instr::NewString: + { + Register &output = registers[instr->construct.reg]; + new (output.getstringptr()) QString; + output.settype(QMetaType::QString); + } + break; + + case Instr::NewUrl: + { + Register &output = registers[instr->construct.reg]; + new (output.geturlptr()) QUrl; + output.settype(QMetaType::QUrl); + } + break; + + case Instr::CleanupString: + registers[instr->cleanup.reg].getstringptr()->~QString(); + break; + + case Instr::CleanupUrl: + registers[instr->cleanup.reg].geturlptr()->~QUrl(); + break; + + case Instr::Fetch: + { + const Register &input = registers[instr->fetch.objectReg]; + Register &output = registers[instr->fetch.output]; + + if (input.isUndefined()) { + throwException(instr->fetch.exceptionId, error, program, context); + return; + } + + QObject *object = input.getQObject(); + if (!object) { + output.setUndefined(); + } else { + void *argv[] = { output.typeDataPtr(), 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv); + } + } + break; + + case Instr::Store: + { + Register &data = registers[instr->store.reg]; + if (data.isUndefined()) { + throwException(instr->store.exceptionId, error, program, context, + QLatin1String("Unable to assign undefined value")); + return; + } + + int status = -1; + void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags }; + QMetaObject::metacall(output, QMetaObject::WriteProperty, + instr->store.index, argv); + } + break; + + case Instr::Copy: + registers[instr->copy.reg] = registers[instr->copy.src]; + break; + + case Instr::Skip: + if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) + instr += instr->skip.count; + break; + + case Instr::Done: + return; + + case Instr::InitString: + if (!identifiers[instr->initstring.offset].identifier) { + quint32 len = *(quint32 *)(data + instr->initstring.dataIdx); + QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); + + QString str = QString::fromRawData(strdata, len); + + identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str); + } + break; + + case Instr::FindGenericTerminal: + case Instr::FindGeneric: + // We start the search in the parent context, as we know that the + // name is not present in the current context or it would have been + // found during the static compile + findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, + QmlContextPrivate::get(context->parent), + identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindGenericTerminal); + break; + + case Instr::FindPropertyTerminal: + case Instr::FindProperty: + { + const Register &object = registers[instr->find.src]; + if (object.isUndefined()) { + throwException(instr->find.exceptionId, error, program, context); + return; + } + + findproperty(object.getQObject(), registers + instr->find.reg, + QmlEnginePrivate::get(context->engine), + instr->find.subscribeIndex, identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindPropertyTerminal); + } + break; + + case Instr::CleanupGeneric: + { + int type = registers[instr->cleanup.reg].gettype(); + if (type == qMetaTypeId<QVariant>()) { + registers[instr->cleanup.reg].getvariantptr()->~QVariant(); + } else if (type == QMetaType::QString) { + registers[instr->cleanup.reg].getstringptr()->~QString(); + } else if (type == QMetaType::QUrl) { + registers[instr->cleanup.reg].geturlptr()->~QUrl(); + } + } + break; + + case Instr::ConvertGenericToReal: + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + output.setqreal(toReal(&input, input.gettype(), &ok)); + if (!ok) output.setUndefined(); + } + break; + + case Instr::ConvertGenericToBool: + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + output.setbool(toBool(&input, input.gettype(), &ok)); + if (!ok) output.setUndefined(); + } + break; + + case Instr::ConvertGenericToString: + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + QString str = toString(&input, input.gettype(), &ok); + if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); } + else { output.setUndefined(); } + } + break; + + case Instr::ConvertGenericToUrl: + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + QUrl url = toUrl(&input, input.gettype(), context, &ok); + if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); } + else { output.setUndefined(); } + } + break; + + default: + qFatal("EEK"); + break; + } + + instr++; + } +} + +void QmlBindingCompiler::dump(const QByteArray &programData) +{ + const Program *program = (const Program *)programData.constData(); + + qWarning() << "Program.bindings:" << program->bindings; + qWarning() << "Program.dataLength:" << program->dataLength; + qWarning() << "Program.subscriptions:" << program->subscriptions; + qWarning() << "Program.indentifiers:" << program->identifiers; + + int count = program->instructionCount; + const Instr *instr = program->instructions(); + + while (count--) { + + switch (instr->common.type) { + case Instr::Noop: + qWarning().nospace() << "Noop"; + break; + case Instr::Subscribe: + qWarning().nospace() << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index; + break; + case Instr::SubscribeId: + qWarning().nospace() << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index; + break; + case Instr::LoadId: + qWarning().nospace() << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadScope: + qWarning().nospace() << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadRoot: + qWarning().nospace() << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadAttached: + qWarning().nospace() << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.index; + break; + case Instr::ConvertIntToReal: + qWarning().nospace() << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertRealToInt: + qWarning().nospace() << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::Real: + qWarning().nospace() << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value; + break; + case Instr::Int: + qWarning().nospace() << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value; + break; + case Instr::Bool: + qWarning().nospace() << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value; + break; + case Instr::String: + qWarning().nospace() << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length; + break; + case Instr::AddReal: + qWarning().nospace() << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::AddInt: + qWarning().nospace() << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::AddString: + qWarning().nospace() << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinusReal: + qWarning().nospace() << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinusInt: + qWarning().nospace() << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::CompareReal: + qWarning().nospace() << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::CompareString: + qWarning().nospace() << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareReal: + qWarning().nospace() << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareString: + qWarning().nospace() << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::GreaterThanReal: + qWarning().nospace() << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MaxReal: + qWarning().nospace() << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinReal: + qWarning().nospace() << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NewString: + qWarning().nospace() << "NewString" << "\t\t" << instr->construct.reg; + break; + case Instr::NewUrl: + qWarning().nospace() << "NewUrl" << "\t\t\t" << instr->construct.reg; + break; + case Instr::CleanupString: + qWarning().nospace() << "CleanupString" << "\t\t" << instr->cleanup.reg; + break; + case Instr::CleanupUrl: + qWarning().nospace() << "CleanupUrl" << "\t\t" << instr->cleanup.reg; + break; + case Instr::Fetch: + qWarning().nospace() << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg; + break; + case Instr::Store: + qWarning().nospace() << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg; + break; + case Instr::Copy: + qWarning().nospace() << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src; + break; + case Instr::Skip: + qWarning().nospace() << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count; + break; + case Instr::Done: + qWarning().nospace() << "Done"; + break; + case Instr::InitString: + qWarning().nospace() << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx; + break; + case Instr::FindGeneric: + qWarning().nospace() << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name; + break; + case Instr::FindGenericTerminal: + qWarning().nospace() << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name; + break; + case Instr::FindProperty: + qWarning().nospace() << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; + break; + case Instr::FindPropertyTerminal: + qWarning().nospace() << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; + break; + case Instr::CleanupGeneric: + qWarning().nospace() << "CleanupGeneric" << "\t\t" << instr->cleanup.reg; + break; + case Instr::ConvertGenericToReal: + qWarning().nospace() << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToBool: + qWarning().nospace() << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToString: + qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToUrl: + qWarning().nospace() << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + default: + qWarning().nospace() << "Unknown"; + break; + } + + ++instr; + } +} + +/*! +Clear the state associated with attempting to compile a specific binding. +This does not clear the global "commited binding" states. +*/ +void QmlBindingCompilerPrivate::resetInstanceState() +{ + registers = 0; + registerCleanups.clear(); + data = committed.data; + exceptions = committed.exceptions; + usedSubscriptionIds.clear(); + subscriptionSet.clear(); + subscriptionIds = committed.subscriptionIds; + registeredStrings = committed.registeredStrings; + bytecode.clear(); +} + +/*! +Mark the last compile as successful, and add it to the "committed data" +section. + +Returns the index for the committed binding. +*/ +int QmlBindingCompilerPrivate::commitCompile() +{ + int rv = committed.count(); + committed.offsets << committed.bytecode.count(); + committed.dependencies << usedSubscriptionIds; + committed.bytecode << bytecode; + committed.data = data; + committed.exceptions = exceptions; + committed.subscriptionIds = subscriptionIds; + committed.registeredStrings = registeredStrings; + return rv; +} + +bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) +{ + resetInstanceState(); + + Result type; + + if (!parseExpression(node, type)) + return false; + + if (subscriptionSet.count() > 0xFFFF || + registeredStrings.count() > 0xFFFF) + return false; + + if (type.unknownType) { + if (destination->type != QMetaType::QReal && + destination->type != QVariant::String && + destination->type != QMetaType::Bool && + destination->type != QVariant::Url) + return false; + + int convertReg = acquireReg(); + + if (destination->type == QMetaType::QReal) { + Instr convert; + convert.common.type = Instr::ConvertGenericToReal; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QVariant::String) { + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QMetaType::Bool) { + Instr convert; + convert.common.type = Instr::ConvertGenericToBool; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QVariant::Url) { + Instr convert; + convert.common.type = Instr::ConvertGenericToUrl; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } + + Instr cleanup; + cleanup.common.type = Instr::CleanupGeneric; + cleanup.cleanup.reg = type.reg; + bytecode << cleanup; + + Instr instr; + instr.common.type = Instr::Store; + instr.store.output = 0; + instr.store.index = destination->index; + instr.store.reg = convertReg; + instr.store.exceptionId = exceptionId(node->expressionCast()); + bytecode << instr; + + if (destination->type == QVariant::String) { + Instr cleanup; + cleanup.common.type = Instr::CleanupString; + cleanup.cleanup.reg = convertReg; + bytecode << cleanup; + } else if (destination->type == QVariant::Url) { + Instr cleanup; + cleanup.common.type = Instr::CleanupUrl; + cleanup.cleanup.reg = convertReg; + bytecode << cleanup; + } + + releaseReg(convertReg); + + Instr done; + done.common.type = Instr::Done; + bytecode << done; + + return true; + } else { + // Can we store the final value? + if (type.type == QVariant::Int && + destination->type == QMetaType::QReal) { + Instr instr; + instr.common.type = Instr::ConvertIntToReal; + instr.unaryop.output = type.reg; + instr.unaryop.src = type.reg; + bytecode << instr; + type.type = QMetaType::QReal; + } else if (type.type == QMetaType::QReal && + destination->type == QVariant::Int) { + Instr instr; + instr.common.type = Instr::ConvertRealToInt; + instr.unaryop.output = type.reg; + instr.unaryop.src = type.reg; + bytecode << instr; + type.type = QVariant::Int; + } else if (type.type == destination->type) { + } else { + const QMetaObject *from = type.metaObject; + const QMetaObject *to = QmlMetaType::rawMetaObjectForType(destination->type); + + if (QmlMetaPropertyPrivate::canConvert(from, to)) + type.type = destination->type; + } + + if (type.type == destination->type) { + Instr instr; + instr.common.type = Instr::Store; + instr.store.output = 0; + instr.store.index = destination->index; + instr.store.reg = type.reg; + instr.store.exceptionId = exceptionId(node->expressionCast()); + bytecode << instr; + + releaseReg(type.reg); + + Instr done; + done.common.type = Instr::Done; + bytecode << done; + + return true; + } else { + return false; + } + } +} + +bool QmlBindingCompilerPrivate::parseExpression(QmlJS::AST::Node *node, Result &type) +{ + while (node->kind == AST::Node::Kind_NestedExpression) + node = static_cast<AST::NestedExpression *>(node)->expression; + + if (tryArith(node)) { + if (!parseArith(node, type)) return false; + } else if (tryLogic(node)) { + if (!parseLogic(node, type)) return false; + } else if (tryConditional(node)) { + if (!parseConditional(node, type)) return false; + } else if (tryName(node)) { + if (!parseName(node, type)) return false; + } else if (tryConstant(node)) { + if (!parseConstant(node, type)) return false; + } else if (tryMethod(node)) { + if (!parseMethod(node, type)) return false; + } else { + return false; + } + return true; +} + +bool QmlBindingCompilerPrivate::tryName(QmlJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_IdentifierExpression || + node->kind == AST::Node::Kind_FieldMemberExpression; +} + +bool QmlBindingCompilerPrivate::parseName(AST::Node *node, Result &type) +{ + QStringList nameParts; + QList<AST::ExpressionNode *> nameNodes; + if (!buildName(nameParts, node, &nameNodes)) + return false; + + int reg = acquireReg(); + if (reg == -1) + return false; + type.reg = reg; + + QmlParser::Object *absType = 0; + + QStringList subscribeName; + + bool wasAttachedObject = false; + + for (int ii = 0; ii < nameParts.count(); ++ii) { + const QString &name = nameParts.at(ii); + + // We don't handle signal properties or attached properties + if (name.length() > 2 && name.startsWith(QLatin1String("on")) && + name.at(2).isUpper()) + return false; + + QmlType *attachType = 0; + if (name.at(0).isUpper()) { + // Could be an attached property + if (ii == nameParts.count() - 1) + return false; + if (nameParts.at(ii + 1).at(0).isUpper()) + return false; + + QmlEnginePrivate::ImportedNamespace *ns = 0; + if (!engine->resolveType(imports, name.toUtf8(), &attachType, 0, 0, 0, &ns)) + return false; + if (ns || !attachType || !attachType->attachedPropertiesType()) + return false; + + wasAttachedObject = true; + } + + if (ii == 0) { + + if (attachType) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + Instr attach; + attach.common.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.index = attachType->index(); + attach.attached.exceptionId = exceptionId(nameNodes.at(ii)); + bytecode << attach; + + subscribeName << contextName(); + subscribeName << QLatin1String("$$$ATTACH_") + name; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + continue; + } else if (ids.contains(name)) { + QmlParser::Object *idObject = ids.value(name); + absType = idObject; + type.metaObject = absType->metaObject(); + + // We check if the id object is the root or + // scope object to avoid a subscription + if (idObject == component) { + Instr instr; + instr.common.type = Instr::LoadRoot; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + } else if (idObject == context) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + } else { + Instr instr; + instr.common.type = Instr::LoadId; + instr.load.index = idObject->idIndex; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << QLatin1String("$$$ID_") + name; + + if (subscription(subscribeName, &type)) { + Instr sub; + sub.common.type = Instr::SubscribeId; + sub.subscribe.offset = subscriptionIndex(subscribeName); + sub.subscribe.reg = reg; + sub.subscribe.index = instr.load.index; + bytecode << sub; + } + } + + } else { + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + + int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname); + int d1Idx = -1; + if (d0Idx == -1) + d1Idx = component->metaObject()->indexOfProperty(cname); + + if (d0Idx != -1) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << contextName(); + subscribeName << name; + + fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)); + } else if(d1Idx != -1) { + Instr instr; + instr.common.type = Instr::LoadRoot; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << QLatin1String("$$$ROOT"); + subscribeName << name; + + fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)); + } else { + Instr find; + if (nameParts.count() == 1) + find.common.type = Instr::FindGenericTerminal; + else + find.common.type = Instr::FindGeneric; + + find.find.reg = reg; + find.find.src = -1; + find.find.name = registerString(name); + find.find.exceptionId = exceptionId(nameNodes.at(ii)); + + subscribeName << QString(QLatin1String("$$$Generic_") + name); + if (subscription(subscribeName, &type)) + find.find.subscribeIndex = subscriptionIndex(subscribeName); + else + find.find.subscribeIndex = -1; + + bytecode << find; + type.unknownType = true; + } + + if (!type.unknownType && type.type == -1) + return false; // Couldn't fetch that type + } + + } else { + + if (attachType) { + Instr attach; + attach.common.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.index = attachType->index(); + bytecode << attach; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + subscribeName << QLatin1String("$$$ATTACH_") + name; + continue; + } + + const QMetaObject *mo = 0; + if (absType) + mo = absType->metaObject(); + else if (type.metaObject) + mo = type.metaObject; + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + int idx = mo?mo->indexOfProperty(cname):-1; + if (absType && idx == -1) + return false; + + subscribeName << name; + + if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) { + absType = 0; + fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)); + if (type.type == -1) + return false; + } else { + + Instr prop; + if (ii == nameParts.count() -1 ) + prop.common.type = Instr::FindPropertyTerminal; + else + prop.common.type = Instr::FindProperty; + + prop.find.reg = reg; + prop.find.src = reg; + prop.find.name = registerString(name); + prop.find.exceptionId = exceptionId(nameNodes.at(ii)); + + if (subscription(subscribeName, &type)) + prop.find.subscribeIndex = subscriptionIndex(subscribeName); + else + prop.find.subscribeIndex = -1; + + type.unknownType = true; + type.metaObject = 0; + type.type = -1; + type.reg = reg; + bytecode << prop; + } + } + + wasAttachedObject = false; + } + + return true; +} + +bool QmlBindingCompilerPrivate::tryArith(QmlJS::AST::Node *node) +{ + if (node->kind != AST::Node::Kind_BinaryExpression) + return false; + + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + if (expression->op == QSOperator::Add || + expression->op == QSOperator::Sub) + return true; + else + return false; +} + +bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type) +{ + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + + type.reg = acquireReg(); + + Result lhs; + Result rhs; + + if (!parseExpression(expression->left, lhs)) return false; + if (!parseExpression(expression->right, rhs)) return false; + + if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) && + (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal)) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if(expression->op == QSOperator::Sub) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if ((lhs.type == QMetaType::QString || lhs.unknownType) && + (rhs.type == QMetaType::QString || rhs.unknownType) && + (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString)) + return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else + return false; +} + +bool QmlBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ + bool nativeReal = rhs.type == QMetaType::QReal || + lhs.type == QMetaType::QReal || + lhs.unknownType || + rhs.unknownType; + + if (nativeReal && lhs.type == QMetaType::Int) { + Instr convert; + convert.common.type = Instr::ConvertIntToReal; + convert.unaryop.output = lhs.reg; + convert.unaryop.src = lhs.reg; + bytecode << convert; + } + + if (nativeReal && rhs.type == QMetaType::Int) { + Instr convert; + convert.common.type = Instr::ConvertIntToReal; + convert.unaryop.output = rhs.reg; + convert.unaryop.src = rhs.reg; + bytecode << convert; + } + + int lhsTmp = -1; + int rhsTmp = -1; + if (lhs.unknownType) { + lhsTmp = acquireReg(); + + Instr conv; + conv.common.type = Instr::ConvertGenericToReal; + conv.unaryop.output = lhsTmp; + conv.unaryop.src = lhs.reg; + bytecode << conv; + } + + if (rhs.unknownType) { + rhsTmp = acquireReg(); + + Instr conv; + conv.common.type = Instr::ConvertGenericToReal; + conv.unaryop.output = rhsTmp; + conv.unaryop.src = rhs.reg; + bytecode << conv; + } + + Instr arith; + if (op == QSOperator::Add) { + arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt; + } else if (op == QSOperator::Sub) { + arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt; + } else { + qFatal("Unsupported arithmetic operator"); + } + + arith.binaryop.output = type.reg; + arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; + bytecode << arith; + + type.metaObject = 0; + type.type = nativeReal?QMetaType::QReal:QMetaType::Int; + type.subscriptionSet.unite(lhs.subscriptionSet); + type.subscriptionSet.unite(rhs.subscriptionSet); + + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); + releaseReg(lhs.reg); + releaseReg(rhs.reg); + + return true; +} + +bool QmlBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ + if (op != QSOperator::Add) + return false; + + int lhsTmp = -1; + int rhsTmp = -1; + + if (lhs.unknownType) { + lhsTmp = acquireReg(Instr::CleanupString); + + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = lhsTmp; + convert.unaryop.src = lhs.reg; + bytecode << convert; + } + + if (rhs.unknownType) { + rhsTmp = acquireReg(Instr::CleanupString); + + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = rhsTmp; + convert.unaryop.src = rhs.reg; + bytecode << convert; + } + + type.reg = acquireReg(Instr::CleanupString); + type.type = QMetaType::QString; + + Instr add; + add.common.type = Instr::AddString; + add.binaryop.output = type.reg; + add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; + bytecode << add; + + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); + + return true; +} + +bool QmlBindingCompilerPrivate::tryLogic(QmlJS::AST::Node *node) +{ + if (node->kind != AST::Node::Kind_BinaryExpression) + return false; + + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + if (expression->op == QSOperator::Gt || + expression->op == QSOperator::Equal || + expression->op == QSOperator::NotEqual) + return true; + else + return false; +} + +bool QmlBindingCompilerPrivate::parseLogic(QmlJS::AST::Node *node, Result &type) +{ + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + + Result lhs; + Result rhs; + + if (!parseExpression(expression->left, lhs)) return false; + if (!parseExpression(expression->right, rhs)) return false; + + type.reg = acquireReg(); + type.metaObject = 0; + type.type = QVariant::Bool; + + if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) { + + Instr op; + if (expression->op == QSOperator::Gt) + op.common.type = Instr::GreaterThanReal; + else if (expression->op == QSOperator::Equal) + op.common.type = Instr::CompareReal; + else if (expression->op == QSOperator::NotEqual) + op.common.type = Instr::NotCompareReal; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + + } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) { + + Instr op; + if (expression->op == QSOperator::Equal) + op.common.type = Instr::CompareString; + else if (expression->op == QSOperator::NotEqual) + op.common.type = Instr::NotCompareString; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + } else { + return false; + } + + releaseReg(lhs.reg); + releaseReg(rhs.reg); + + return true; +} + +bool QmlBindingCompilerPrivate::tryConditional(QmlJS::AST::Node *node) +{ + return (node->kind == AST::Node::Kind_ConditionalExpression); +} + +bool QmlBindingCompilerPrivate::parseConditional(QmlJS::AST::Node *node, Result &type) +{ + AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node); + + AST::Node *test = expression->expression; + if (test->kind == AST::Node::Kind_NestedExpression) + test = static_cast<AST::NestedExpression*>(test)->expression; + + Result etype; + if (!parseExpression(test, etype)) return false; + + if (etype.type != QVariant::Bool) + return false; + + Instr skip; + skip.common.type = Instr::Skip; + skip.skip.reg = etype.reg; + skip.skip.count = 0; + int skipIdx = bytecode.count(); + bytecode << skip; + + // Release to allow reuse of reg + releaseReg(etype.reg); + + QSet<QString> preSubSet = subscriptionSet; + + // int preConditionalSubscriptions = subscriptionSet.count(); + + Result ok; + if (!parseExpression(expression->ok, ok)) return false; + if (ok.unknownType) return false; + + int skipIdx2 = bytecode.count(); + skip.skip.reg = -1; + bytecode << skip; + + // Release to allow reuse of reg + releaseReg(ok.reg); + bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1; + + subscriptionSet = preSubSet; + + Result ko; + if (!parseExpression(expression->ko, ko)) return false; + if (ko.unknownType) return false; + + // Release to allow reuse of reg + releaseReg(ko.reg); + bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1; + + if (ok != ko) + return false; // Must be same type and in same register + + subscriptionSet = preSubSet; + + if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet)) + return false; // Conditionals cannot introduce new subscriptions + + type = ok; + + return true; +} + +bool QmlBindingCompilerPrivate::tryConstant(QmlJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_TrueLiteral || + node->kind == AST::Node::Kind_FalseLiteral || + node->kind == AST::Node::Kind_NumericLiteral || + node->kind == AST::Node::Kind_StringLiteral; +} + +bool QmlBindingCompilerPrivate::parseConstant(QmlJS::AST::Node *node, Result &type) +{ + type.metaObject = 0; + type.type = -1; + type.reg = acquireReg(); + + if (node->kind == AST::Node::Kind_TrueLiteral) { + type.type = QVariant::Bool; + Instr instr; + instr.common.type = Instr::Bool; + instr.bool_value.reg = type.reg; + instr.bool_value.value = true; + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_FalseLiteral) { + type.type = QVariant::Bool; + Instr instr; + instr.common.type = Instr::Bool; + instr.bool_value.reg = type.reg; + instr.bool_value.value = false; + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_NumericLiteral) { + qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value); + + if (qreal(float(value)) != value) + return false; + + type.type = QMetaType::QReal; + Instr instr; + instr.common.type = Instr::Real; + instr.real_value.reg = type.reg; + instr.real_value.value = float(value); + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_StringLiteral) { + QString str = static_cast<AST::StringLiteral *>(node)->value->asString(); + type.type = QMetaType::QString; + type.reg = registerLiteralString(str); + return true; + } else { + return false; + } +} + +bool QmlBindingCompilerPrivate::tryMethod(QmlJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_CallExpression; +} + +bool QmlBindingCompilerPrivate::parseMethod(QmlJS::AST::Node *node, Result &result) +{ + AST::CallExpression *expr = static_cast<AST::CallExpression *>(node); + + QStringList name; + if (!buildName(name, expr->base)) + return false; + + if (name.count() != 2 || name.at(0) != QLatin1String("Math")) + return false; + + QString method = name.at(1); + + AST::ArgumentList *args = expr->arguments; + if (!args) return false; + AST::ExpressionNode *arg0 = args->expression; + args = args->next; + if (!args) return false; + AST::ExpressionNode *arg1 = args->expression; + if (args->next != 0) return false; + if (!arg0 || !arg1) return false; + + Result r0; + if (!parseExpression(arg0, r0)) return false; + Result r1; + if (!parseExpression(arg1, r1)) return false; + + if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal) + return false; + + Instr op; + if (method == QLatin1String("max")) { + op.common.type = Instr::MaxReal; + } else if (method == QLatin1String("min")) { + op.common.type = Instr::MinReal; + } else { + return false; + } + // We release early to reuse registers + releaseReg(r0.reg); + releaseReg(r1.reg); + + op.binaryop.output = acquireReg(); + op.binaryop.src1 = r0.reg; + op.binaryop.src2 = r1.reg; + bytecode << op; + + result.type = QMetaType::QReal; + result.reg = op.binaryop.output; + + return true; +} + +bool QmlBindingCompilerPrivate::buildName(QStringList &name, + QmlJS::AST::Node *node, + QList<QmlJS::AST::ExpressionNode *> *nodes) +{ + if (node->kind == AST::Node::Kind_IdentifierExpression) { + name << static_cast<AST::IdentifierExpression*>(node)->name->asString(); + if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node); + } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { + AST::FieldMemberExpression *expr = + static_cast<AST::FieldMemberExpression *>(node); + + if (!buildName(name, expr->base, nodes)) + return false; + + name << expr->name->asString(); + if (nodes) *nodes << expr; + } else { + return false; + } + + return true; +} + + +bool QmlBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, + int idx, const QStringList &subName, QmlJS::AST::ExpressionNode *node) +{ + QMetaProperty prop = mo->property(idx); + rv.metaObject = 0; + rv.type = 0; + + if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) { + Instr sub; + sub.common.type = Instr::Subscribe; + sub.subscribe.offset = subscriptionIndex(subName); + sub.subscribe.reg = reg; + sub.subscribe.index = prop.notifySignalIndex(); + bytecode << sub; + } + + Instr fetch; + fetch.common.type = Instr::Fetch; + fetch.fetch.objectReg = reg; + fetch.fetch.index = idx; + fetch.fetch.output = reg; + fetch.fetch.exceptionId = exceptionId(node); + + rv.type = prop.userType(); + rv.metaObject = QmlMetaType::metaObjectForType(rv.type); + rv.reg = reg; + + if (rv.type == QMetaType::QString) { + int tmp = acquireReg(); + Instr copy; + copy.common.type = Instr::Copy; + copy.copy.reg = tmp; + copy.copy.src = reg; + bytecode << copy; + releaseReg(tmp); + fetch.fetch.objectReg = tmp; + + Instr setup; + setup.common.type = Instr::NewString; + setup.construct.reg = reg; + bytecode << setup; + registerCleanup(reg, Instr::CleanupString); + } + + bytecode << fetch; + + if (!rv.metaObject && + rv.type != QMetaType::QReal && + rv.type != QMetaType::Int && + rv.type != QMetaType::Bool && + rv.type != qMetaTypeId<QmlGraphicsAnchorLine>() && + rv.type != QMetaType::QString) { + rv.metaObject = 0; + rv.type = 0; + return false; // Unsupported type (string not supported yet); + } + + return true; +} + +void QmlBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType) +{ + registerCleanups.insert(reg, qMakePair(cleanup, cleanupType)); +} + +int QmlBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType) +{ + for (int ii = 0; ii < 32; ++ii) { + if (!(registers & (1 << ii))) { + registers |= (1 << ii); + + if (cleanup != Instr::Noop) + registerCleanup(ii, cleanup, cleanupType); + + return ii; + } + } + return -1; +} + +void QmlBindingCompilerPrivate::releaseReg(int reg) +{ + Q_ASSERT(reg >= 0 && reg <= 31); + + if (registerCleanups.contains(reg)) { + QPair<int, int> c = registerCleanups[reg]; + registerCleanups.remove(reg); + Instr cleanup; + cleanup.common.type = (quint8)c.first; + cleanup.cleanup.reg = reg; + bytecode << cleanup; + } + + quint32 mask = 1 << reg; + registers &= ~mask; +} + +// Returns a reg +int QmlBindingCompilerPrivate::registerLiteralString(const QString &str) +{ + QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar)); + int offset = data.count(); + data += strdata; + + int reg = acquireReg(Instr::CleanupString); + + Instr string; + string.common.type = Instr::String; + string.string_value.reg = reg; + string.string_value.offset = offset; + string.string_value.length = str.length(); + bytecode << string; + + return reg; +} + +// Returns an identifier offset +int QmlBindingCompilerPrivate::registerString(const QString &string) +{ + Q_ASSERT(!string.isEmpty()); + + QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string); + + if (iter == registeredStrings.end()) { + quint32 len = string.length(); + QByteArray lendata((const char *)&len, sizeof(quint32)); + QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar)); + strdata.prepend(lendata); + int rv = data.count(); + data += strdata; + + iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv)); + } + + Instr reg; + reg.common.type = Instr::InitString; + reg.initstring.offset = iter->first; + reg.initstring.dataIdx = iter->second; + bytecode << reg; + return reg.initstring.offset; +} + +bool QmlBindingCompilerPrivate::subscription(const QStringList &sub, Result *result) +{ + QString str = sub.join(QLatin1String(".")); + result->subscriptionSet.insert(str); + + if (subscriptionSet.contains(str)) { + return false; + } else { + subscriptionSet.insert(str); + return true; + } +} + +int QmlBindingCompilerPrivate::subscriptionIndex(const QStringList &sub) +{ + QString str = sub.join(QLatin1String(".")); + QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str); + if (iter == subscriptionIds.end()) + iter = subscriptionIds.insert(str, subscriptionIds.count()); + usedSubscriptionIds.insert(*iter); + return *iter; +} + +/* + Returns true if lhs contains no subscriptions that aren't also in base or rhs AND + rhs contains no subscriptions that aren't also in base or lhs. +*/ +bool QmlBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, + const QSet<QString> &lhs, + const QSet<QString> &rhs) +{ + QSet<QString> difflhs = lhs; + difflhs.subtract(rhs); + QSet<QString> diffrhs = rhs; + diffrhs.subtract(lhs); + + difflhs.unite(diffrhs); + difflhs.subtract(base); + + return difflhs.isEmpty(); +} + +quint8 QmlBindingCompilerPrivate::exceptionId(QmlJS::AST::ExpressionNode *n) +{ + quint8 rv = 0xFF; + if (n && exceptions.count() < 0xFF) { + rv = (quint8)exceptions.count(); + QmlJS::AST::SourceLocation l = n->firstSourceLocation(); + quint64 e = l.startLine; + e <<= 32; + e |= l.startColumn; + exceptions.append(e); + } + return rv; +} + +QmlBindingCompiler::QmlBindingCompiler() +: d(new QmlBindingCompilerPrivate) +{ +} + +QmlBindingCompiler::~QmlBindingCompiler() +{ + delete d; d = 0; +} + +/* +Returns true if any bindings were compiled. +*/ +bool QmlBindingCompiler::isValid() const +{ + return !d->committed.bytecode.isEmpty(); +} + +/* +-1 on failure, otherwise the binding index to use. +*/ +int QmlBindingCompiler::compile(const Expression &expression, QmlEnginePrivate *engine) +{ + if (!expression.expression.asAST()) return false; + + d->context = expression.context; + d->component = expression.component; + d->destination = expression.property; + d->ids = expression.ids; + d->imports = expression.imports; + d->engine = engine; + + if (d->compile(expression.expression.asAST())) { + return d->commitCompile(); + } else { + return -1; + } +} + + +QByteArray QmlBindingCompilerPrivate::buildSignalTable() const +{ + QHash<int, QList<int> > table; + + for (int ii = 0; ii < committed.count(); ++ii) { + const QSet<int> &deps = committed.dependencies.at(ii); + for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter) + table[*iter].append(ii); + } + + QVector<quint32> header; + QVector<quint32> data; + for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) { + header.append(committed.subscriptionIds.count() + data.count()); + const QList<int> &bindings = table[ii]; + data.append(bindings.count()); + for (int jj = 0; jj < bindings.count(); ++jj) + data.append(bindings.at(jj)); + } + header << data; + + return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32)); +} + +QByteArray QmlBindingCompilerPrivate::buildExceptionData() const +{ + QByteArray rv; + rv.resize(committed.exceptions.count() * sizeof(quint64)); + ::memcpy(rv.data(), committed.exceptions.constData(), rv.size()); + return rv; +} + +/* +Returns the compiled program. +*/ +QByteArray QmlBindingCompiler::program() const +{ + QByteArray programData; + + if (isValid()) { + Program prog; + prog.bindings = d->committed.count(); + + QVector<Instr> bytecode; + Instr skip; + skip.common.type = Instr::Skip; + skip.skip.reg = -1; + for (int ii = 0; ii < d->committed.count(); ++ii) { + skip.skip.count = d->committed.count() - ii - 1; + skip.skip.count+= d->committed.offsets.at(ii); + bytecode << skip; + } + bytecode << d->committed.bytecode; + + QByteArray data = d->committed.data; + while (data.count() % 4) data.append('\0'); + prog.signalTableOffset = data.count(); + data += d->buildSignalTable(); + while (data.count() % 4) data.append('\0'); + prog.exceptionDataOffset = data.count(); + data += d->buildExceptionData(); + + prog.dataLength = 4 * ((data.size() + 3) / 4); + prog.subscriptions = d->committed.subscriptionIds.count(); + prog.identifiers = d->committed.registeredStrings.count(); + prog.instructionCount = bytecode.count(); + int size = sizeof(Program) + bytecode.count() * sizeof(Instr); + size += prog.dataLength; + + programData.resize(size); + memcpy(programData.data(), &prog, sizeof(Program)); + if (prog.dataLength) + memcpy((char *)((Program *)programData.data())->data(), data.constData(), + data.size()); + memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), + bytecode.count() * sizeof(Instr)); + } + + return programData; +} + + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledbindings_p.h b/src/declarative/qml/qmlcompiledbindings_p.h new file mode 100644 index 0000000..1d8fac4 --- /dev/null +++ b/src/declarative/qml/qmlcompiledbindings_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDINGOPTIMIZATIONS_P_H +#define QMLBINDINGOPTIMIZATIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlexpression_p.h" +#include "qmlbinding.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QmlBindingCompilerPrivate; +class QmlBindingCompiler +{ +public: + QmlBindingCompiler(); + ~QmlBindingCompiler(); + + // Returns true if bindings were compiled + bool isValid() const; + + struct Expression + { + QmlParser::Object *component; + QmlParser::Object *context; + QmlParser::Property *property; + QmlParser::Variant expression; + QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; + }; + + // -1 on failure, otherwise the binding index to use + int compile(const Expression &, QmlEnginePrivate *); + + // Returns the compiled program + QByteArray program() const; + + static void dump(const QByteArray &); +private: + QmlBindingCompilerPrivate *d; +}; + +class QmlCompiledBindingsPrivate; +class QmlCompiledBindings : public QObject, public QmlAbstractExpression, public QmlRefCount +{ +public: + QmlCompiledBindings(const char *program, QmlContext *context); + virtual ~QmlCompiledBindings(); + + QmlAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property); + +protected: + int qt_metacall(QMetaObject::Call, int, void **); + +private: + Q_DISABLE_COPY(QmlCompiledBindings); + Q_DECLARE_PRIVATE(QmlCompiledBindings); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLBINDINGOPTIMIZATIONS_P_H + diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp new file mode 100644 index 0000000..48a0893 --- /dev/null +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiler_p.h" +#include "qmlengine.h" +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "qmlcontext.h" +#include "qmlcontext_p.h" + +#include <QtCore/qdebug.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +int QmlCompiledData::pack(const char *data, size_t size) +{ + const char *p = packData.constData(); + unsigned int ps = packData.size(); + + for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { + if (0 == ::memcmp(p + ii, data, size)) + return ii; + } + + int rv = packData.size(); + packData.append(data, size); + return rv; +} + +int QmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if (idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if (idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QmlCompiledData::indexForUrl(const QUrl &data) +{ + int idx = urls.indexOf(data); + if (idx == -1) { + idx = urls.count(); + urls << data; + } + return idx; +} + +int QmlCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= floatData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = floatData.count(); + for (int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= intData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = intData.count(); + for (int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForLocation(const QmlParser::Location &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l; + return rv; +} + +int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l.start << l.end; + return rv; +} + +QmlCompiledData::QmlCompiledData(QmlEngine *engine) +: QmlCleanup(engine), importCache(0), root(0), rootPropertyCache(0) +{ +} + +QmlCompiledData::~QmlCompiledData() +{ + for (int ii = 0; ii < types.count(); ++ii) { + if (types.at(ii).ref) + types.at(ii).ref->release(); + } + + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + + for (int ii = 0; ii < contextCaches.count(); ++ii) + contextCaches.at(ii)->release(); + + if (importCache) + importCache->release(); + + if (rootPropertyCache) + rootPropertyCache->release(); + + qDeleteAll(cachedPrograms); + qDeleteAll(cachedClosures); +} + +void QmlCompiledData::clear() +{ + qDeleteAll(cachedPrograms); + qDeleteAll(cachedClosures); + for (int ii = 0; ii < cachedClosures.count(); ++ii) + cachedClosures[ii] = 0; + for (int ii = 0; ii < cachedPrograms.count(); ++ii) + cachedPrograms[ii] = 0; +} + + +QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt, const QBitField &bindings) const +{ + if (type) { + QObject *rv = type->create(); + if (rv) + QmlEngine::setContextForObject(rv, ctxt); + return rv; + } else { + Q_ASSERT(component); + return QmlComponentPrivate::get(component)->create(ctxt, bindings); + } +} + +const QMetaObject *QmlCompiledData::TypeReference::metaObject() const +{ + if (type) { + return type->metaObject(); + } else { + Q_ASSERT(component); + return static_cast<QmlComponentPrivate *>(QObjectPrivate::get(component))->cc->root; + } +} + +void QmlCompiledData::dumpInstructions() +{ + if (!name.isEmpty()) + qWarning() << name; + qWarning().nospace() << "Index\tLine\tOperation\t\tData1\tData2\tData3\tComments"; + qWarning().nospace() << "-------------------------------------------------------------------------------"; + for (int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning().nospace() << "-------------------------------------------------------------------------------"; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp new file mode 100644 index 0000000..26ebd27 --- /dev/null +++ b/src/declarative/qml/qmlcompiler.cpp @@ -0,0 +1,2815 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiler_p.h" + +#include "qmlcompositetypedata_p.h" +#include "qmlparser_p.h" +#include "qmlscriptparser_p.h" +#include "qmlpropertyvaluesource.h" +#include "qmlcomponent.h" +#include "qmetaobjectbuilder_p.h" +#include "qmlstringconverters_p.h" +#include "qmlengine_p.h" +#include "qmlengine.h" +#include "qmlcontext.h" +#include "qmlmetatype.h" +#include "qmlcustomparser_p_p.h" +#include "qmlcontext_p.h" +#include "qmlcomponent_p.h" +#include "parser/qmljsast_p.h" +#include "qmlvmemetaobject_p.h" +#include "qmlexpression_p.h" +#include "qmlmetaproperty_p.h" +#include "qmlrewrite_p.h" +#include "qmlscriptstring.h" +#include "qmlglobal_p.h" +#include "qmlscriptparser_p.h" +#include "qmlbinding.h" +#include "qmlcompiledbindings_p.h" + +#include <qfxperf_p_p.h> + +#include <QCoreApplication> +#include <QColor> +#include <QDebug> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QAtomicInt> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); +DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATISTICS_DUMP); +DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL); + +using namespace QmlParser; + +/*! + Instantiate a new QmlCompiler. +*/ +QmlCompiler::QmlCompiler() +: output(0), engine(0), unitRoot(0), unit(0) +{ +} + +/*! + Returns true if the last call to compile() caused errors. + + \sa errors() +*/ +bool QmlCompiler::isError() const +{ + return !exceptions.isEmpty(); +} + +/*! + Return the list of errors from the last call to compile(), or an empty list + if there were no errors. +*/ +QList<QmlError> QmlCompiler::errors() const +{ + return exceptions; +} + +/*! + Returns true if \a val is a legal object id, false otherwise. + + Legal ids must start with a lower-case letter or underscore, and contain only + letters, numbers and underscores. +*/ +bool QmlCompiler::isValidId(const QString &val) +{ + if (val.isEmpty()) + return false; + + // TODO this will be enforced and return false + if (val.at(0).isLetter() && !val.at(0).isLower()) { + //return false; + qWarning() << "id '" + val + "' is invalid: ids cannot start with uppercase letters. This will be enforced in an upcoming version of QML."; + } + + QChar u(QLatin1Char('_')); + for (int ii = 0; ii < val.count(); ++ii) + if (val.at(ii) != u && + ((ii == 0 && !val.at(ii).isLetter()) || + (ii != 0 && !val.at(ii).isLetterOrNumber())) ) + return false; + + return true; +} + +/*! + Returns true if \a name refers to an attached property, false otherwise. + + Attached property names are those that start with a capital letter. +*/ +bool QmlCompiler::isAttachedPropertyName(const QByteArray &name) +{ + return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; +} + +/*! + Returns true if \a name refers to a signal property, false otherwise. + + Signal property names are those that start with "on", followed by a capital + letter. +*/ +bool QmlCompiler::isSignalPropertyName(const QByteArray &name) +{ + return name.length() >= 3 && name.startsWith("on") && + 'A' <= name.at(2) && 'Z' >= name.at(2); +} + +/*! + \macro COMPILE_EXCEPTION + \internal + Inserts an error into the QmlCompiler error list, and returns false + (failure). + + \a token is used to source the error line and column, and \a desc is the + error itself. \a desc can be an expression that can be piped into QDebug. + + For example: + + \code + COMPILE_EXCEPTION(property, QCoreApplication::translate("QmlCompiler","Error for property \"%1\"").arg(QString::fromUtf8(property->name))); + \endcode +*/ +#define COMPILE_EXCEPTION(token, desc) \ + { \ + QString exceptionDescription; \ + QmlError error; \ + error.setUrl(output->url); \ + error.setLine((token)->location.start.line); \ + error.setColumn((token)->location.start.column); \ + error.setDescription(desc.trimmed()); \ + exceptions << error; \ + return false; \ + } + +/*! + \macro COMPILE_CHECK + \internal + Returns false if \a is false, otherwise does nothing. +*/ +#define COMPILE_CHECK(a) \ + { \ + if (!a) return false; \ + } + +/*! + Returns true if literal \a v can be assigned to property \a prop, otherwise + false. + + This test corresponds to action taken by genLiteralAssignment(). Any change + made here, must have a corresponding action in genLiteralAssigment(). +*/ +bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) +{ + QString string = v->value.asScript(); + + if (!prop.isWritable()) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(string.toUtf8().constData()); + if (value == -1) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: unknown enumeration")); + return true; + } + int type = prop.userType(); + switch(type) { + case -1: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: string expected")); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: url expected")); + break; + case QVariant::UInt: + { + bool ok; + string.toUInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: unsigned int expected")); + } + break; + case QVariant::Int: + { + bool ok; + string.toInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: int expected")); + } + break; + case QMetaType::Float: + { + bool ok; + string.toFloat(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: float expected")); + } + break; + case QVariant::Double: + { + bool ok; + string.toDouble(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: double expected")); + } + break; + case QVariant::Color: + { + bool ok; + QmlStringConverters::colorFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: color expected")); + } + break; + case QVariant::Date: + { + bool ok; + QmlStringConverters::dateFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: date expected")); + } + break; + case QVariant::Time: + { + bool ok; + QmlStringConverters::timeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: time expected")); + } + break; + case QVariant::DateTime: + { + bool ok; + QmlStringConverters::dateTimeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: datetime expected")); + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: point expected")); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: size expected")); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: rect expected")); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: boolean expected")); + } + break; + case QVariant::Vector3D: + { + bool ok; + QmlStringConverters::vector3DFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: 3D vector expected")); + } + break; + default: + { + int t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type())))); + } + break; + } + return true; +} + +/*! + Generate a store instruction for assigning literal \a v to property \a prop. + + Any literal assignment that is approved in testLiteralAssignment() must have + a corresponding action in this method. +*/ +void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) +{ + QString string = v->value.asScript(); + + QmlInstruction instr; + instr.line = v->location.start.line; + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(string.toUtf8().constData()); + + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = value; + output->bytecode << instr; + return; + } + + int type = prop.userType(); + switch(type) { + case -1: + { + instr.type = QmlInstruction::StoreVariant; + instr.storeString.propertyIndex = prop.propertyIndex(); + instr.storeString.value = output->indexForString(string); + } + break; + case QVariant::String: + { + instr.type = QmlInstruction::StoreString; + instr.storeString.propertyIndex = prop.propertyIndex(); + instr.storeString.value = output->indexForString(string); + } + break; + case QVariant::Url: + { + instr.type = QmlInstruction::StoreUrl; + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); + instr.storeUrl.propertyIndex = prop.propertyIndex(); + instr.storeUrl.value = output->indexForUrl(u); + } + break; + case QVariant::UInt: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = string.toUInt(); + } + break; + case QVariant::Int: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = string.toInt(); + } + break; + case QMetaType::Float: + { + instr.type = QmlInstruction::StoreFloat; + instr.storeFloat.propertyIndex = prop.propertyIndex(); + instr.storeFloat.value = string.toFloat(); + } + break; + case QVariant::Double: + { + instr.type = QmlInstruction::StoreDouble; + instr.storeDouble.propertyIndex = prop.propertyIndex(); + instr.storeDouble.value = string.toDouble(); + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(string); + instr.type = QmlInstruction::StoreColor; + instr.storeColor.propertyIndex = prop.propertyIndex(); + instr.storeColor.value = c.rgba(); + } + break; + case QVariant::Date: + { + QDate d = QmlStringConverters::dateFromString(string); + instr.type = QmlInstruction::StoreDate; + instr.storeDate.propertyIndex = prop.propertyIndex(); + instr.storeDate.value = d.toJulianDay(); + } + break; + case QVariant::Time: + { + QTime time = QmlStringConverters::timeFromString(string); + int data[] = { time.hour(), time.minute(), + time.second(), time.msec() }; + int index = output->indexForInt(data, 4); + instr.type = QmlInstruction::StoreTime; + instr.storeTime.propertyIndex = prop.propertyIndex(); + instr.storeTime.valueIndex = index; + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QmlStringConverters::dateTimeFromString(string); + int data[] = { dateTime.date().toJulianDay(), + dateTime.time().hour(), + dateTime.time().minute(), + dateTime.time().second(), + dateTime.time().msec() }; + int index = output->indexForInt(data, 5); + instr.type = QmlInstruction::StoreDateTime; + instr.storeDateTime.propertyIndex = prop.propertyIndex(); + instr.storeDateTime.valueIndex = index; + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = + QmlStringConverters::pointFFromString(string, &ok); + float data[] = { point.x(), point.y() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + float data[] = { size.width(), size.height() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = output->indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = prop.propertyIndex(); + instr.storeRect.valueIndex = index; + } + break; + case QVariant::Bool: + { + bool b = v->value.asBoolean(); + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = b; + } + break; + case QVariant::Vector3D: + { + bool ok; + QVector3D vector = + QmlStringConverters::vector3DFromString(string, &ok); + float data[] = { vector.x(), vector.y(), vector.z() }; + int index = output->indexForFloat(data, 3); + instr.type = QmlInstruction::StoreVector3D; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + default: + { + int t = prop.userType(); + int index = output->customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + data.index = output->indexForString(string); + data.type = t; + output->customTypeData << data; + } + break; + } + output->bytecode << instr; +} + +/*! + Resets data by clearing the lists that the QmlCompiler modifies. +*/ +void QmlCompiler::reset(QmlCompiledData *data) +{ + data->types.clear(); + data->primitives.clear(); + data->floatData.clear(); + data->intData.clear(); + data->customTypeData.clear(); + data->datas.clear(); + data->bytecode.clear(); +} + +/*! + Compile \a unit, and store the output in \a out. \a engine is the QmlEngine + with which the QmlCompiledData will be associated. + + Returns true on success, false on failure. On failure, the compile errors + are available from errors(). + + If the environment variant QML_COMPILER_DUMP is set + (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr + on a successful compiler. +*/ +bool QmlCompiler::compile(QmlEngine *engine, + QmlCompositeTypeData *unit, + QmlCompiledData *out) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QmlPerfTimer<QmlPerf::Compilation> pc; +#endif + exceptions.clear(); + + Q_ASSERT(out); + reset(out); + + output = out; + + // Compile types + for (int ii = 0; ii < unit->types.count(); ++ii) { + QmlCompositeTypeData::TypeReference &tref = unit->types[ii]; + QmlCompiledData::TypeReference ref; + QmlScriptParser::TypeReference *parserRef = unit->data.referencedTypes().at(ii); + if (tref.type) + ref.type = tref.type; + else if (tref.unit) { + ref.component = tref.unit->toComponent(engine); + + if (ref.component->isError()) { + QmlError error; + error.setUrl(output->url); + error.setDescription(QLatin1String("Unable to create type ") + + parserRef->name); + if (!parserRef->refObjects.isEmpty()) { + QmlParser::Object *parserObject = parserRef->refObjects.first(); + error.setLine(parserObject->location.start.line); + error.setColumn(parserObject->location.start.column); + } + + exceptions << error; + exceptions << ref.component->errors(); + reset(out); + return false; + } + ref.ref = tref.unit; + ref.ref->addref(); + } + ref.className = parserRef->name.toUtf8(); + out->types << ref; + } + + Object *root = unit->data.tree(); + Q_ASSERT(root); + + this->engine = engine; + this->unit = unit; + this->unitRoot = root; + compileTree(root); + + if (!isError()) { + if (compilerDump()) + out->dumpInstructions(); + if (compilerStatDump()) + dumpStats(); + } else { + reset(out); + } + + compileState = ComponentCompileState(); + savedCompileStates.clear(); + output = 0; + this->engine = 0; + this->unit = 0; + this->unitRoot = 0; + + return !isError(); +} + +void QmlCompiler::compileTree(Object *tree) +{ + compileState.root = tree; + + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.line = 0; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + output->bytecode << init; + + genObject(tree); + + QmlInstruction def; + init.line = 0; + def.type = QmlInstruction::SetDefault; + output->bytecode << def; + + output->imports = unit->imports; + output->importCache = output->imports.cache(engine); + + Q_ASSERT(tree->metatype); + + if (tree->metadata.isEmpty()) { + output->root = tree->metatype; + } else { + static_cast<QMetaObject &>(output->rootData) = *tree->metaObject(); + output->root = &output->rootData; + } + if (!tree->metadata.isEmpty()) + QmlEnginePrivate::get(engine)->registerCompositeType(output); +} + +static bool ValuePtrLessThan(const Value *t1, const Value *t2) +{ + return t1->location.start.line < t2->location.start.line || + (t1->location.start.line == t2->location.start.line && + t1->location.start.column < t2->location.start.column); +} + +bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) +{ + componentStat.objects++; + + Q_ASSERT (obj->type != -1); + const QmlCompiledData::TypeReference &tr = + output->types.at(obj->type); + obj->metatype = tr.metaObject(); + + if (tr.component) + obj->url = tr.component->url(); + if (tr.type) + obj->typeName = tr.type->qmlTypeName(); + obj->className = tr.className; + + // This object is a "Component" element + if (tr.type && obj->metatype == &QmlComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); + return true; + } + + // Build any script blocks for this type + for (int ii = 0; ii < obj->scriptBlockObjects.count(); ++ii) + COMPILE_CHECK(buildScript(obj, obj->scriptBlockObjects.at(ii))); + + // Object instantiations reset the binding context + BindingContext objCtxt(obj); + + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); + + // Find the native type and check for the QmlParserStatus interface + QmlType *type = toQmlType(obj); + Q_ASSERT(type); + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) + compileState.parserStatusCount++; + + // Check if this is a custom parser type. Custom parser types allow + // assignments to non-existant properties. These assignments are then + // compiled by the type. + bool isCustomParser = output->types.at(obj->type).type && + output->types.at(obj->type).type->customParser() != 0; + QList<QmlCustomParserProperty> customProps; + + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + foreach(Property *prop, obj->properties) { + if (prop->name == "id") { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } + + // Merge + Property *defaultProperty = 0; + Property *skipProperty = 0; + if (obj->defaultProperty) { + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); + QMetaProperty p = QmlMetaType::defaultProperty(metaObject); + if (p.name()) { + Property *explicitProperty = obj->getProperty(p.name(), false); + if (explicitProperty && !explicitProperty->value) { + skipProperty = explicitProperty; + + defaultProperty = new Property; + defaultProperty->parent = obj; + defaultProperty->isDefault = true; + defaultProperty->location = obj->defaultProperty->location; + defaultProperty->listValueRange = obj->defaultProperty->listValueRange; + defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions; + + defaultProperty->values = obj->defaultProperty->values; + defaultProperty->values += explicitProperty->values; + foreach(Value *value, defaultProperty->values) + value->addref(); + qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan); + + } else { + defaultProperty = obj->defaultProperty; + defaultProperty->addref(); + } + } else { + defaultProperty = obj->defaultProperty; + defaultProperty->addref(); + } + } + + // Build all explicit properties specified + foreach(Property *prop, obj->properties) { + + if (prop == skipProperty) + continue; + if (prop->name == "id") + continue; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj)) { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } else { + customProps << QmlCustomParserNodePrivate::fromProperty(prop); + } + } else { + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); + } else { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } + } + + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(QString::fromUtf8(prop->name))) + prop->isDeferred = true; + + } + + // Build the default property + if (defaultProperty) { + Property *prop = defaultProperty; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj)) { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } else { + customProps << QmlCustomParserNodePrivate::fromProperty(prop); + } + } else { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } + + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(QString::fromUtf8(prop->name))) + prop->isDeferred = true; + } + + if (defaultProperty) + defaultProperty->release(); + + // Compile custom parser parts + if (isCustomParser && !customProps.isEmpty()) { + QmlCustomParser *cp = output->types.at(obj->type).type->customParser(); + cp->clearErrors(); + obj->custom = cp->compile(customProps); + foreach (QmlError err, cp->errors()) { + err.setUrl(output->url); + exceptions << err; + } + } + + return true; +} + +void QmlCompiler::genObject(QmlParser::Object *obj) +{ + const QmlCompiledData::TypeReference &tr = + output->types.at(obj->type); + if (tr.type && obj->metatype == &QmlComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.column = obj->location.start.column; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + if (!output->types.at(create.create.type).type && + !obj->bindingBitmask.isEmpty()) { + Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); + create.create.bindingBits = + output->indexForByteArray(obj->bindingBitmask); + } else { + create.create.bindingBits = -1; + } + output->bytecode << create; + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + QmlInstruction meta; + meta.type = QmlInstruction::StoreMetaObject; + meta.line = 0; + meta.storeMeta.data = output->indexForByteArray(obj->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); + meta.storeMeta.propertyCache = output->propertyCaches.count(); + // ### Surely the creation of this property cache could be more efficient + QmlPropertyCache *propertyCache = 0; + if (tr.component && QmlComponentPrivate::get(tr.component)->cc->rootPropertyCache) { + propertyCache = QmlComponentPrivate::get(tr.component)->cc->rootPropertyCache->copy(); + } else { + propertyCache = QmlPropertyCache::create(engine, obj->metaObject()->superClass()); + } + propertyCache->append(engine, obj->metaObject(), QmlPropertyCache::Data::NoFlags, + QmlPropertyCache::Data::IsVMEFunction); + if (obj == unitRoot) { + propertyCache->addref(); + output->rootPropertyCache = propertyCache; + } + output->propertyCaches << propertyCache; + output->bytecode << meta; + } + + // Set the object id + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = 0; + id.setId.value = output->indexForString(obj->id); + id.setId.index = obj->idIndex; + output->bytecode << id; + } + + // Set any script blocks + for (int ii = 0; ii < obj->scripts.count(); ++ii) { + QmlInstruction script; + script.type = QmlInstruction::StoreScript; + script.line = 0; // ### + int idx = output->scripts.count(); + output->scripts << obj->scripts.at(ii); + script.storeScript.value = idx; + output->bytecode << script; + } + + // Begin the class + if (obj->parserStatusCast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = obj->parserStatusCast; + begin.line = obj->location.start.line; + output->bytecode << begin; + } + + genObjectBody(obj); +} + +void QmlCompiler::genObjectBody(QmlParser::Object *obj) +{ + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, obj->scriptStringProperties) { + QmlInstruction ss; + ss.type = QmlInstruction::StoreScriptString; + ss.storeScriptString.propertyIndex = prop.first->index; + ss.storeScriptString.value = + output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.scope = prop.second; + output->bytecode << ss; + } + + bool seenDefer = false; + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + genValueProperty(prop, obj); + } + if (seenDefer) { + QmlInstruction defer; + defer.type = QmlInstruction::Defer; + defer.line = 0; + defer.defer.deferCount = 0; + int deferIdx = output->bytecode.count(); + output->bytecode << defer; + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary + init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary + init.init.contextCache = -1; + init.init.compiledBinding = -1; + output->bytecode << init; + + foreach(Property *prop, obj->valueProperties) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); + } + + output->bytecode[deferIdx].defer.deferCount = + output->bytecode.count() - deferIdx - 1; + } + + foreach(Property *prop, obj->signalProperties) { + + QmlParser::Value *v = prop->values.at(0); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = v->location.start.line; + assign.assignSignalObject.signal = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + } else if (v->type == Value::SignalExpression) { + + QmlInstruction store; + store.type = QmlInstruction::StoreSignal; + store.line = v->location.start.line; + store.storeSignal.signalIndex = prop->index; + store.storeSignal.value = + output->indexForString(v->value.asScript().trimmed()); + output->bytecode << store; + + } + + } + + foreach(Property *prop, obj->attachedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->location.start.line; + fetch.fetchAttached.id = prop->index; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->groupedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->valueTypeProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchValueType; + fetch.fetchValue.property = prop->index; + fetch.fetchValue.type = prop->type; + fetch.line = prop->location.start.line; + + output->bytecode << fetch; + + foreach(Property *vprop, prop->value->valueProperties) { + genPropertyAssignment(vprop, prop->value, prop); + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopValueType; + pop.fetchValue.property = prop->index; + pop.fetchValue.type = prop->type; + pop.line = prop->location.start.line; + output->bytecode << pop; + } +} + +void QmlCompiler::genComponent(QmlParser::Object *obj) +{ + QmlParser::Object *root = obj->defaultProperty->values.at(0)->object; + Q_ASSERT(root); + + QmlInstruction create; + create.type = QmlInstruction::CreateComponent; + create.line = root->location.start.line; + create.createComponent.column = root->location.start.column; + create.createComponent.endLine = root->location.end.line; + output->bytecode << create; + int count = output->bytecode.count(); + + ComponentCompileState oldCompileState = compileState; + compileState = componentState(root); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + init.line = obj->location.start.line; + output->bytecode << init; + + genObject(root); + + QmlInstruction def; + init.line = 0; + def.type = QmlInstruction::SetDefault; + output->bytecode << def; + + output->bytecode[count - 1].createComponent.count = + output->bytecode.count() - count; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = 0; + id.setId.value = output->indexForString(obj->id); + id.setId.index = obj->idIndex; + output->bytecode << id; + } +} + +bool QmlCompiler::buildComponent(QmlParser::Object *obj, + const BindingContext &ctxt) +{ + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + // Find, check and set the "id" property (if any) + Property *idProp = 0; + if (obj->properties.count() > 1 || + (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) + COMPILE_EXCEPTION(*obj->properties.begin(), QCoreApplication::translate("QmlCompiler","Invalid component specification")); + + if (!obj->scriptBlockObjects.isEmpty()) + COMPILE_EXCEPTION(obj->scriptBlockObjects.first(), QCoreApplication::translate("QmlCompiler","Invalid component specification")); + + if (obj->properties.count()) + idProp = *obj->properties.begin(); + + if (idProp && (idProp->value || idProp->values.count() > 1 || !isValidId(idProp->values.first()->primitive()))) + COMPILE_EXCEPTION(idProp, QCoreApplication::translate("QmlCompiler","Invalid component id specification")); + + if (idProp) { + QString idVal = idProp->values.first()->primitive(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION(idProp, QCoreApplication::translate("QmlCompiler","id is not unique")); + + obj->id = idVal; + addId(idVal, obj); + } + + // Check the Component tree is well formed + if (obj->defaultProperty && + (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || + (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","Invalid component body specification")); + + Object *root = 0; + if (obj->defaultProperty && obj->defaultProperty->values.count()) + root = obj->defaultProperty->values.first()->object; + + if (!root) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","Cannot create empty component specification")); + + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); + + return true; +} + +bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) +{ + Object::ScriptBlock scriptBlock; + + if (script->properties.count() == 1 && + script->properties.begin().key() == QByteArray("source")) { + + Property *source = *script->properties.begin(); + if (script->defaultProperty) + COMPILE_EXCEPTION(source, QCoreApplication::translate("QmlCompiler","Invalid Script block. Specify either the source property or inline script")); + + if (source->value || source->values.count() != 1 || + source->values.at(0)->object || !source->values.at(0)->value.isStringList()) + COMPILE_EXCEPTION(source, QCoreApplication::translate("QmlCompiler","Invalid Script source value")); + + QStringList sources = source->values.at(0)->value.asStringList(); + + for (int jj = 0; jj < sources.count(); ++jj) { + QString sourceUrl = output->url.resolved(QUrl(sources.at(jj))).toString(); + QString scriptCode; + int lineNumber = 1; + + for (int ii = 0; ii < unit->resources.count(); ++ii) { + if (unit->resources.at(ii)->url == sourceUrl) { + scriptCode = QString::fromUtf8(unit->resources.at(ii)->data); + break; + } + } + + if (!scriptCode.isEmpty()) { + scriptBlock.codes.append(scriptCode); + scriptBlock.files.append(sourceUrl); + scriptBlock.lineNumbers.append(lineNumber); + } + } + + } else if (!script->properties.isEmpty()) { + COMPILE_EXCEPTION(*script->properties.begin(), QCoreApplication::translate("QmlCompiler","Properties cannot be set on Script block")); + } else if (script->defaultProperty) { + + QString scriptCode; + int lineNumber = 1; + QString sourceUrl = output->url.toString(); + + QmlParser::Location currentLocation; + + for (int ii = 0; ii < script->defaultProperty->values.count(); ++ii) { + Value *v = script->defaultProperty->values.at(ii); + if (lineNumber == 1) + lineNumber = v->location.start.line; + if (v->object || !v->value.isString()) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid Script block")); + + if (ii == 0) { + currentLocation = v->location.start; + scriptCode.append(QString(currentLocation.column, QLatin1Char(' '))); + } + + while (currentLocation.line < v->location.start.line) { + scriptCode.append(QLatin1Char('\n')); + currentLocation.line++; + currentLocation.column = 0; + } + + scriptCode.append(QString(v->location.start.column - currentLocation.column, QLatin1Char(' '))); + + scriptCode += v->value.asString(); + currentLocation = v->location.end; + currentLocation.column++; + } + + if (!scriptCode.isEmpty()) { + scriptBlock.codes.append(scriptCode); + scriptBlock.files.append(sourceUrl); + scriptBlock.lineNumbers.append(lineNumber); + } + } + + if (!scriptBlock.codes.isEmpty()) + obj->scripts << scriptBlock; + + return true; +} + +bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, + const BindingContext &ctxt) +{ + ComponentCompileState oldComponentCompileState = compileState; + ComponentStat oldComponentStat = componentStat; + + compileState = ComponentCompileState(); + compileState.root = obj; + + componentStat = ComponentStat(); + componentStat.lineNumber = obj->location.start.line; + + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + + compileState = oldComponentCompileState; + componentStat = oldComponentStat; + + return true; +} + + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QmlCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) +{ + Q_ASSERT(obj->metatype); + Q_ASSERT(!obj->defaultProperty); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context + + foreach(Property *prop, obj->properties) { + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); + } else { + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + } + } + + return true; +} + +int QmlCompiler::componentTypeRef() +{ + QmlType *t = QmlMetaType::qmlType("Qt/Component",4,6); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) + return ii; + } + QmlCompiledData::TypeReference ref; + ref.className = "Component"; + ref.type = t; + output->types << ref; + return output->types.count() - 1; +} + +int QmlCompiler::findSignalByName(const QMetaObject *mo, const QByteArray &name) +{ + int methods = mo->methodCount(); + for (int ii = methods - 1; ii >= 0; --ii) { + QMetaMethod method = mo->method(ii); + QByteArray methodName = method.signature(); + int idx = methodName.indexOf('('); + methodName = methodName.left(idx); + + if (methodName == name) + return ii; + } + return -1; +} + +bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(obj->metaObject()); + Q_ASSERT(!prop->isEmpty()); + + QByteArray name = prop->name; + Q_ASSERT(name.startsWith("on")); + name = name.mid(2); + if(name[0] >= 'A' && name[0] <= 'Z') + name[0] = name[0] - 'A' + 'a'; + + int sigIdx = findSignalByName(obj->metaObject(), name); + + if (sigIdx == -1) { + + // If the "on<Signal>" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + + } else { + + if (prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Incorrectly specified signal")); + + prop->index = sigIdx; + obj->addSignalProperty(prop); + + if (prop->values.at(0)->object) { + COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); + prop->values.at(0)->type = Value::SignalObject; + } else { + prop->values.at(0)->type = Value::SignalExpression; + + QString script = prop->values.at(0)->value.asScript().trimmed(); + if (script.isEmpty()) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Empty signal assignment")); + } + } + + return true; +} + + +/*! + Returns true if (value) property \a prop exists on obj, false otherwise. +*/ +bool QmlCompiler::doesPropertyExist(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if(isAttachedPropertyName(prop->name) || prop->name == "id") + return true; + + const QMetaObject *mo = obj->metaObject(); + if (mo) { + if (prop->isDefault) { + QMetaProperty p = QmlMetaType::defaultProperty(mo); + return p.name() != 0; + } else { + int idx = mo->indexOfProperty(prop->name.constData()); + return idx != -1; + } + } + + return false; +} + +bool QmlCompiler::buildProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->isEmpty()) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Empty property assignment")); + + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); + + if (isAttachedPropertyName(prop->name)) { + // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Attached properties cannot be used here")); + } + + QmlType *type = 0; + QmlEnginePrivate::ImportedNamespace *typeNamespace = 0; + QmlEnginePrivate::get(engine)->resolveType(unit->imports, prop->name, + &type, 0, 0, 0, &typeNamespace); + + if (typeNamespace) { + // ### We might need to indicate that this property is a namespace + // for the DOM API + COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, + ctxt)); + return true; + } else if (!type || !type->attachedPropertiesType()) { + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Non-existant attached object")); + } + + if (!prop->value) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->index(); + prop->value->metatype = type->attachedPropertiesType(); + } else { + // Setup regular property data + QMetaProperty p; + + if (prop->isDefault) { + p = QmlMetaType::defaultProperty(metaObject); + + if (p.name()) { + prop->index = p.propertyIndex(); + prop->name = p.name(); + } + + } else { + prop->index = metaObject->indexOfProperty(prop->name.constData()); + + if (prop->index != -1) { + p = metaObject->property(prop->index); + Q_ASSERT(p.name()); + } + } + + // We can't error here as the "id" property does not require a + // successful index resolution + if (p.name()) { + prop->type = p.userType(); + } + } + + if (prop->index != -1) + prop->parent->setBindingBit(prop->index); + + if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { + + // The magic "id" behavior doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } else if (isAttachedPropertyName(prop->name)) { + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + + } else if (prop->index == -1) { + + if (prop->isDefault) { + COMPILE_EXCEPTION(prop->values.first(), QCoreApplication::translate("QmlCompiler","Cannot assign to non-existant default property")); + } else { + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Cannot assign to non-existant property \"%1\"").arg(QString::fromUtf8(prop->name))); + } + + } else if (prop->value) { + + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); + + } else if (QmlEnginePrivate::get(engine)->isQmlList(prop->type) || + QmlMetaType::isList(prop->type)) { + + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + + } else if (prop->type == qMetaTypeId<QmlScriptString>()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +bool +QmlCompiler::buildPropertyInNamespace(QmlEnginePrivate::ImportedNamespace *ns, + QmlParser::Property *nsProp, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (!nsProp->value) + COMPILE_EXCEPTION(nsProp, QCoreApplication::translate("QmlCompiler","Invalid use of namespace")); + + foreach (Property *prop, nsProp->value->properties) { + + if (!isAttachedPropertyName(prop->name)) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Not an attached property name")); + + // Setup attached property data + + QmlType *type = 0; + QmlEnginePrivate::get(engine)->resolveTypeInNamespace(ns, prop->name, + &type, 0, 0, 0); + + if (!type || !type->attachedPropertiesType()) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Non-existant attached object")); + + if (!prop->value) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->index(); + prop->value->metatype = type->attachedPropertiesType(); + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + } + + return true; +} + +void QmlCompiler::genValueProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if (QmlEnginePrivate::get(engine)->isQmlList(prop->type) || + QmlMetaType::isList(prop->type)) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QmlCompiler::genListProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QmlInstruction::Type fetchType; + QmlInstruction::Type storeType; + int listType; + + if (QmlEnginePrivate::get(engine)->isQmlList(prop->type)) { + fetchType = QmlInstruction::FetchQmlList; + storeType = QmlInstruction::StoreObjectQmlList; + listType = QmlEnginePrivate::get(engine)->qmlListType(prop->type); + } else { + fetchType = QmlInstruction::FetchQList; + storeType = QmlInstruction::StoreObjectQList; + listType = QmlMetaType::listType(prop->type); + } + + QmlInstruction fetch; + fetch.type = fetchType; + fetch.line = prop->location.start.line; + fetch.fetchQmlList.property = prop->index; + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; + output->bytecode << fetch; + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } else { + QmlInstruction store; + store.type = storeType; + store.line = prop->location.start.line; + output->bytecode << store; + } + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } + + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->location.start.line; + output->bytecode << pop; +} + +void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Property *valueTypeProperty) +{ + for (int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + + if (QmlMetaType::isInterface(prop->type)) { + + QmlInstruction store; + store.type = QmlInstruction::StoreInterface; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else if (prop->type == -1) { + + QmlInstruction store; + store.type = QmlInstruction::StoreVariantObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else { + + QmlInstruction store; + store.type = QmlInstruction::StoreObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } + } else if (v->type == Value::ValueSource) { + genObject(v->object); + + QmlInstruction store; + store.type = QmlInstruction::StoreValueSource; + store.line = v->object->location.start.line; + if (valueTypeProperty) { + store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty); + store.assignValueSource.owner = 1; + } else { + store.assignValueSource.property = genPropertyData(prop); + store.assignValueSource.owner = 0; + } + QmlType *valueType = toQmlType(v->object); + store.assignValueSource.castValue = valueType->propertyValueSourceCast(); + output->bytecode << store; + + } else if (v->type == Value::ValueInterceptor) { + genObject(v->object); + + QmlInstruction store; + store.type = QmlInstruction::StoreValueInterceptor; + store.line = v->object->location.start.line; + if (valueTypeProperty) { + store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty); + store.assignValueInterceptor.owner = 1; + } else { + store.assignValueInterceptor.property = genPropertyData(prop); + store.assignValueInterceptor.owner = 0; + } + QmlType *valueType = toQmlType(v->object); + store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast(); + output->bytecode << store; + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj, valueTypeProperty); + + } else if (v->type == Value::Literal) { + + QMetaProperty mp = obj->metaObject()->property(prop->index); + genLiteralAssignment(mp, v); + + } + + } +} + +bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if (prop->value || + prop->values.count() > 1 || + prop->values.at(0)->object) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid use of id property")); + + QmlParser::Value *idValue = prop->values.at(0); + QString val = idValue->primitive(); + + if (!isValidId(val)) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","\"%1\" is not a valid object id").arg(val)); + + // We disallow id's that conflict with import prefixes and types + QmlEnginePrivate::ImportedNamespace *ns = 0; + QmlType *type = 0; + QmlEnginePrivate::get(engine)->resolveType(unit->imports, val.toUtf8(), + &type, 0, 0, 0, &ns); + if (type) + COMPILE_EXCEPTION(idValue, QCoreApplication::translate("QmlCompiler","id conflicts with type name")); + if (ns) + COMPILE_EXCEPTION(idValue, QCoreApplication::translate("QmlCompiler","id conflicts with namespace prefix")); + + if (compileState.ids.contains(val)) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","id is not unique")); + + prop->values.at(0)->type = Value::Id; + + obj->id = val; + addId(val, obj); + + return true; +} + +void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) +{ + Q_ASSERT(!compileState.ids.contains(id)); + Q_ASSERT(obj->id == id); + obj->idIndex = compileState.ids.count(); + compileState.ids.insert(id, obj); + compileState.idIndexes.insert(obj->idIndex, obj); +} + +void QmlCompiler::addBindingReference(const BindingReference &ref) +{ + Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value)); + compileState.bindings.insert(ref.value, ref); +} + +void QmlCompiler::saveComponentState() +{ + Q_ASSERT(compileState.root); + Q_ASSERT(!savedCompileStates.contains(compileState.root)); + + savedCompileStates.insert(compileState.root, compileState); + savedComponentStats.append(componentStat); +} + +QmlCompiler::ComponentCompileState +QmlCompiler::componentState(QmlParser::Object *obj) +{ + Q_ASSERT(savedCompileStates.contains(obj)); + return savedCompileStates.value(obj); +} + +// Build attached property object. In this example, +// Text { +// GridView.row: 10 +// } +// GridView is an attached property object. +bool QmlCompiler::buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->value); + Q_ASSERT(prop->index != -1); // This is set in buildProperty() + + obj->addAttachedProperty(prop); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + + return true; +} + + +// Build "grouped" properties. In this example: +// Text { +// font.pointSize: 12 +// font.family: "Helvetica" +// } +// font is a nested property. pointSize and family are not. +bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->type != 0); + Q_ASSERT(prop->index != -1); + + if (prop->values.count()) + COMPILE_EXCEPTION(prop->values.first(), QCoreApplication::translate("QmlCompiler", "Invalid value in grouped property")); + + if (prop->type < (int)QVariant::UserType) { + QmlEnginePrivate *ep = + static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine)); + if (prop->type >= 0 /* QVariant == -1 */ && ep->valueTypes[prop->type]) { + COMPILE_CHECK(buildValueTypeProperty(ep->valueTypes[prop->type], + prop->value, obj, ctxt.incr())); + obj->addValueTypeProperty(prop); + } else { + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid grouped property access")); + } + + } else { + // Load the nested property's meta type + prop->value->metatype = + QmlEnginePrivate::get(engine)->metaObjectForType(prop->type); + if (!prop->value->metatype) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid grouped property access")); + + obj->addGroupedProperty(prop); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + } + + return true; +} + +bool QmlCompiler::buildValueTypeProperty(QObject *type, + QmlParser::Object *obj, + QmlParser::Object *baseObj, + const BindingContext &ctxt) +{ + if (obj->defaultProperty) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","Invalid property use")); + obj->metatype = type->metaObject(); + + foreach (Property *prop, obj->properties) { + int idx = type->metaObject()->indexOfProperty(prop->name.constData()); + if (idx == -1) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Cannot assign to non-existant property \"%1\"").arg(QString::fromUtf8(prop->name))); + QMetaProperty p = type->metaObject()->property(idx); + prop->index = idx; + prop->type = p.userType(); + + if (prop->value) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Property assignment expected")); + + if (prop->values.count() != 1) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Single property assignment expected")); + + Value *value = prop->values.at(0); + + if (value->object) { + bool isPropertyValue = output->types.at(value->object->type).type->propertyValueSourceCast() != -1; + bool isPropertyInterceptor = output->types.at(value->object->type).type->propertyValueInterceptorCast() != -1; + if (!isPropertyValue && !isPropertyInterceptor) { + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Unexpected object assignment")); + } else { + COMPILE_CHECK(buildObject(value->object, ctxt)); + + if (isPropertyInterceptor && baseObj->synthdata.isEmpty()) + buildDynamicMeta(baseObj, ForceCreation); + value->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; + } + } else if (value->value.isScript()) { + // ### Check for writability + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.bindingContext = ctxt; + reference.bindingContext.owner++; + addBindingReference(reference); + value->type = Value::PropertyBinding; + } else { + COMPILE_CHECK(testLiteralAssignment(p, value)); + value->type = Value::Literal; + } + obj->addValueProperty(prop); + } + + return true; +} + +// Build assignments to QML lists. QML lists are properties of type +// QList<T *> * and QmlList<T *> *. +// +// QList<T *> * types can accept a list of objects, or a single binding +// QmlList<T *> * types can accept a list of objects +bool QmlCompiler::buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(QmlMetaType::isList(prop->type) || + QmlEnginePrivate::get(engine)->isQmlList(prop->type)); + + int t = prop->type; + + obj->addValueProperty(prop); + + if (QmlEnginePrivate::get(engine)->isQmlList(t)) { + int listType = QmlEnginePrivate::get(engine)->qmlListType(t); + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if (v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(buildObject(v->object, ctxt)); + + // We check object coercian here. We check interface assignment + // at runtime. + if (!listTypeIsInterface) { + if (!canCoerce(listType, v->object)) { + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Cannot assign object to list")); + } + } + + } else { + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Cannot assign primitives to lists")); + } + } + + } else { + int listType = QmlMetaType::listType(t); + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + + bool assignedBinding = false; + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if (v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(buildObject(v->object, ctxt)); + + // We check object coercian here. We check interface assignment + // at runtime. + if (!listTypeIsInterface) { + if (!canCoerce(listType, v->object)) { + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Cannot assign object to list")); + } + } + + } else if (v->value.isScript()) { + if (assignedBinding) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Can only assign one binding to lists")); + + assignedBinding = true; + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + v->type = Value::PropertyBinding; + } else { + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Cannot assign primitives to lists")); + } + } + + } + + return true; +} + +// Compiles an assignment to a QmlScriptString property +bool QmlCompiler::buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(1), QCoreApplication::translate("QmlCompiler", "Cannot assign multiple values to a script property")); + + if (prop->values.at(0)->object || !prop->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop->values.at(0), QCoreApplication::translate("QmlCompiler", "Invalid property assignment: script expected")); + + obj->addScriptStringProperty(prop, ctxt.stack); + + return true; +} + +// Compile regular property assignments of the form "property: <value>" +// +// ### The following problems exist +// +// There is no distinction between how "lists" of values are specified. This +// Item { +// children: Item {} +// children: Item {} +// } +// is identical to +// Item { +// children: [ Item {}, Item {} ] +// } +// +// We allow assignming multiple values to single value properties +bool QmlCompiler::buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + obj->addValueProperty(prop); + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if (v->object) { + + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); + + } + } + + return true; +} + +// Compile assigning a single object instance to a regular property +bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); + + if (!obj->metaObject()->property(prop->index).isWritable()) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + + if (QmlMetaType::isInterface(prop->type)) { + + // Assigning an object to an interface ptr property + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + + } else if (prop->type == -1) { + + // Assigning an object to a QVariant + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else { + // Normally buildObject() will set this up, but we need the static + // meta object earlier to test for assignability. It doesn't matter + // that there may still be outstanding synthesized meta object changes + // on this type, as they are not relevant for assignability testing + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); + + // Will be true if the assigned type inherits QmlPropertyValueSource + bool isPropertyValue = false; + // Will be true if the assigned type inherits QmlPropertyValueInterceptor + bool isPropertyInterceptor = false; + if (QmlType *valueType = toQmlType(v->object)) { + isPropertyValue = valueType->propertyValueSourceCast() != -1; + isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1; + } + + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions that might + // effect the properties on the type, but don't effect assignability + const QMetaObject *propertyMetaObject = + QmlEnginePrivate::get(engine)->rawMetaObjectForType(prop->type); + + // Will be true if the assgned type inherits propertyMetaObject + bool isAssignable = false; + // Determine isAssignable value + if (propertyMetaObject) { + const QMetaObject *c = v->object->metatype; + while(c) { + isAssignable |= (QmlMetaPropertyPrivate::equal(c, propertyMetaObject)); + c = c->superClass(); + } + } + + if (isAssignable) { + // Simple assignment + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else if (propertyMetaObject == &QmlComponent::staticMetaObject) { + // Automatic "Component" insertion + QmlParser::Object *root = v->object; + QmlParser::Object *component = new QmlParser::Object; + component->type = componentTypeRef(); + component->typeName = "Qt/Component"; + component->metatype = &QmlComponent::staticMetaObject; + component->location = root->location; + QmlParser::Value *componentValue = new QmlParser::Value; + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + } else if (isPropertyValue || isPropertyInterceptor) { + // Assign as a property value source + COMPILE_CHECK(buildObject(v->object, ctxt)); + + if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) + buildDynamicMeta(prop->parent, ForceCreation); + v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; + } else { + COMPILE_EXCEPTION(v->object, QCoreApplication::translate("QmlCompiler","Cannot assign object to property")); + } + } + + return true; +} + +// Compile assigning a literal or binding to a regular property +bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + + if (v->value.isScript()) { + + //optimization for <Type>.<EnumValue> enum assignments + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment)); + if (isEnumAssignment) { + v->type = Value::Literal; + return true; + } + + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + + v->type = Value::PropertyBinding; + + } else { + + COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); + + v->type = Value::Literal; + } + + return true; +} + +bool QmlCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, + QmlParser::Object *obj, + QmlParser::Value *v, + bool *isAssignment) +{ + *isAssignment = false; + if (!prop.isEnumType()) + return true; + + if (!prop.isWritable()) + COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + + QString string = v->value.asString(); + if (!string.at(0).isUpper()) + return true; + + QStringList parts = string.split(QLatin1Char('.')); + if (parts.count() != 2) + return true; + + QString typeName = parts.at(0); + QmlType *type = 0; + QmlEnginePrivate::get(engine)->resolveType(unit->imports, typeName.toUtf8(), + &type, 0, 0, 0, 0); + + if (!type || obj->typeName != type->qmlTypeName()) + return true; + + QString enumValue = parts.at(1); + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(enumValue.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(enumValue.toUtf8().constData()); + if (value == -1) + return true; + + v->type = Value::Literal; + v->value = QmlParser::Variant(enumValue); + *isAssignment = true; + + return true; +} + +// Ensures that the dynamic meta specification on obj is valid +bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) +{ + QSet<QByteArray> propNames; + QSet<QByteArray> methodNames; + bool seenDefaultProperty = false; + + // Check properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const QmlParser::Object::DynamicProperty &prop = + obj->dynamicProperties.at(ii); + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION(&prop, QCoreApplication::translate("QmlCompiler","Duplicate default property")); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION(&prop, QCoreApplication::translate("QmlCompiler","Duplicate property name")); + + propNames.insert(prop.name); + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + QByteArray name = obj->dynamicSignals.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","Duplicate signal name")); + methodNames.insert(name); + } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + QByteArray name = obj->dynamicSlots.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","Duplicate method name")); + methodNames.insert(name); + } + + return true; +} + +bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj) +{ + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p.isDefaultProperty) + property = obj->getDefaultProperty(); + else + property = obj->getProperty(p.name); + + if (property->value) + COMPILE_EXCEPTION(property, QCoreApplication::translate("QmlCompiler","Invalid property nesting")); + + for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { + Value *v = p.defaultValue->values.at(ii); + v->addref(); + property->values.append(v); + } + } + return true; +} + +Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) + +bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) +{ + Q_ASSERT(obj); + Q_ASSERT(obj->metatype); + + if (mode != ForceCreation && + obj->dynamicProperties.isEmpty() && + obj->dynamicSignals.isEmpty() && + obj->dynamicSlots.isEmpty()) + return true; + + COMPILE_CHECK(checkDynamicMeta(obj)); + + QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0); + + QByteArray newClassName = obj->metatype->className(); + newClassName.append("_QML_"); + int idx = classIndexCounter()->fetchAndAddRelaxed(1); + newClassName.append(QByteArray::number(idx)); + if (compileState.root == obj) { + QString path = output->url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + if (lastSlash > -1) { + QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); + } + } + + QMetaObjectBuilder builder; + builder.setClassName(newClassName); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + + bool hasAlias = false; + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + int propIdx = + obj->metaObject()->indexOfProperty(p.name.constData()); + if (-1 != propIdx) { + QMetaProperty prop = obj->metaObject()->property(propIdx); + if (prop.isFinal()) + COMPILE_EXCEPTION(&p, QCoreApplication::translate("QmlCompiler","Cannot override FINAL property")); + } + + if (p.isDefaultProperty && + (p.type != Object::DynamicProperty::Alias || + mode == ResolveAliases)) + builder.addClassInfo("DefaultProperty", p.name); + + QByteArray type; + int propertyType = 0; + bool readonly = false; + switch(p.type) { + case Object::DynamicProperty::Alias: + hasAlias = true; + continue; + break; + case Object::DynamicProperty::CustomList: + case Object::DynamicProperty::Custom: + { + QByteArray customTypeName; + QmlType *qmltype = 0; + QUrl url; + QmlEnginePrivate *priv = QmlEnginePrivate::get(engine); + if (!priv->resolveType(unit->imports, p.customType, &qmltype, + &url, 0, 0, 0)) + COMPILE_EXCEPTION(&p, QCoreApplication::translate("QmlCompiler","Invalid property type")); + + if (!qmltype) { + QmlCompositeTypeData *tdata = priv->typeManager.get(url); + Q_ASSERT(tdata); + Q_ASSERT(tdata->status == QmlCompositeTypeData::Complete); + + QmlCompiledData *data = tdata->toCompiledComponent(engine); + customTypeName = data->root->className(); + } else { + customTypeName = qmltype->typeName(); + } + + if (p.type == Object::DynamicProperty::Custom) { + type = customTypeName + '*'; + propertyType = QMetaType::QObjectStar; + } else { + readonly = true; + type = "QmlList<"; + type.append(customTypeName); + type.append("*>*"); + propertyType = qMetaTypeId<QmlList<QObject*>* >(); + } + } + break; + case Object::DynamicProperty::Variant: + propertyType = -1; + type = "QVariant"; + break; + case Object::DynamicProperty::Int: + propertyType = QVariant::Int; + type = "int"; + break; + case Object::DynamicProperty::Bool: + propertyType = QVariant::Bool; + type = "bool"; + break; + case Object::DynamicProperty::Real: + propertyType = QVariant::Double; + type = "double"; + break; + case Object::DynamicProperty::String: + propertyType = QVariant::String; + type = "QString"; + break; + case Object::DynamicProperty::Url: + propertyType = QVariant::Url; + type = "QUrl"; + break; + case Object::DynamicProperty::Color: + propertyType = QVariant::Color; + type = "QColor"; + break; + case Object::DynamicProperty::Date: + propertyType = QVariant::Date; + type = "QDate"; + break; + } + + ((QmlVMEMetaData *)dynamicData.data())->propertyCount++; + QmlVMEMetaData::PropertyData propertyData = { propertyType }; + dynamicData.append((char *)&propertyData, sizeof(propertyData)); + + builder.addSignal(p.name + "Changed()"); + QMetaPropertyBuilder propBuilder = + builder.addProperty(p.name, type, builder.methodCount() - 1); + propBuilder.setScriptable(true); + propBuilder.setWritable(!readonly); + } + + if (mode == ResolveAliases) { + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (p.type == Object::DynamicProperty::Alias) { + ((QmlVMEMetaData *)dynamicData.data())->aliasCount++; + compileAlias(builder, dynamicData, obj, p); + } + } + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); + QByteArray sig(s.name + '('); + for (int jj = 0; jj < s.parameterTypes.count(); ++jj) { + if (jj) sig.append(','); + sig.append(s.parameterTypes.at(jj)); + } + sig.append(')'); + QMetaMethodBuilder b = builder.addSignal(sig); + b.setParameterNames(s.parameterNames); + ((QmlVMEMetaData *)dynamicData.data())->signalCount++; + } + + QStringList funcScripts; + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + Object::DynamicSlot &s = obj->dynamicSlots[ii]; + QByteArray sig(s.name + '('); + QString funcScript(QLatin1String("(function(")); + + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj) { + sig.append(','); + funcScript.append(QLatin1Char(',')); + } + funcScript.append(QLatin1String(s.parameterNames.at(jj))); + sig.append("QVariant"); + } + sig.append(')'); + funcScript.append(QLatin1Char(')')); + funcScript.append(s.body); + funcScript.append(QLatin1Char(')')); + funcScripts << funcScript; + + QMetaMethodBuilder b = builder.addSlot(sig); + b.setReturnType("QVariant"); + b.setParameterNames(s.parameterNames); + + ((QmlVMEMetaData *)dynamicData.data())->methodCount++; + QmlVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, funcScript.length(), 0 }; + + dynamicData.append((char *)&methodData, sizeof(methodData)); + } + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const QString &funcScript = funcScripts.at(ii); + QmlVMEMetaData::MethodData *data = + ((QmlVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)funcScript.constData(), + (funcScript.length() * sizeof(QChar))); + } + + obj->metadata = builder.toRelocatableData(); + builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); + + if (mode == IgnoreAliases && hasAlias) + compileState.aliasingObjects << obj; + + obj->synthdata = dynamicData; + + return true; +} + +#include <qmljsparser_p.h> + +static QStringList astNodeToStringList(QmlJS::AST::Node *node) +{ + if (node->kind == QmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QmlJS::AST::IdentifierExpression *>(node)->name->asString(); + return QStringList() << name; + } else if (node->kind == QmlJS::AST::Node::Kind_FieldMemberExpression) { + QmlJS::AST::FieldMemberExpression *expr = static_cast<QmlJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name->asString()); + return rv; + } + return QStringList(); +} + +bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, + QByteArray &data, + Object *obj, + const Object::DynamicProperty &prop) +{ + if (!prop.defaultValue) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","No property alias location")); + + if (prop.defaultValue->values.count() != 1 || + prop.defaultValue->values.at(0)->object || + !prop.defaultValue->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias location")); + + QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + if (!node) + COMPILE_EXCEPTION(obj, QCoreApplication::translate("QmlCompiler","No property alias location")); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() != 1 && alias.count() != 2) + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias reference. An alias reference must be specified as <id> or <id>.<property>")); + + if (!compileState.ids.contains(alias.at(0))) + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); + + Object *idObject = compileState.ids[alias.at(0)]; + + QByteArray typeName; + + int propIdx = -1; + int flags = 0; + bool writable = false; + if (alias.count() == 2) { + propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + + if (-1 == propIdx) + COMPILE_EXCEPTION(prop.defaultValue, QCoreApplication::translate("QmlCompiler","Invalid alias location")); + + QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); + writable = aliasProperty.isWritable(); + + if (aliasProperty.isEnumType()) + typeName = "int"; // Avoid introducing a dependency on the aliased metaobject + else + typeName = aliasProperty.typeName(); + } else { + typeName = idObject->metaObject()->className(); + + //use the base type since it has been registered with metatype system + int index = typeName.indexOf("_QML_"); + if (index != -1) { + typeName = typeName.left(index); + } else { + index = typeName.indexOf("_QMLTYPE_"); + const QMetaObject *mo = idObject->metaObject(); + while (index != -1 && mo) { + typeName = mo->superClass()->className(); + index = typeName.indexOf("_QMLTYPE_"); + mo = mo->superClass(); + } + } + + typeName += '*'; + } + + if (typeName.endsWith('*')) + flags |= QML_ALIAS_FLAG_PTR; + + data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); + data.append((const char *)&propIdx, sizeof(propIdx)); + data.append((const char *)&flags, sizeof(flags)); + + builder.addSignal(prop.name + "Changed()"); + QMetaPropertyBuilder propBuilder = + builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1); + propBuilder.setScriptable(true); + propBuilder.setWritable(writable); + return true; +} + +bool QmlCompiler::buildBinding(QmlParser::Value *value, + QmlParser::Property *prop, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); + + QMetaProperty mp = prop->parent->metaObject()->property(prop->index); + if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) + COMPILE_EXCEPTION(prop, QCoreApplication::translate("QmlCompiler","Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.bindingContext = ctxt; + addBindingReference(reference); + + return true; +} + +void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Property *valueTypeProperty) +{ + Q_UNUSED(obj); + Q_ASSERT(compileState.bindings.contains(binding)); + + const BindingReference &ref = compileState.bindings.value(binding); + if (ref.dataType == BindingReference::Experimental) { + QmlInstruction store; + store.type = QmlInstruction::StoreCompiledBinding; + store.assignBinding.value = ref.compiledIndex; + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + if (valueTypeProperty) + store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) | + ((valueTypeProperty->type & 0xFF)) << 16 | + ((prop->index & 0xFF) << 24); + else + store.assignBinding.property = prop->index; + store.line = binding->location.start.line; + output->bytecode << store; + return; + } + + QmlInstruction store; + store.type = QmlInstruction::StoreBinding; + store.assignBinding.value = output->indexForByteArray(ref.compiledData); + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + store.line = binding->location.start.line; + + Q_ASSERT(ref.bindingContext.owner == 0 || + (ref.bindingContext.owner != 0 && valueTypeProperty)); + if (ref.bindingContext.owner) { + store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.assignBinding.property = genPropertyData(prop); + } + + output->bytecode << store; +} + +int QmlCompiler::genContextCache() +{ + if (compileState.ids.count() == 0) + return -1; + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + for (QHash<QString, QmlParser::Object *>::ConstIterator iter = compileState.ids.begin(); + iter != compileState.ids.end(); + ++iter) + cache->add(iter.key(), (*iter)->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + +int QmlCompiler::genValueTypeData(QmlParser::Property *valueTypeProp, + QmlParser::Property *prop) +{ + return output->indexForByteArray(QmlMetaPropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index, valueTypeProp->index, valueTypeProp->type)); +} + +int QmlCompiler::genPropertyData(QmlParser::Property *prop) +{ + return output->indexForByteArray(QmlMetaPropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index)); +} + +bool QmlCompiler::completeComponentBuild() +{ + componentStat.ids = compileState.ids.count(); + + for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { + Object *aliasObject = compileState.aliasingObjects.at(ii); + COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + } + + QmlBindingCompiler::Expression expr; + expr.component = compileState.root; + expr.ids = compileState.ids; + + QmlBindingCompiler bindingCompiler; + + for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { + BindingReference &binding = *iter; + + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; + expr.imports = unit->imports; + + if (qmlExperimental()) { + int index = bindingCompiler.compile(expr, QmlEnginePrivate::get(engine)); + if (index != -1) { + qWarning() << "Accepted for optimization:" << qPrintable(expr.expression.asScript()); + binding.dataType = BindingReference::Experimental; + binding.compiledIndex = index; + componentStat.optimizedBindings++; + continue; + } else { + qWarning() << "Rejected for optimization:" << qPrintable(expr.expression.asScript()); + } + } + + binding.dataType = BindingReference::QtScript; + + // Pre-rewrite the expression + QString expression = binding.expression.asScript(); + + // ### Optimize + QmlRewrite::SharedBindingTester sharableTest; + bool isSharable = sharableTest.isSharable(expression); + + QmlRewrite::RewriteBinding rewriteBinding; + expression = rewriteBinding(expression); + + quint32 length = expression.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); + } + + binding.compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)expression.constData(), + expression.length() * sizeof(QChar)); + + componentStat.scriptBindings++; + } + + if (bindingCompiler.isValid()) { + compileState.compiledBindingData = bindingCompiler.program(); + QmlBindingCompiler::dump(compileState.compiledBindingData); + } + + saveComponentState(); + + return true; +} + +void QmlCompiler::dumpStats() +{ + qWarning().nospace() << "QML Document: " << output->url.toString(); + for (int ii = 0; ii < savedComponentStats.count(); ++ii) { + const ComponentStat &stat = savedComponentStats.at(ii); + qWarning().nospace() << " Component Line " << stat.lineNumber; + qWarning().nospace() << " Total Objects: " << stat.objects; + qWarning().nospace() << " IDs Used: " << stat.ids; + qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings; + qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings; + } +} + +/*! + Returns true if from can be assigned to a (QObject) property of type + to. +*/ +bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) +{ + const QMetaObject *toMo = + QmlEnginePrivate::get(engine)->rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); + + while (fromMo) { + if (QmlMetaPropertyPrivate::equal(fromMo, toMo)) + return true; + fromMo = fromMo->superClass(); + } + return false; +} + +/*! + Returns true if from can be assigned to a (QObject) property of type + to. +*/ +bool QmlCompiler::canCoerce(int to, int from) +{ + const QMetaObject *toMo = + QmlEnginePrivate::get(engine)->rawMetaObjectForType(to); + const QMetaObject *fromMo = + QmlEnginePrivate::get(engine)->rawMetaObjectForType(from); + + while (fromMo) { + if (QmlMetaPropertyPrivate::equal(fromMo, toMo)) + return true; + fromMo = fromMo->superClass(); + } + return false; +} + +QmlType *QmlCompiler::toQmlType(QmlParser::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QmlType *type = 0; + while (!type && mo) { + type = QmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + +QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) +{ + const QMetaObject *mo = obj->metatype; + + int idx = mo->indexOfClassInfo("DeferredPropertyNames"); + if (idx == -1) + return QStringList(); + + QMetaClassInfo classInfo = mo->classInfo(idx); + QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); + return rv; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h new file mode 100644 index 0000000..f3f266b --- /dev/null +++ b/src/declarative/qml/qmlcompiler_p.h @@ -0,0 +1,337 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPILER_P_H +#define QMLCOMPILER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qml.h" +#include "qmlerror.h" +#include "qmlinstruction_p.h" +#include "qmlcompositetypemanager_p.h" +#include "qmlparser_p.h" +#include "qmlengine_p.h" +#include "qbitfield_p.h" +#include "qmlpropertycache_p.h" +#include "qmlintegercache_p.h" +#include "qmltypenamecache_p.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlComponent; +class QmlContext; + +class QScriptProgram; +class Q_AUTOTEST_EXPORT QmlCompiledData : public QmlRefCount, public QmlCleanup +{ +public: + QmlCompiledData(QmlEngine *engine); + virtual ~QmlCompiledData(); + + QString name; + QUrl url; + QmlEnginePrivate::Imports imports; + QmlTypeNameCache *importCache; + + struct TypeReference + { + TypeReference() + : type(0), component(0), ref(0) {} + + QByteArray className; + QmlType *type; + QmlComponent *component; + + QmlRefCount *ref; + QObject *createInstance(QmlContext *, const QBitField &) const; + const QMetaObject *metaObject() const; + }; + QList<TypeReference> types; + struct CustomTypeData + { + int index; + int type; + }; + + const QMetaObject *root; + QAbstractDynamicMetaObject rootData; + QmlPropertyCache *rootPropertyCache; + QList<QString> primitives; + QList<float> floatData; + QList<int> intData; + QList<CustomTypeData> customTypeData; + QList<QByteArray> datas; + QList<QmlParser::Location> locations; + QList<QmlInstruction> bytecode; + QList<QScriptProgram *> cachedPrograms; + QList<QScriptValue *> cachedClosures; + QList<QmlPropertyCache *> propertyCaches; + QList<QmlIntegerCache *> contextCaches; + QList<QmlParser::Object::ScriptBlock> scripts; + QList<QUrl> urls; + + void dumpInstructions(); + +protected: + virtual void clear(); // From QmlCleanup + +private: + void dump(QmlInstruction *, int idx = -1); + QmlCompiledData(const QmlCompiledData &other); + QmlCompiledData &operator=(const QmlCompiledData &other); + QByteArray packData; + friend class QmlCompiler; + int pack(const char *, size_t); + + int indexForString(const QString &); + int indexForByteArray(const QByteArray &); + int indexForFloat(float *, int); + int indexForInt(int *, int); + int indexForLocation(const QmlParser::Location &); + int indexForLocation(const QmlParser::LocationSpan &); + int indexForUrl(const QUrl &); +}; + +class QMetaObjectBuilder; +class Q_DECLARATIVE_EXPORT QmlCompiler +{ +public: + QmlCompiler(); + + bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledData *); + + bool isError() const; + QList<QmlError> errors() const; + + static bool isValidId(const QString &); + static bool isAttachedPropertyName(const QByteArray &); + static bool isSignalPropertyName(const QByteArray &); + +private: + static void reset(QmlCompiledData *); + + struct BindingContext { + BindingContext() + : stack(0), owner(0), object(0) {} + BindingContext(QmlParser::Object *o) + : stack(0), owner(0), object(o) {} + BindingContext incr() const { + BindingContext rv(object); + rv.stack = stack + 1; + return rv; + } + bool isSubContext() const { return stack != 0; } + int stack; + int owner; + QmlParser::Object *object; + }; + + void compileTree(QmlParser::Object *tree); + + + bool buildObject(QmlParser::Object *obj, const BindingContext &); + bool buildScript(QmlParser::Object *obj, QmlParser::Object *script); + bool buildComponent(QmlParser::Object *obj, const BindingContext &); + bool buildSubObject(QmlParser::Object *obj, const BindingContext &); + bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildProperty(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildPropertyInNamespace(QmlEnginePrivate::ImportedNamespace *ns, + QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &); + bool buildIdProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildValueTypeProperty(QObject *type, + QmlParser::Object *obj, + QmlParser::Object *baseObj, + const BindingContext &ctxt); + bool buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool doesPropertyExist(QmlParser::Property *prop, QmlParser::Object *obj); + bool testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + bool testQualifiedEnumAssignment(const QMetaProperty &prop, + QmlParser::Object *obj, + QmlParser::Value *value, + bool *isAssignment); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation }; + bool mergeDynamicMetaProperties(QmlParser::Object *obj); + bool buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QmlParser::Object *obj); + bool buildBinding(QmlParser::Value *, QmlParser::Property *prop, + const BindingContext &ctxt); + bool buildComponentFromRoot(QmlParser::Object *obj, const BindingContext &); + bool compileAlias(QMetaObjectBuilder &, + QByteArray &data, + QmlParser::Object *obj, + const QmlParser::Object::DynamicProperty &); + bool completeComponentBuild(); + + + void genObject(QmlParser::Object *obj); + void genObjectBody(QmlParser::Object *obj); + void genComponent(QmlParser::Object *obj); + void genValueProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genListProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Property *valueTypeProperty = 0); + void genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + void genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Property *valueTypeProperty = 0); + int genContextCache(); + + int genValueTypeData(QmlParser::Property *prop, QmlParser::Property *valueTypeProp); + int genPropertyData(QmlParser::Property *prop); + + int componentTypeRef(); + + static int findSignalByName(const QMetaObject *, const QByteArray &name); + static QmlType *toQmlType(QmlParser::Object *from); + bool canCoerce(int to, QmlParser::Object *from); + bool canCoerce(int to, int from); + + QStringList deferredProperties(QmlParser::Object *); + + void addId(const QString &, QmlParser::Object *); + + void dumpStats(); + + struct BindingReference { + QmlParser::Variant expression; + QmlParser::Property *property; + QmlParser::Value *value; + + enum DataType { QtScript, Experimental }; + DataType dataType; + + int compiledIndex; + + QByteArray compiledData; + BindingContext bindingContext; + }; + void addBindingReference(const BindingReference &); + + struct ComponentCompileState + { + ComponentCompileState() + : parserStatusCount(0), pushedProperties(0), root(0) {} + QHash<QString, QmlParser::Object *> ids; + QHash<int, QmlParser::Object *> idIndexes; + int parserStatusCount; + int pushedProperties; + + QByteArray compiledBindingData; + + QHash<QmlParser::Value *, BindingReference> bindings; + QList<QmlParser::Object *> aliasingObjects; + QmlParser::Object *root; + }; + ComponentCompileState compileState; + + struct ComponentStat + { + ComponentStat() + : ids(0), scriptBindings(0), optimizedBindings(0), objects(0) {} + + int lineNumber; + + int ids; + int scriptBindings; + int optimizedBindings; + int objects; + }; + ComponentStat componentStat; + + void saveComponentState(); + + ComponentCompileState componentState(QmlParser::Object *); + QHash<QmlParser::Object *, ComponentCompileState> savedCompileStates; + QList<ComponentStat> savedComponentStats; + + QList<QmlError> exceptions; + QmlCompiledData *output; + QmlEngine *engine; + QmlParser::Object *unitRoot; + QmlCompositeTypeData *unit; +}; +QT_END_NAMESPACE + +#endif // QMLCOMPILER_P_H diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp new file mode 100644 index 0000000..9e06016 --- /dev/null +++ b/src/declarative/qml/qmlcomponent.cpp @@ -0,0 +1,798 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" + +#include "qmlcompiler_p.h" +#include "qmlcontext_p.h" +#include "qmlcompositetypedata_p.h" +#include "qmlengine_p.h" +#include "qmlvme_p.h" +#include "qml.h" +#include "qmlengine.h" +#include "qmlbinding.h" +#include "qmlbinding_p.h" +#include "qmlglobal_p.h" +#include "qmlscriptparser_p.h" + +#include <qfxperf_p_p.h> + +#include <QStack> +#include <QStringList> +#include <QFileInfo> +#include <QtCore/qdebug.h> +#include <QApplication> + +QT_BEGIN_NAMESPACE + +class QByteArray; +int statusId = qRegisterMetaType<QmlComponent::Status>("QmlComponent::Status"); + +/*! + \class QmlComponent + \brief The QmlComponent class encapsulates a QML component description. + \mainclass +*/ + +/*! + \qmlclass Component QmlComponent + \brief The Component element encapsulates a QML component description. + + Components are reusable, encapsulated Qml element with a well-defined interface. + They are often defined in \l {qmldocuments.html}{Component Files}. + + The \e Component element allows defining components within a QML file. + This can be useful for reusing a small component within a single QML + file, or for defining a component that logically belongs with the + file containing it. + + \qml +Item { + Component { + id: redSquare + Rectangle { + color: "red" + width: 10 + height: 10 + } + } + Loader { sourceComponent: redSquare } + Loader { sourceComponent: redSquare; x: 20 } +} + \endqml + + \section1 Attached Properties + + \e onCompleted + + Emitted after component "startup" has completed. This can be used to + execute script code at startup, once the full QML environment has been + established. + + The \c {Component::onCompleted} attached property can be applied to + any element. The order of running the \c onCompleted scripts is + undefined. + + \qml + Rectangle { + Component.onCompleted: console.log("Completed Running!") + Rectangle { + Component.onCompleted: console.log("Nested Completed Running!") + } + } + \endqml +*/ +QML_DEFINE_TYPE(Qt,4,6,Component,QmlComponent); + +/*! + \enum QmlComponent::Status + + Specifies the loading status of the QmlComponent. + + \value Null This QmlComponent has no data. Call loadUrl() or setData() to add QML content. + \value Ready This QmlComponent is ready and create() may be called. + \value Loading This QmlComponent is loading network data. + \value Error An error has occured. Calling errorDescription() to retrieve a description. +*/ + +void QmlComponentPrivate::typeDataReady() +{ + Q_Q(QmlComponent); + + Q_ASSERT(typeData); + + fromTypeData(typeData); + typeData = 0; + + emit q->statusChanged(q->status()); +} + +void QmlComponentPrivate::updateProgress(qreal p) +{ + Q_Q(QmlComponent); + + progress = p; + emit q->progressChanged(p); +} + +void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) +{ + url = data->imports.baseUrl(); + QmlCompiledData *c = data->toCompiledComponent(engine); + + if (!c) { + Q_ASSERT(data->status == QmlCompositeTypeData::Error); + + state.errors = data->errors; + + } else { + + cc = c; + + } + + data->release(); +} + +void QmlComponentPrivate::clear() +{ + if (typeData) { + typeData->remWaiter(this); + typeData->release(); + typeData = 0; + } + + if (cc) { + cc->release(); + cc = 0; + } +} + +/*! + \internal +*/ +QmlComponent::QmlComponent(QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ +} + +/*! + Destruct the QmlComponent. +*/ +QmlComponent::~QmlComponent() +{ + Q_D(QmlComponent); + + if (d->state.completePending) { + qWarning("QmlComponent: Component destroyed while completion pending"); + d->completeCreate(); + } + + if (d->typeData) { + d->typeData->remWaiter(d); + d->typeData->release(); + } + if (d->cc) + d->cc->release(); +} + +/*! + \property QmlComponent::status + The component's current \l{QmlComponent::Status} {status}. + */ +QmlComponent::Status QmlComponent::status() const +{ + Q_D(const QmlComponent); + + if (d->typeData) + return Loading; + else if (!d->state.errors.isEmpty()) + return Error; + else if (d->engine && d->cc) + return Ready; + else + return Null; +} + +/*! + \property QmlComponent::isNull + + Is true if the component is in the Null state, false otherwise. + + Equivalent to status() == QmlComponent::Null. +*/ +bool QmlComponent::isNull() const +{ + return status() == Null; +} + +/*! + \property QmlComponent::isReady + + Is true if the component is in the Ready state, false otherwise. + + Equivalent to status() == QmlComponent::Ready. +*/ +bool QmlComponent::isReady() const +{ + return status() == Ready; +} + +/*! + \property QmlComponent::isError + + Is true if the component is in the Error state, false otherwise. + + Equivalent to status() == QmlComponent::Error. +*/ +bool QmlComponent::isError() const +{ + return status() == Error; +} + +/*! + \property QmlComponent::isLoading + + Is true if the component is in the Loading state, false otherwise. + + Equivalent to status() == QmlComponent::Loading. +*/ +bool QmlComponent::isLoading() const +{ + return status() == Loading; +} + +/*! + \property QmlComponent::progress + The progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ +qreal QmlComponent::progress() const +{ + Q_D(const QmlComponent); + return d->progress; +} + +/*! + \fn void QmlComponent::progressChanged(qreal progress) + + Emitted whenever the component's loading progress changes. \a progress will be the + current progress between 0.0 (nothing loaded) and 1.0 (finished). +*/ + +/*! + \fn void QmlComponent::statusChanged(QmlComponent::Status status) + + Emitted whenever the component's status changes. \a status will be the + new status. +*/ + +/*! + Create a QmlComponent with no data and give it the specified + \a engine and \a parent. Set the data with setData(). +*/ +QmlComponent::QmlComponent(QmlEngine *engine, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; +} + +/*! + Create a QmlComponent from the given \a url and give it the + specified \a parent and \a engine. + + \sa loadUrl() +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent) +: QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + loadUrl(url); +} + +/*! + Create a QmlComponent from the given \a fileName and give it the specified + \a parent and \a engine. + + \sa loadUrl() +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QString &fileName, + QObject *parent) +: QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + loadUrl(QUrl::fromLocalFile(fileName)); +} + +/*! + \internal +*/ +QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledData *cc, int start, int count, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + d->cc = cc; + cc->addref(); + d->start = start; + d->count = count; + d->url = cc->url; + d->progress = 1.0; +} + +/*! + Sets the QmlComponent to use the given QML \a data. If \a url + is provided, it is used to set the component name and to provide + a base path for items resolved by this component. +*/ +void QmlComponent::setData(const QByteArray &data, const QUrl &url) +{ + Q_D(QmlComponent); + + d->clear(); + + d->url = url; + + QmlCompositeTypeData *typeData = + QmlEnginePrivate::get(d->engine)->typeManager.getImmediate(data, url); + + if (typeData->status == QmlCompositeTypeData::Waiting + || typeData->status == QmlCompositeTypeData::WaitingResources) + { + d->typeData = typeData; + d->typeData->addWaiter(d); + + } else { + + d->fromTypeData(typeData); + + } + + d->progress = 1.0; + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! +Returns the QmlContext the component was created in. This is only +valid for components created directly from QML. +*/ +QmlContext *QmlComponent::creationContext() const +{ + Q_D(const QmlComponent); + if(d->creationContext) + return d->creationContext; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(this); + if (ddata) + return ddata->context; + else + return 0; +} + +/*! + \internal + Sets the QmlContext the component was created in. This is only + desirable for components created in QML script. +*/ +void QmlComponent::setCreationContext(QmlContext* c) +{ + Q_D(QmlComponent); + d->creationContext = c; +} + +/*! + Load the QmlComponent from the provided \a url. +*/ +void QmlComponent::loadUrl(const QUrl &url) +{ + Q_D(QmlComponent); + + d->clear(); + + if (url.isRelative() && !url.isEmpty()) + d->url = d->engine->baseUrl().resolved(url); + else + d->url = url; + + QmlCompositeTypeData *data = + QmlEnginePrivate::get(d->engine)->typeManager.get(d->url); + + if (data->status == QmlCompositeTypeData::Waiting + || data->status == QmlCompositeTypeData::WaitingResources) + { + d->typeData = data; + d->typeData->addWaiter(d); + d->progress = data->progress; + } else { + d->fromTypeData(data); + d->progress = 1.0; + } + + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! + Return the list of errors that occured during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ +QList<QmlError> QmlComponent::errors() const +{ + Q_D(const QmlComponent); + if (isError()) + return d->state.errors; + else + return QList<QmlError>(); +} + +/*! + \internal + errorsString is only meant as a way to get the errors in script +*/ +QString QmlComponent::errorsString() const +{ + Q_D(const QmlComponent); + QString ret; + if(!isError()) + return ret; + foreach(const QmlError &e, d->state.errors) { + ret += e.url().toString() + QLatin1Char(':') + + QString::number(e.line()) + QLatin1Char(' ') + + e.description() + QLatin1Char('\n'); + } + return ret; +} + +/*! + \property QmlComponent::url + The component URL. This is the URL passed to either the constructor, + or the loadUrl() or setData() methods. +*/ +QUrl QmlComponent::url() const +{ + Q_D(const QmlComponent); + return d->url; +} + +/*! + \internal +*/ +QmlComponent::QmlComponent(QmlComponentPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + + +/*! + \internal + A version of create which returns a scriptObject, for use in script +*/ +QScriptValue QmlComponent::createObject() +{ + Q_D(QmlComponent); + QmlContext* ctxt = creationContext(); + if(!ctxt){ + qWarning() << QLatin1String("createObject can only be used in QML"); + return QScriptValue(); + } + QObject* ret = create(ctxt); + return QmlEnginePrivate::qmlScriptObject(ret, d->engine); +} + +/*! + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + If \a context is 0 (the default), it will create the instance in the + engine' s \l {QmlEngine::rootContext()}{root context}. +*/ +QObject *QmlComponent::create(QmlContext *context) +{ + Q_D(QmlComponent); + + return d->create(context, QBitField()); +} + +QObject *QmlComponentPrivate::create(QmlContext *context, + const QBitField &bindings) +{ + QObject *create(QmlContext *context, const QBitField &); + if (!context) + context = engine->rootContext(); + + if (context->engine() != engine) { + qWarning("QmlComponent::create(): Must create component in context from the same QmlEngine"); + return 0; + } + + QObject *rv = beginCreate(context, bindings); + completeCreate(); + return rv; +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QmlComponent::create() to create a + component. + + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + When QmlComponent constructs an instance, it occurs in three steps: + \list 1 + \i The object hierarchy is created, and constant values are assigned. + \i Property bindings are evaluated for the the first time. + \i If applicable, QmlParserStatus::componentComplete() is called on objects. + \endlist + QmlComponent::beginCreate() differs from QmlComponent::create() in that it + only performs step 1. QmlComponent::completeCreate() must be called to + complete steps 2 and 3. + + This breaking point is sometimes useful when using attached properties to + communicate information to an instantiated component, as it allows their + initial values to be configured before property bindings take effect. +*/ +QObject *QmlComponent::beginCreate(QmlContext *context) +{ + Q_D(QmlComponent); + return d->beginCreate(context, QBitField()); +} + +QObject * +QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) +{ + Q_Q(QmlComponent); + if (!context) { + qWarning("QmlComponent::beginCreate(): Cannot create a component in a null context"); + return 0; + } + + if (context->engine() != engine) { + qWarning("QmlComponent::beginCreate(): Must create component in context from the same QmlEngine"); + return 0; + } + + if (state.completePending) { + qWarning("QmlComponent: Cannot create new component instance before completing the previous"); + return 0; + } + + if (!q->isReady()) { + qWarning("QmlComponent: Component is not ready"); + return 0; + } + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + QmlContextPrivate *contextPriv = + static_cast<QmlContextPrivate *>(QObjectPrivate::get(context)); + QmlContext *ctxt = new QmlContext(context, 0, true); + static_cast<QmlContextPrivate*>(ctxt->d_func())->url = cc->url; + static_cast<QmlContextPrivate*>(ctxt->d_func())->imports = cc->importCache; + cc->importCache->addref(); + + QObject *rv = begin(ctxt, ep, cc, start, count, &state, bindings); + + if (rv) { + QmlGraphics_setParent_noEvent(ctxt, rv); + } else { + delete ctxt; + } + + if (rv && !contextPriv->isInternal && ep->isDebugging) + contextPriv->instances.append(rv); + return rv; +} + +QObject * QmlComponentPrivate::begin(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QmlCompiledData *component, int start, int count, + ConstructionState *state, const QBitField &bindings) +{ + bool isRoot = !enginePriv->inBeginCreate; + enginePriv->inBeginCreate = true; + + QmlVME vme; + QObject *rv = vme.run(ctxt, component, start, count, bindings); + + if (vme.isError()) + state->errors = vme.errors(); + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->componentAttacheds = enginePriv->componentAttacheds; + if (state->componentAttacheds) + state->componentAttacheds->prev = &state->componentAttacheds; + + enginePriv->componentAttacheds = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } + + return rv; +} + +void QmlComponentPrivate::beginDeferred(QmlContext *, QmlEnginePrivate *enginePriv, + QObject *object, ConstructionState *state) +{ + bool isRoot = !enginePriv->inBeginCreate; + enginePriv->inBeginCreate = true; + + QmlVME vme; + vme.runDeferred(object); + + if (vme.isError()) + state->errors = vme.errors(); + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->componentAttacheds = enginePriv->componentAttacheds; + if (state->componentAttacheds) + state->componentAttacheds->prev = &state->componentAttacheds; + + enginePriv->componentAttacheds = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } +} + +void QmlComponentPrivate::complete(QmlEnginePrivate *enginePriv, ConstructionState *state) +{ + if (state->completePending) { + + for (int ii = 0; ii < state->bindValues.count(); ++ii) { + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv = + state->bindValues.at(ii); + for (int jj = 0; jj < bv.count; ++jj) { + if(bv.at(jj)) + bv.at(jj)->setEnabled(true, QmlMetaProperty::BypassInterceptor | + QmlMetaProperty::DontRemoveBinding); + } + QmlEnginePrivate::clear(bv); + } + + for (int ii = 0; ii < state->parserStatus.count(); ++ii) { + QmlEnginePrivate::SimpleList<QmlParserStatus> ps = + state->parserStatus.at(ii); + + for (int jj = ps.count - 1; jj >= 0; --jj) { + QmlParserStatus *status = ps.at(jj); + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } + } + QmlEnginePrivate::clear(ps); + } + + while (state->componentAttacheds) { + QmlComponentAttached *a = state->componentAttacheds; + if (a->next) a->next->prev = &state->componentAttacheds; + state->componentAttacheds = a->next; + a->prev = 0; a->next = 0; + emit a->completed(); + } + + state->bindValues.clear(); + state->parserStatus.clear(); + state->completePending = false; + + enginePriv->inProgressCreations--; + if (0 == enginePriv->inProgressCreations) { + while (enginePriv->erroredBindings) { + qWarning().nospace() << qPrintable(enginePriv->erroredBindings->error.toString()); + enginePriv->erroredBindings->removeError(); + } + } + } +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QmlComponent::create() to create a + component. + + Complete a component creation begin with QmlComponent::beginCreate(). +*/ +void QmlComponent::completeCreate() +{ + Q_D(QmlComponent); + d->completeCreate(); +} + +void QmlComponentPrivate::completeCreate() +{ + if (state.completePending) { + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + complete(ep, &state); + } +} + +QmlComponentAttached::QmlComponentAttached(QObject *parent) +: QObject(parent), prev(0), next(0) +{ +} + +QmlComponentAttached::~QmlComponentAttached() +{ + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} + +/*! + \internal +*/ +QmlComponentAttached *QmlComponent::qmlAttachedProperties(QObject *obj) +{ + QmlComponentAttached *a = new QmlComponentAttached(obj); + + QmlEngine *engine = qmlEngine(obj); + if (!engine || !QmlEnginePrivate::get(engine)->inBeginCreate) + return a; + + QmlEnginePrivate *p = QmlEnginePrivate::get(engine); + + a->next = p->componentAttacheds; + a->prev = &p->componentAttacheds; + if (a->next) a->next->prev = &a->next; + p->componentAttacheds = a; + + return a; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h new file mode 100644 index 0000000..342f503 --- /dev/null +++ b/src/declarative/qml/qmlcomponent.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENT_H +#define QMLCOMPONENT_H + +#include "qml.h" +#include "qmlerror.h" + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlCompiledData; +class QByteArray; +class QmlComponentPrivate; +class QmlEngine; +class QmlComponentAttached; +class Q_DECLARATIVE_EXPORT QmlComponent : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlComponent) + Q_PROPERTY(bool isNull READ isNull NOTIFY statusChanged) + Q_PROPERTY(bool isReady READ isReady NOTIFY statusChanged) + Q_PROPERTY(bool isError READ isError NOTIFY statusChanged) + Q_PROPERTY(bool isLoading READ isLoading NOTIFY statusChanged) + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QUrl url READ url CONSTANT) + +public: + QmlComponent(QObject *parent = 0); + QmlComponent(QmlEngine *, QObject *parent=0); + QmlComponent(QmlEngine *, const QString &fileName, QObject *parent = 0); + QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0); + virtual ~QmlComponent(); + + Q_ENUMS(Status) + enum Status { Null, Ready, Loading, Error }; + Status status() const; + + bool isNull() const; + bool isReady() const; + bool isError() const; + bool isLoading() const; + + QList<QmlError> errors() const; + Q_INVOKABLE QString errorsString() const; + + qreal progress() const; + + QUrl url() const; + + virtual QObject *create(QmlContext *context = 0); + virtual QObject *beginCreate(QmlContext *); + virtual void completeCreate(); + + Q_INVOKABLE QScriptValue createObject(); + + void loadUrl(const QUrl &url); + void setData(const QByteArray &, const QUrl &baseUrl); + + void setCreationContext(QmlContext*); + QmlContext *creationContext() const; + + static QmlComponentAttached *qmlAttachedProperties(QObject *); + +Q_SIGNALS: + void statusChanged(QmlComponent::Status); + void progressChanged(qreal); + +protected: + QmlComponent(QmlComponentPrivate &dd, QObject* parent); + +private: + QmlComponent(QmlEngine *, QmlCompiledData *, int, int, QObject *parent); + + friend class QmlVME; + friend class QmlCompositeTypeData; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QmlComponent::Status) +QML_DECLARE_TYPE(QmlComponent) +QML_DECLARE_TYPEINFO(QmlComponent, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QMLCOMPONENT_H diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h new file mode 100644 index 0000000..4039a61 --- /dev/null +++ b/src/declarative/qml/qmlcomponent_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENT_P_H +#define QMLCOMPONENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlcomponent.h" + +#include "qmlengine_p.h" +#include "qmlcompositetypemanager_p.h" +#include "qbitfield_p.h" +#include "qmlerror.h" +#include "qml.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QmlComponent; +class QmlEngine; +class QmlCompiledData; + +class QmlComponentAttached; +class QmlComponentPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlComponent) + +public: + QmlComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {} + + QObject *create(QmlContext *context, const QBitField &); + QObject *beginCreate(QmlContext *, const QBitField &); + void completeCreate(); + + QmlCompositeTypeData *typeData; + void typeDataReady(); + void updateProgress(qreal); + + void fromTypeData(QmlCompositeTypeData *data); + + QUrl url; + qreal progress; + + int start; + int count; + QmlCompiledData *cc; + + struct ConstructionState { + ConstructionState() : componentAttacheds(0), completePending(false) {} + QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues; + QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; + QmlComponentAttached *componentAttacheds; + QList<QmlError> errors; + bool completePending; + }; + ConstructionState state; + + static QObject *begin(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QmlCompiledData *component, int start, int count, + ConstructionState *state, const QBitField &bindings = QBitField()); + static void beginDeferred(QmlContext *ctxt, QmlEnginePrivate *enginePriv, + QObject *object, ConstructionState *state); + static void complete(QmlEnginePrivate *enginePriv, ConstructionState *state); + + QmlEngine *engine; + QmlContext *creationContext; + + void clear(); + + static QmlComponentPrivate *get(QmlComponent *c) { + return static_cast<QmlComponentPrivate *>(QObjectPrivate::get(c)); + } +}; + +class QmlComponentAttached : public QObject +{ + Q_OBJECT +public: + QmlComponentAttached(QObject *parent = 0); + ~QmlComponentAttached(); + + QmlComponentAttached **prev; + QmlComponentAttached *next; + +Q_SIGNALS: + void completed(); + +private: + friend class QmlComponentPrivate; +}; + +QT_END_NAMESPACE + +#endif // QMLCOMPONENT_P_H diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h new file mode 100644 index 0000000..c8b9f25 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypedata_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPOSITETYPEDATA_P_H +#define QMLCOMPOSITETYPEDATA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlengine_p.h" + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlCompositeTypeResource; +class QmlCompositeTypeData : public QmlRefCount +{ +public: + QmlCompositeTypeData(); + virtual ~QmlCompositeTypeData(); + + enum Status { + Invalid, + Complete, + Error, + Waiting, + WaitingResources + }; + Status status; + enum ErrorType { + NoError, + AccessError, + GeneralError + }; + ErrorType errorType; + + QList<QmlError> errors; + + QmlEnginePrivate::Imports imports; + + QList<QmlCompositeTypeData *> dependants; + + // Return a QmlComponent if the QmlCompositeTypeData is not in the Waiting + // state. The QmlComponent is owned by the QmlCompositeTypeData, so a + // reference should be kept to keep the QmlComponent alive. + QmlComponent *toComponent(QmlEngine *); + // Return a QmlCompiledData if possible, or 0 if an error + // occurs + QmlCompiledData *toCompiledComponent(QmlEngine *); + + struct TypeReference + { + TypeReference(); + + QmlType *type; + QmlCompositeTypeData *unit; + }; + + QList<TypeReference> types; + QList<QmlCompositeTypeResource *> resources; + + // Add or remove p as a waiter. When the QmlCompositeTypeData becomes + // ready, the QmlComponentPrivate::typeDataReady() method will be invoked on + // p. The waiter is automatically removed when the typeDataReady() method + // is invoked, so there is no need to call remWaiter() in this case. + void addWaiter(QmlComponentPrivate *p); + void remWaiter(QmlComponentPrivate *p); + + qreal progress; + +private: + friend class QmlCompositeTypeManager; + friend class QmlCompiler; + friend class QmlDomDocument; + + QmlScriptParser data; + QList<QmlComponentPrivate *> waiters; + QmlComponent *component; + QmlCompiledData *compiledComponent; +}; + +class QmlCompositeTypeResource : public QmlRefCount +{ +public: + QmlCompositeTypeResource(); + virtual ~QmlCompositeTypeResource(); + + enum Status { + Invalid, + Complete, + Error, + Waiting + }; + Status status; + + QList<QmlCompositeTypeData *> dependants; + + QString url; + QByteArray data; +}; + +#endif // QMLCOMPOSITETYPEDATA_P_H + diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp new file mode 100644 index 0000000..3504fe9 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -0,0 +1,670 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompositetypemanager_p.h" + +#include "qmlcompositetypedata_p.h" +#include "qmlscriptparser_p.h" +#include "qmlengine.h" +#include "qmlengine_p.h" +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "qmlcompiler_p.h" + +#include <QtNetwork/qnetworkreply.h> +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> + +QT_BEGIN_NAMESPACE + +#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0)) +inline uint qHash(const QUrl &uri) +{ + return qHash(uri.toEncoded(QUrl::FormattingOption(0x100))); +} +#endif + +QmlCompositeTypeData::QmlCompositeTypeData() +: status(Invalid), errorType(NoError), component(0), compiledComponent(0) +{ +} + +QmlCompositeTypeData::~QmlCompositeTypeData() +{ + for (int ii = 0; ii < dependants.count(); ++ii) + dependants.at(ii)->release(); + + for (int ii = 0; ii < resources.count(); ++ii) + resources.at(ii)->release(); + + if (compiledComponent) + compiledComponent->release(); + + if (component) + delete component; +} + +QmlCompositeTypeResource::QmlCompositeTypeResource() +{ +} + +QmlCompositeTypeResource::~QmlCompositeTypeResource() +{ + for (int ii = 0; ii < dependants.count(); ++ii) + dependants.at(ii)->release(); +} + +void QmlCompositeTypeData::addWaiter(QmlComponentPrivate *p) +{ + waiters << p; +} + +void QmlCompositeTypeData::remWaiter(QmlComponentPrivate *p) +{ + waiters.removeAll(p); +} + +QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) +{ + if (!component) { + + QmlCompiledData *cc = toCompiledComponent(engine); + if (cc) { + component = new QmlComponent(engine, cc, -1, -1, 0); + cc->release(); + } else { + component = new QmlComponent(engine, 0); + component->d_func()->url = imports.baseUrl(); + component->d_func()->state.errors = errors; + } + + } + + return component; +} + +QmlCompiledData * +QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) +{ + if (status == Complete && !compiledComponent) { + + compiledComponent = new QmlCompiledData(engine); + compiledComponent->url = imports.baseUrl(); + compiledComponent->name = compiledComponent->url.toString(); + + QmlCompiler compiler; + if (!compiler.compile(engine, this, compiledComponent)) { + status = Error; + errors = compiler.errors(); + compiledComponent->release(); + compiledComponent = 0; + } + + // Data is no longer needed once we have a compiled component + data.clear(); + } + + if (compiledComponent) + compiledComponent->addref(); + + return compiledComponent; +} + +QmlCompositeTypeData::TypeReference::TypeReference() +: type(0), unit(0) +{ +} + +QmlCompositeTypeManager::QmlCompositeTypeManager(QmlEngine *e) +: engine(e) +{ +} + +QmlCompositeTypeManager::~QmlCompositeTypeManager() +{ + for (Components::Iterator iter = components.begin(); iter != components.end();) { + (*iter)->release(); + iter = components.erase(iter); + } + for (Resources::Iterator iter = resources.begin(); iter != resources.end();) { + (*iter)->release(); + iter = resources.erase(iter); + } +} + +QmlCompositeTypeData *QmlCompositeTypeManager::get(const QUrl &url) +{ + QmlCompositeTypeData *unit = components.value(url); + + if (!unit) { + unit = new QmlCompositeTypeData; + unit->status = QmlCompositeTypeData::Waiting; + unit->progress = 0.0; + unit->imports.setBaseUrl(url); + components.insert(url, unit); + + loadSource(unit); + } + + unit->addref(); + return unit; +} + +QmlCompositeTypeData * +QmlCompositeTypeManager::getImmediate(const QByteArray &data, const QUrl &url) +{ + QmlCompositeTypeData *unit = new QmlCompositeTypeData; + unit->status = QmlCompositeTypeData::Waiting; + unit->imports.setBaseUrl(url); + setData(unit, data, url); + return unit; +} + +void QmlCompositeTypeManager::clearCache() +{ + for (Components::Iterator iter = components.begin(); iter != components.end();) { + if ((*iter)->status != QmlCompositeTypeData::Waiting) { + (*iter)->release(); + iter = components.erase(iter); + } else { + ++iter; + } + } + + for (Resources::Iterator iter = resources.begin(); iter != resources.end();) { + if ((*iter)->status != QmlCompositeTypeResource::Waiting) { + (*iter)->release(); + iter = resources.erase(iter); + } else { + ++iter; + } + } +} + +void QmlCompositeTypeManager::replyFinished() +{ + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + + QmlCompositeTypeData *unit = components.value(reply->url()); + Q_ASSERT(unit); + + if (reply->error() != QNetworkReply::NoError) { + QString errorDescription; + // ### - Fill in error + errorDescription = QLatin1String("Network error for URL ") + + reply->url().toString(); + + unit->status = QmlCompositeTypeData::Error; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errorType = QmlCompositeTypeData::AccessError; + unit->errors << error; + doComplete(unit); + + } else { + QByteArray data = reply->readAll(); + + setData(unit, data, reply->url()); + } + + reply->deleteLater(); +} + +void QmlCompositeTypeManager::resourceReplyFinished() +{ + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + + QmlCompositeTypeResource *resource = resources.value(reply->url()); + Q_ASSERT(resource); + + if (reply->error() != QNetworkReply::NoError) { + + resource->status = QmlCompositeTypeResource::Error; + + } else { + + resource->status = QmlCompositeTypeResource::Complete; + resource->data = reply->readAll(); + + } + + doComplete(resource); + reply->deleteLater(); +} + +static QString toLocalFileOrQrc(const QUrl& url) +{ + QString r = url.toLocalFile(); + if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) + r = QLatin1Char(':') + url.path(); + return r; +} + +void QmlCompositeTypeManager::loadResource(QmlCompositeTypeResource *resource) +{ + QUrl url(resource->url); + + QString lf = toLocalFileOrQrc(url); + if (!lf.isEmpty()) { + + QFile file(lf); + if (file.open(QFile::ReadOnly)) { + resource->data = file.readAll(); + resource->status = QmlCompositeTypeResource::Complete; + } else { + resource->status = QmlCompositeTypeResource::Error; + } + + } else { + + QNetworkReply *reply = + engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(resourceReplyFinished())); + + } +} + +void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit) +{ + QUrl url(unit->imports.baseUrl()); + + QString lf = toLocalFileOrQrc(url); + if (!lf.isEmpty()) { + + QFile file(lf); + if (file.open(QFile::ReadOnly)) { + QByteArray data = file.readAll(); + setData(unit, data, url); + } else { + QString errorDescription; + // ### - Fill in error + errorDescription = QLatin1String("File error for URL ") + url.toString(); + unit->status = QmlCompositeTypeData::Error; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errorType = QmlCompositeTypeData::AccessError; + unit->errors << error; + doComplete(unit); + } + + } else { + QNetworkReply *reply = + engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(replyFinished())); + QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } +} + +void QmlCompositeTypeManager::requestProgress(qint64 received, qint64 total) +{ + if (total <= 0) + return; + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + + QmlCompositeTypeData *unit = components.value(reply->url()); + Q_ASSERT(unit); + + unit->progress = qreal(received)/total; + + foreach (QmlComponentPrivate *comp, unit->waiters) + comp->updateProgress(unit->progress); +} + +void QmlCompositeTypeManager::setData(QmlCompositeTypeData *unit, + const QByteArray &data, + const QUrl &url) +{ + bool ok = true; + if (!unit->data.parse(data, url)) { + ok = false; + unit->errors << unit->data.errors(); + } + + if (ok) { + compile(unit); + } else { + unit->status = QmlCompositeTypeData::Error; + unit->errorType = QmlCompositeTypeData::GeneralError; + doComplete(unit); + } +} + +void QmlCompositeTypeManager::doComplete(QmlCompositeTypeData *unit) +{ + for (int ii = 0; ii < unit->dependants.count(); ++ii) { + checkComplete(unit->dependants.at(ii)); + unit->dependants.at(ii)->release(); + } + unit->dependants.clear(); + + while(!unit->waiters.isEmpty()) { + QmlComponentPrivate *p = unit->waiters.takeFirst(); + p->typeDataReady(); + } +} + +void QmlCompositeTypeManager::doComplete(QmlCompositeTypeResource *resource) +{ + for (int ii = 0; ii < resource->dependants.count(); ++ii) { + checkComplete(resource->dependants.at(ii)); + resource->dependants.at(ii)->release(); + } + resource->dependants.clear(); +} + +void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) +{ + if (unit->status != QmlCompositeTypeData::Waiting + && unit->status != QmlCompositeTypeData::WaitingResources) + return; + + int waiting = 0; + for (int ii = 0; ii < unit->resources.count(); ++ii) { + QmlCompositeTypeResource *r = unit->resources.at(ii); + + if (!r) + continue; + + if (r->status == QmlCompositeTypeResource::Error) { + unit->status = QmlCompositeTypeData::Error; + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Resource %1 unavailable").arg(r->url)); + unit->errors << error; + doComplete(unit); + return; + } else if (r->status == QmlCompositeTypeResource::Waiting) { + waiting++; + } + } + + if (waiting == 0) { + if (unit->status == QmlCompositeTypeData::WaitingResources) { + waiting += resolveTypes(unit); + if (unit->status != QmlCompositeTypeData::Error) { + if (waiting) + unit->status = QmlCompositeTypeData::Waiting; + } else { + return; + } + } else { + for (int ii = 0; ii < unit->types.count(); ++ii) { + QmlCompositeTypeData *u = unit->types.at(ii).unit; + + if (!u) + continue; + + if (u->status == QmlCompositeTypeData::Error) { + unit->status = QmlCompositeTypeData::Error; + unit->errors = u->errors; + doComplete(unit); + return; + } else if (u->status == QmlCompositeTypeData::Waiting) { + waiting++; + } + } + } + } + + if (!waiting) { + unit->status = QmlCompositeTypeData::Complete; + doComplete(unit); + } +} + +int QmlCompositeTypeManager::resolveTypes(QmlCompositeTypeData *unit) +{ + // not called until all resources are loaded (they include import URLs) + + int waiting = 0; + + foreach (QmlScriptParser::Import imp, unit->data.imports()) { + QString qmldir; + if (imp.type == QmlScriptParser::Import::File && imp.qualifier.isEmpty()) { + QString importUrl = unit->imports.baseUrl().resolved(QUrl(imp.uri + QLatin1String("/qmldir"))).toString(); + for (int ii = 0; ii < unit->resources.count(); ++ii) { + if (unit->resources.at(ii)->url == importUrl) { + qmldir = QString::fromUtf8(unit->resources.at(ii)->data); + break; + } + } + } + + int vmaj = -1; + int vmin = -1; + if (!imp.version.isEmpty()) { + int dot = imp.version.indexOf(QLatin1Char('.')); + if (dot < 0) { + vmaj = imp.version.toInt(); + vmin = 0; + } else { + vmaj = imp.version.left(dot).toInt(); + vmin = imp.version.mid(dot+1).toInt(); + } + } + + if (!QmlEnginePrivate::get(engine)-> + addToImport(&unit->imports, qmldir, imp.uri, imp.qualifier, vmaj, vmin, imp.type)) + { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Import %1 unavailable").arg(imp.uri)); + unit->status = QmlCompositeTypeData::Error; + unit->errorType = QmlCompositeTypeData::GeneralError; + unit->errors << error; + doComplete(unit); + return 0; + } + } + + QList<QmlScriptParser::TypeReference*> types = unit->data.referencedTypes(); + + for (int ii = 0; ii < types.count(); ++ii) { + QmlScriptParser::TypeReference *parserRef = types.at(ii); + QByteArray typeName = parserRef->name.toUtf8(); + + QmlCompositeTypeData::TypeReference ref; + + QUrl url; + int majorVersion; + int minorVersion; + QmlEnginePrivate::ImportedNamespace *typeNamespace = 0; + if (!QmlEnginePrivate::get(engine)->resolveType(unit->imports, typeName, &ref.type, &url, &majorVersion, &minorVersion, &typeNamespace) + || typeNamespace) + { + // Known to not be a type: + // - known to be a namespace (Namespace {}) + // - type with unknown namespace (UnknownNamespace.SomeType {}) + QmlError error; + error.setUrl(unit->imports.baseUrl()); + if (typeNamespace) + error.setDescription(tr("Namespace %1 cannot be used as a type").arg(QString::fromUtf8(typeName))); + else + error.setDescription(tr("%1 is not a type").arg(QString::fromUtf8(typeName))); + if (!parserRef->refObjects.isEmpty()) { + QmlParser::Object *obj = parserRef->refObjects.first(); + error.setLine(obj->location.start.line); + error.setColumn(obj->location.start.column); + } + unit->status = QmlCompositeTypeData::Error; + unit->errorType = QmlCompositeTypeData::GeneralError; + unit->errors << error; + doComplete(unit); + return 0; + } + + if (ref.type) { + foreach (QmlParser::Object *obj, parserRef->refObjects) { + // store namespace for DOM + obj->majorVersion = majorVersion; + obj->minorVersion = minorVersion; + } + unit->types << ref; + continue; + } + + QmlCompositeTypeData *urlUnit = components.value(url); + + if (!urlUnit) { + urlUnit = new QmlCompositeTypeData; + urlUnit->status = QmlCompositeTypeData::Waiting; + urlUnit->imports.setBaseUrl(url); + components.insert(url, urlUnit); + + loadSource(urlUnit); + } + + ref.unit = urlUnit; + switch(urlUnit->status) { + case QmlCompositeTypeData::Invalid: + case QmlCompositeTypeData::Error: + unit->status = QmlCompositeTypeData::Error; + { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Type %1 unavailable").arg(QString::fromUtf8(typeName))); + if (!parserRef->refObjects.isEmpty()) { + QmlParser::Object *obj = parserRef->refObjects.first(); + error.setLine(obj->location.start.line); + error.setColumn(obj->location.start.column); + } + unit->errors << error; + } + if (urlUnit->errorType != QmlCompositeTypeData::AccessError) + unit->errors << urlUnit->errors; + doComplete(unit); + return 0; + + case QmlCompositeTypeData::Complete: + break; + + case QmlCompositeTypeData::Waiting: + case QmlCompositeTypeData::WaitingResources: + unit->addref(); + ref.unit->dependants << unit; + waiting++; + break; + } + + unit->types << ref; + } + return waiting; +} + +// ### Check ref counting in here +void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) +{ + int waiting = 0; + + QList<QUrl> resourceList = unit->data.referencedResources(); + + foreach (QmlScriptParser::Import imp, unit->data.imports()) { + if (imp.type == QmlScriptParser::Import::File && imp.qualifier.isEmpty()) { + QUrl importUrl = unit->imports.baseUrl().resolved(QUrl(imp.uri + QLatin1String("/qmldir"))); + if (toLocalFileOrQrc(importUrl).isEmpty()) { + // Import requires remote qmldir + resourceList.prepend(importUrl); + } + } + } + + for (int ii = 0; ii < resourceList.count(); ++ii) { + QUrl url = unit->imports.baseUrl().resolved(resourceList.at(ii)); + + QmlCompositeTypeResource *resource = resources.value(url); + + if (!resource) { + resource = new QmlCompositeTypeResource; + resource->status = QmlCompositeTypeResource::Waiting; + resource->url = url.toString(); + resources.insert(url, resource); + + loadResource(resource); + } + + switch(resource->status) { + case QmlCompositeTypeResource::Invalid: + case QmlCompositeTypeResource::Error: + unit->status = QmlCompositeTypeData::Error; + { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Resource %1 unavailable").arg(resource->url)); + unit->errors << error; + } + doComplete(unit); + return; + + case QmlCompositeTypeData::Complete: + break; + + case QmlCompositeTypeData::Waiting: + unit->addref(); + resource->dependants << unit; + waiting++; + break; + } + + resource->addref(); + unit->resources << resource; + } + + if (waiting == 0) { + waiting += resolveTypes(unit); + if (unit->status != QmlCompositeTypeData::Error) { + if (!waiting) { + unit->status = QmlCompositeTypeData::Complete; + doComplete(unit); + } else { + unit->status = QmlCompositeTypeData::Waiting; + } + } + } else { + unit->status = QmlCompositeTypeData::WaitingResources; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h new file mode 100644 index 0000000..89e2353 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPOSITETYPEMANAGER_P_H +#define QMLCOMPOSITETYPEMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlscriptparser_p.h" +#include "qmlrefcount_p.h" +#include "qmlerror.h" +#include "qmlengine.h" + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlCompiledData; +class QmlComponentPrivate; +class QmlComponent; +class QmlDomDocument; + +class QmlCompositeTypeData; +class QmlCompositeTypeResource; + +class QmlCompositeTypeManager : public QObject +{ + Q_OBJECT +public: + QmlCompositeTypeManager(QmlEngine *); + ~QmlCompositeTypeManager(); + + // Return a QmlCompositeTypeData for url. The QmlCompositeTypeData may be + // cached. + QmlCompositeTypeData *get(const QUrl &url); + // Return a QmlCompositeTypeData for data, with the provided base url. The + // QmlCompositeTypeData will not be cached. + QmlCompositeTypeData *getImmediate(const QByteArray &data, const QUrl &url); + + // Clear cached types. Only types that aren't in the Waiting state will + // be cleared. + void clearCache(); + +private Q_SLOTS: + void replyFinished(); + void resourceReplyFinished(); + void requestProgress(qint64 received, qint64 total); + +private: + void loadSource(QmlCompositeTypeData *); + void loadResource(QmlCompositeTypeResource *); + void compile(QmlCompositeTypeData *); + void setData(QmlCompositeTypeData *, const QByteArray &, const QUrl &); + + void doComplete(QmlCompositeTypeData *); + void doComplete(QmlCompositeTypeResource *); + void checkComplete(QmlCompositeTypeData *); + int resolveTypes(QmlCompositeTypeData *); + + QmlEngine *engine; + typedef QHash<QUrl, QmlCompositeTypeData *> Components; + Components components; + typedef QHash<QUrl, QmlCompositeTypeResource *> Resources; + Resources resources; +}; + +QT_END_NAMESPACE + +#endif // QMLCOMPOSITETYPEMANAGER_P_H + diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp new file mode 100644 index 0000000..4c6dc6f --- /dev/null +++ b/src/declarative/qml/qmlcontext.cpp @@ -0,0 +1,541 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcontext.h" +#include "qmlcontext_p.h" + +#include "qmlexpression_p.h" +#include "qmlengine_p.h" +#include "qmlengine.h" +#include "qmlcompiledbindings_p.h" +#include "qmlinfo.h" + +#include <qscriptengine.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qdebug.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +QmlContextPrivate::QmlContextPrivate() +: parent(0), engine(0), isInternal(false), propertyNames(0), + notifyIndex(-1), highPriorityCount(0), imports(0), expressions(0), contextObjects(0), + idValues(0), idValueCount(0), optimizedBindings(0) +{ +} + +void QmlContextPrivate::addScript(const QmlParser::Object::ScriptBlock &script, QObject *scopeObject) +{ + Q_Q(QmlContext); + + if (!engine) + return; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + scriptContext->pushScope(enginePriv->contextClass->newContext(q, scopeObject)); + + QScriptValue scope = scriptEngine->newObject(); + scriptContext->setActivationObject(scope); + + for (int ii = 0; ii < script.codes.count(); ++ii) { + scriptEngine->evaluate(script.codes.at(ii), script.files.at(ii), script.lineNumbers.at(ii)); + + if (scriptEngine->hasUncaughtException()) { + QmlError error; + QmlExpressionPrivate::exceptionToError(scriptEngine, error); + qWarning().nospace() << qPrintable(error.toString()); + } + } + + scriptEngine->popContext(); + + scripts.append(scope); +} + +void QmlContextPrivate::destroyed(ContextGuard *guard) +{ + Q_Q(QmlContext); + + // process of being deleted (which is *probably* why obj has been destroyed + // anyway), as we're about to get deleted which will invalidate all the + // expressions that could depend on us + QObject *parent = q->parent(); + if (parent && QObjectPrivate::get(parent)->wasDeleted) + return; + + while(guard->bindings) { + QObject *o = guard->bindings->target; + int mi = guard->bindings->methodIndex; + guard->bindings->clear(); + if (o) o->qt_metacall(QMetaObject::InvokeMetaMethod, mi, 0); + } + + for (int ii = 0; ii < idValueCount; ++ii) { + if (&idValues[ii] == guard) { + QMetaObject::activate(q, ii + notifyIndex, 0); + return; + } + } +} + +void QmlContextPrivate::init() +{ + Q_Q(QmlContext); + + if (parent) + parent->d_func()->childContexts.insert(q); +} + +/*! + \class QmlContext + \brief The QmlContext class defines a context within a QML engine. + \mainclass + + Contexts allow data to be exposed to the QML components instantiated by the + QML engine. + + Each QmlContext contains a set of properties, distinct from + its QObject properties, that allow data to be + explicitly bound to a context by name. The context properties are defined or + updated by calling QmlContext::setContextProperty(). The following example shows + a Qt model being bound to a context and then accessed from a QML file. + + \code + QmlEngine engine; + QmlContext context(engine.rootContext()); + context.setContextProperty("myModel", modelData); + + QmlComponent component(&engine, "ListView { model=myModel }"); + component.create(&context); + \endcode + + To simplify binding and maintaining larger data sets, QObject's can be + added to a QmlContext. These objects are known as the context's default + objects. In this case all the properties of the QObject are + made available by name in the context, as though they were all individually + added by calling QmlContext::setContextProperty(). Changes to the property's + values are detected through the property's notify signal. This method is + also slightly more faster than manually adding property values. + + The following example has the same effect as the one above, but it is + achieved using a default object. + + \code + class MyDataSet : ... { + ... + Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged) + ... + }; + + MyDataSet myDataSet; + QmlEngine engine; + QmlContext context(engine.rootContext()); + context.addDefaultObject(&myDataSet); + + QmlComponent component(&engine, "ListView { model=myModel }"); + component.create(&context); + \endcode + + Default objects added first take precedence over those added later. All properties + added explicitly by QmlContext::setContextProperty() take precedence over default + object properties. + + Contexts are hierarchal, with the \l {QmlEngine::rootContext()}{root context} + being created by the QmlEngine. A component instantiated in a given context + has access to that context's data, as well as the data defined by its + ancestor contexts. Data values (including those added implicitly by the + default objects) in a context override those in ancestor contexts. Data + that should be available to all components instantiated by the QmlEngine + should be added to the \l {QmlEngine::rootContext()}{root context}. + + In the following example, + + \code + QmlEngine engine; + QmlContext context1(engine.rootContext()); + QmlContext context2(&context1); + QmlContext context3(&context2); + + context1.setContextProperty("a", 12); + context2.setContextProperty("b", 13); + context3.setContextProperty("a", 14); + context3.setContextProperty("c", 14); + \endcode + + a QML component instantiated in context1 would have access to the "a" data, + a QML component instantiated in context2 would have access to the "a" and + "b" data, and a QML component instantiated in context3 would have access to + the "a", "b" and "c" data - although its "a" data would return 14, unlike + that in context1 or context2. +*/ + +/*! \internal */ +QmlContext::QmlContext(QmlEngine *e, bool) +: QObject(*(new QmlContextPrivate)) +{ + Q_D(QmlContext); + d->engine = e; + d->init(); +} + +/*! + Create a new QmlContext as a child of \a engine's root context, and the + QObject \a parent. +*/ +QmlContext::QmlContext(QmlEngine *engine, QObject *parent) +: QObject(*(new QmlContextPrivate), parent) +{ + Q_D(QmlContext); + QmlContext *parentContext = engine?engine->rootContext():0; + d->parent = parentContext; + d->engine = parentContext->engine(); + d->init(); +} + +/*! + Create a new QmlContext with the given \a parentContext, and the + QObject \a parent. +*/ +QmlContext::QmlContext(QmlContext *parentContext, QObject *parent) +: QObject(*(new QmlContextPrivate), parent) +{ + Q_D(QmlContext); + d->parent = parentContext; + d->engine = parentContext->engine(); + d->init(); +} + +/*! + \internal +*/ +QmlContext::QmlContext(QmlContext *parentContext, QObject *parent, bool) +: QObject(*(new QmlContextPrivate), parent) +{ + Q_D(QmlContext); + d->parent = parentContext; + d->engine = parentContext->engine(); + d->isInternal = true; + d->init(); +} + +/*! + Destroys the QmlContext. + + Any expressions, or sub-contexts dependent on this context will be + invalidated, but not destroyed (unless they are parented to the QmlContext + object). + */ +QmlContext::~QmlContext() +{ + Q_D(QmlContext); + if (d->parent) + d->parent->d_func()->childContexts.remove(this); + + for (QSet<QmlContext *>::ConstIterator iter = d->childContexts.begin(); + iter != d->childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + (*iter)->d_func()->parent = 0; + } + + QmlAbstractExpression *expression = d->expressions; + while (expression) { + QmlAbstractExpression *nextExpression = expression->m_nextExpression; + + expression->m_context = 0; + expression->m_prevExpression = 0; + expression->m_nextExpression = 0; + + expression = nextExpression; + } + + while (d->contextObjects) { + QmlDeclarativeData *co = d->contextObjects; + d->contextObjects = d->contextObjects->nextContextObject; + + co->context = 0; + co->nextContextObject = 0; + co->prevContextObject = 0; + } + + delete [] d->idValues; + + if (d->propertyNames) + d->propertyNames->release(); + + if (d->imports) + d->imports->release(); + + if (d->optimizedBindings) + d->optimizedBindings->release(); +} + +void QmlContextPrivate::invalidateEngines() +{ + if (!engine) + return; + engine = 0; + for (QSet<QmlContext *>::ConstIterator iter = childContexts.begin(); + iter != childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + } +} + +/* +Refreshes all expressions that could possibly depend on this context. +Refreshing flushes all context-tree dependent caches in the expressions, and should occur every +time the context tree *structure* (not values) changes. +*/ +void QmlContextPrivate::refreshExpressions() +{ + for (QSet<QmlContext *>::ConstIterator iter = childContexts.begin(); + iter != childContexts.end(); + ++iter) { + (*iter)->d_func()->refreshExpressions(); + } + + QmlAbstractExpression *expression = expressions; + while (expression) { + expression->refresh(); + expression = expression->m_nextExpression; + } +} + +/*! + Return the context's QmlEngine, or 0 if the context has no QmlEngine or the + QmlEngine was destroyed. +*/ +QmlEngine *QmlContext::engine() const +{ + Q_D(const QmlContext); + return d->engine; +} + +/*! + Return the context's parent QmlContext, or 0 if this context has no + parent or if the parent has been destroyed. +*/ +QmlContext *QmlContext::parentContext() const +{ + Q_D(const QmlContext); + return d->parent; +} + +/*! + Add \a defaultObject to this context. The object will be added after + any existing default objects. +*/ +void QmlContext::addDefaultObject(QObject *defaultObject) +{ + Q_D(QmlContext); + d->defaultObjects.prepend(defaultObject); +} + +/*! + Set a the \a value of the \a name property on this context. +*/ +void QmlContext::setContextProperty(const QString &name, const QVariant &value) +{ + Q_D(QmlContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + if (d->engine && QmlEnginePrivate::get(d->engine)->isObject(value.userType())) { + QObject *o = *(QObject **)value.constData(); + setContextProperty(name, o); + } else { + + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + + int idx = d->propertyNames->value(name); + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); + d->propertyValues.append(value); + + d->refreshExpressions(); + } else { + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } + } +} + +void QmlContextPrivate::setIdProperty(int idx, QObject *obj) +{ + if (notifyIndex == -1) { + Q_Q(QmlContext); + notifyIndex = q->metaObject()->methodCount(); + } + + idValues[idx].priv = this; + idValues[idx] = obj; +} + +void QmlContextPrivate::setIdPropertyData(QmlIntegerCache *data) +{ + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; +} + +/*! + Set a the \a value of the \a name property on this context. + + QmlContext does \bold not take ownership of \a value. +*/ +void QmlContext::setContextProperty(const QString &name, QObject *value) +{ + Q_D(QmlContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + int idx = d->propertyNames->value(name); + + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); + d->propertyValues.append(QVariant::fromValue(value)); + + d->refreshExpressions(); + } else { + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +QVariant QmlContext::contextProperty(const QString &name) const +{ + Q_D(const QmlContext); + QVariant value; + int idx = -1; + if (d->propertyNames) + idx = d->propertyNames->value(name); + + if (idx == -1) { + QByteArray utf8Name = name.toUtf8(); + for (int ii = d->defaultObjects.count() - 1; ii >= 0; --ii) { + QObject *obj = d->defaultObjects.at(ii); + QmlPropertyCache::Data local; + QmlPropertyCache::Data *property = QmlPropertyCache::property(d->engine, obj, name, local); + + if (property) { + value = obj->metaObject()->property(property->coreIndex).read(obj); + break; + } + } + if (!value.isValid() && parentContext()) + value = parentContext()->contextProperty(name); + } else { + value = d->propertyValues[idx]; + } + + return value; +} + +/*! + Resolves the URL \a src relative to the URL of the + containing component. + + \sa QmlEngine::baseUrl(), setBaseUrl() +*/ +QUrl QmlContext::resolvedUrl(const QUrl &src) +{ + Q_D(QmlContext); + QmlContext *ctxt = this; + if (src.isRelative() && !src.isEmpty()) { + if (ctxt) { + while(ctxt) { + if(ctxt->d_func()->url.isValid()) + break; + else + ctxt = ctxt->parentContext(); + } + + if (ctxt) + return ctxt->d_func()->url.resolved(src); + else if (d->engine) + return d->engine->baseUrl().resolved(src); + } + return QUrl(); + } else { + return src; + } +} + +/*! + Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl. + + Calling this function will override the url of the containing + component used by default. + + \sa resolvedUrl() +*/ +void QmlContext::setBaseUrl(const QUrl &baseUrl) +{ + d_func()->url = baseUrl; +} + +/*! + Returns the base url of the component, or the containing component + if none is set. +*/ +QUrl QmlContext::baseUrl() const +{ + const QmlContext* p = this; + while (p && p->d_func()->url.isEmpty()) { + p = p->parentContext(); + } + if (p) + return p->d_func()->url; + else + return QUrl(); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h new file mode 100644 index 0000000..bf389a0 --- /dev/null +++ b/src/declarative/qml/qmlcontext.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXT_H +#define QMLCONTEXT_H + +#include <QtCore/qurl.h> +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QmlEngine; +class QmlRefCount; +class QmlContextPrivate; +class QmlCompositeTypeData; + +class Q_DECLARATIVE_EXPORT QmlContext : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlContext) + +public: + QmlContext(QmlEngine *parent, QObject *objParent=0); + QmlContext(QmlContext *parent, QObject *objParent=0); + virtual ~QmlContext(); + + QmlEngine *engine() const; + QmlContext *parentContext() const; + + void addDefaultObject(QObject *); + void setContextProperty(const QString &, QObject *); + void setContextProperty(const QString &, const QVariant &); + + QVariant contextProperty(const QString &) const; + + QUrl resolvedUrl(const QUrl &); + + void setBaseUrl(const QUrl &); + QUrl baseUrl() const; + +private: + friend class QmlVME; + friend class QmlEngine; + friend class QmlEnginePrivate; + friend class QmlExpression; + friend class QmlExpressionPrivate; + friend class QmlContextScriptClass; + friend class QmlObjectScriptClass; + friend class QmlComponent; + friend class QmlComponentPrivate; + friend class QmlScriptPrivate; + friend class QmlBoundSignalProxy; + QmlContext(QmlContext *parent, QObject *objParent, bool); + QmlContext(QmlEngine *, bool); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLCONTEXT_H diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h new file mode 100644 index 0000000..cd7e1b6 --- /dev/null +++ b/src/declarative/qml/qmlcontext_p.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXT_P_H +#define QMLCONTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlcontext.h" + +#include "qmldeclarativedata_p.h" +#include "qmlengine_p.h" +#include "qmlintegercache_p.h" +#include "qmltypenamecache_p.h" + +#include <QtCore/qhash.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qset.h> + +#include <private/qobject_p.h> +#include "qmlguard_p.h" + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlExpression; +class QmlEngine; +class QmlExpression; +class QmlExpressionPrivate; +class QmlAbstractExpression; +class QmlBinding_Id; +class QmlCompiledBindings; + +class Q_DECLARATIVE_EXPORT QmlContextPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlContext) +public: + QmlContextPrivate(); + + QmlContext *parent; + QmlEngine *engine; + + bool isInternal; + + QmlIntegerCache *propertyNames; + QList<QVariant> propertyValues; + int notifyIndex; + + QObjectList defaultObjects; + int highPriorityCount; + + QList<QScriptValue> scripts; + void addScript(const QmlParser::Object::ScriptBlock &, QObject *); + + QUrl url; + + QmlTypeNameCache *imports; + + void init(); + + void invalidateEngines(); + void refreshExpressions(); + QSet<QmlContext *> childContexts; + + QmlAbstractExpression *expressions; + + QmlDeclarativeData *contextObjects; + + struct IdNotifier + { + inline IdNotifier(); + inline ~IdNotifier(); + + inline void clear(); + + IdNotifier *next; + IdNotifier**prev; + QObject *target; + int methodIndex; + }; + + struct ContextGuard : public QmlGuard<QObject> + { + inline ContextGuard(); + inline ContextGuard &operator=(QObject *obj); + inline virtual void objectDestroyed(QObject *); + + QmlContextPrivate *priv; + IdNotifier *bindings; + }; + ContextGuard *idValues; + int idValueCount; + void setIdProperty(int, QObject *); + void setIdPropertyData(QmlIntegerCache *); + void destroyed(ContextGuard *); + + static QmlContextPrivate *get(QmlContext *context) { + return static_cast<QmlContextPrivate *>(QObjectPrivate::get(context)); + } + static QmlContext *get(QmlContextPrivate *context) { + return static_cast<QmlContext *>(context->q_func()); + } + + QmlCompiledBindings *optimizedBindings; + + // Only used for debugging + QList<QPointer<QObject> > instances; +}; + +QmlContextPrivate::IdNotifier::IdNotifier() +: next(0), prev(0), target(0), methodIndex(-1) +{ +} + +QmlContextPrivate::IdNotifier::~IdNotifier() +{ + clear(); +} + +void QmlContextPrivate::IdNotifier::clear() +{ + if (next) next->prev = prev; + if (prev) *prev = next; + next = 0; prev = 0; target = 0; + methodIndex = -1; +} + +QmlContextPrivate::ContextGuard::ContextGuard() +: priv(0), bindings(0) +{ +} + +QmlContextPrivate::ContextGuard &QmlContextPrivate::ContextGuard::operator=(QObject *obj) +{ + (QmlGuard<QObject>&)*this = obj; return *this; +} + +void QmlContextPrivate::ContextGuard::objectDestroyed(QObject *) +{ + priv->destroyed(this); +} + +QT_END_NAMESPACE + +#endif // QMLCONTEXT_P_H diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp new file mode 100644 index 0000000..80d52ad --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcontextscriptclass_p.h" + +#include "qmlengine_p.h" +#include "qmlcontext_p.h" +#include "qmltypenamescriptclass_p.h" +#include "qmlguard_p.h" + +QT_BEGIN_NAMESPACE + +struct ContextData : public QScriptDeclarativeClass::Object { + ContextData() : isSharedContext(true) {} + ContextData(QmlContext *c, QObject *o) : context(c), scopeObject(o), isSharedContext(false) {} + QmlGuard<QmlContext> context; + QmlGuard<QObject> scopeObject; + bool isSharedContext; + + QmlContext *getContext(QmlEngine *engine) { + if (isSharedContext) { + return QmlEnginePrivate::get(engine)->sharedContext; + } else { + return context.data(); + } + } + + QObject *getScope(QmlEngine *engine) { + if (isSharedContext) { + return QmlEnginePrivate::get(engine)->sharedScope; + } else { + return scopeObject.data(); + } + } +}; + +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) +: QmlScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), + lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1), lastDefaultObject(-1) +{ +} + +QmlContextScriptClass::~QmlContextScriptClass() +{ +} + +QScriptValue QmlContextScriptClass::newContext(QmlContext *context, QObject *scopeObject) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new ContextData(context, scopeObject)); +} + +QScriptValue QmlContextScriptClass::newSharedContext() +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new ContextData()); +} + +QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + return data->getContext(engine); +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + + lastScopeObject = 0; + lastContext = 0; + lastData = 0; + lastPropertyIndex = -1; + lastDefaultObject = -1; + + QmlContext *bindContext = ((ContextData *)object)->getContext(engine); + QObject *scopeObject = ((ContextData *)object)->getScope(engine); + if (!bindContext) + return 0; + + bool includeTypes = true; + while (bindContext) { + QScriptClass::QueryFlags rv = + queryProperty(bindContext, scopeObject, name, flags, includeTypes); + scopeObject = 0; // Only applies to the first context + includeTypes = false; // Only applies to the first context + if (rv) return rv; + bindContext = bindContext->parentContext(); + } + + return 0; +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObject, + const Identifier &name, + QScriptClass::QueryFlags flags, + bool includeTypes) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; + if (lastPropertyIndex != -1) { + lastContext = bindContext; + return QScriptClass::HandlesReadAccess; + } + + if (includeTypes && cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + + if (data) { + lastData = data; + lastContext = bindContext; + return QScriptClass::HandlesReadAccess; + } + } + + for (int ii = 0; ii < cp->scripts.count(); ++ii) { + lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); + if (lastFunction.isValid()) { + lastContext = bindContext; + return QScriptClass::HandlesReadAccess; + } + } + + if (scopeObject) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(scopeObject, name, flags, bindContext, + QmlObjectScriptClass::ImplicitObject | QmlObjectScriptClass::SkipAttachedProperties); + if (rv) { + lastScopeObject = scopeObject; + lastContext = bindContext; + return rv; + } + } + + for (int ii = cp->defaultObjects.count() - 1; ii >= 0; --ii) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext, + QmlObjectScriptClass::ImplicitObject | QmlObjectScriptClass::SkipAttachedProperties); + + if (rv) { + lastDefaultObject = ii; + lastContext = bindContext; + return rv; + } + } + + return 0; +} + +QmlContextScriptClass::ScriptValue +QmlContextScriptClass::property(Object *object, const Identifier &name) +{ + Q_UNUSED(object); + + QmlContext *bindContext = lastContext; + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (lastScopeObject) { + + return ep->objectClass->property(lastScopeObject, name); + + } else if (lastData) { + + if (lastData->type) + return Value(scriptEngine, ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->type)); + else + return Value(scriptEngine, ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->typeNamespace)); + + } else if (lastPropertyIndex != -1) { + + QScriptValue rv; + if (lastPropertyIndex < cp->idValueCount) { + rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); + } else { + QVariant value = cp->propertyValues.at(lastPropertyIndex); + rv = ep->scriptValueFromVariant(value); + } + + ep->capturedProperties << + QmlEnginePrivate::CapturedProperty(bindContext, -1, lastPropertyIndex + cp->notifyIndex); + + return Value(scriptEngine, rv); + } else if(lastDefaultObject != -1) { + + // Default object property + return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + + } else { + + return Value(scriptEngine, lastFunction); + + } +} + +void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(object); + Q_ASSERT(lastScopeObject || lastDefaultObject != -1); + + QmlContext *bindContext = lastContext; + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + if (lastScopeObject) { + ep->objectClass->setProperty(lastScopeObject, name, value, bindContext); + } else { + ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value, + bindContext); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h new file mode 100644 index 0000000..f98d44f --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXTSCRIPTCLASS_P_H +#define QMLCONTEXTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmltypenamecache_p.h" +#include "qmlscriptclass_p.h" + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlContextScriptClass : public QmlScriptClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + QScriptValue newContext(QmlContext *, QObject * = 0); + QScriptValue newSharedContext(); + + QmlContext *contextFromValue(const QScriptValue &); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual ScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + +private: + QScriptClass::QueryFlags queryProperty(QmlContext *, QObject *scopeObject, + const Identifier &, + QScriptClass::QueryFlags flags, + bool includeTypes); + + QmlEngine *engine; + + QObject *lastScopeObject; + QmlContext *lastContext; + QmlTypeNameCache::Data *lastData; + int lastPropertyIndex; + int lastDefaultObject; + QScriptValue lastFunction; + + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QMLCONTEXTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlcustomparser.cpp b/src/declarative/qml/qmlcustomparser.cpp new file mode 100644 index 0000000..116644a --- /dev/null +++ b/src/declarative/qml/qmlcustomparser.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcustomparser_p.h" +#include "qmlcustomparser_p_p.h" + +#include "qmlparser_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace QmlParser; + +/*! + \class QmlCustomParser + \brief The QmlCustomParser class allows you to add new arbitrary types to QML. + \internal + + By subclassing QmlCustomParser, you can add a parser for + building a particular type. + + The subclass must implement compile() and setCustomData(), and define + itself in the meta type system with the macro: + + \code + QML_DEFINE_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass) + \endcode +*/ + +/* + \fn QByteArray QmlCustomParser::compile(const QList<QmlCustomParserProperty> & properties) + + The custom parser processes \a properties, and returns + a QByteArray containing data meaningful only to the + custom parser; the type engine will pass this same data to + setCustomData() when making an instance of the data. + + Errors must be reported via the error() functions. + + The QByteArray may be cached between executions of the system, so + it must contain correctly-serialized data (not, for example, + pointers to stack objects). +*/ + +/* + \fn void QmlCustomParser::setCustomData(QObject *object, const QByteArray &data) + + This function sets \a object to have the properties defined + by \a data, which is a block of data previously returned by a call + to compile(). + + The \a object will be an instance of the TypeClass specified by QML_DEFINE_CUSTOM_TYPE. +*/ + +QmlCustomParserNode +QmlCustomParserNodePrivate::fromObject(QmlParser::Object *root) +{ + QmlCustomParserNode rootNode; + rootNode.d->name = root->typeName; + rootNode.d->location = root->location.start; + + for(QHash<QByteArray, Property *>::Iterator iter = root->properties.begin(); + iter != root->properties.end(); + ++iter) { + + Property *p = *iter; + + rootNode.d->properties << fromProperty(p); + } + + return rootNode; +} + +QmlCustomParserProperty +QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p) +{ + QmlCustomParserProperty prop; + prop.d->name = p->name; + prop.d->isList = (p->values.count() > 1); + prop.d->location = p->location.start; + + if (p->value) { + QmlCustomParserNode node = fromObject(p->value); + QList<QmlCustomParserProperty> props = node.properties(); + for (int ii = 0; ii < props.count(); ++ii) + prop.d->values << QVariant::fromValue(props.at(ii)); + } else { + for(int ii = 0; ii < p->values.count(); ++ii) { + Value *v = p->values.at(ii); + v->type = QmlParser::Value::Literal; + + if(v->object) { + QmlCustomParserNode node = fromObject(v->object); + prop.d->values << QVariant::fromValue(node); + } else { + prop.d->values << QVariant::fromValue(v->value); + } + + } + } + + return prop; +} + +QmlCustomParserNode::QmlCustomParserNode() +: d(new QmlCustomParserNodePrivate) +{ +} + +QmlCustomParserNode::QmlCustomParserNode(const QmlCustomParserNode &other) +: d(new QmlCustomParserNodePrivate) +{ + *this = other; +} + +QmlCustomParserNode &QmlCustomParserNode::operator=(const QmlCustomParserNode &other) +{ + d->name = other.d->name; + d->properties = other.d->properties; + d->location = other.d->location; + return *this; +} + +QmlCustomParserNode::~QmlCustomParserNode() +{ + delete d; d = 0; +} + +QByteArray QmlCustomParserNode::name() const +{ + return d->name; +} + +QList<QmlCustomParserProperty> QmlCustomParserNode::properties() const +{ + return d->properties; +} + +QmlParser::Location QmlCustomParserNode::location() const +{ + return d->location; +} + +QmlCustomParserProperty::QmlCustomParserProperty() +: d(new QmlCustomParserPropertyPrivate) +{ +} + +QmlCustomParserProperty::QmlCustomParserProperty(const QmlCustomParserProperty &other) +: d(new QmlCustomParserPropertyPrivate) +{ + *this = other; +} + +QmlCustomParserProperty &QmlCustomParserProperty::operator=(const QmlCustomParserProperty &other) +{ + d->name = other.d->name; + d->isList = other.d->isList; + d->values = other.d->values; + d->location = other.d->location; + return *this; +} + +QmlCustomParserProperty::~QmlCustomParserProperty() +{ + delete d; d = 0; +} + +QByteArray QmlCustomParserProperty::name() const +{ + return d->name; +} + +bool QmlCustomParserProperty::isList() const +{ + return d->isList; +} + +QmlParser::Location QmlCustomParserProperty::location() const +{ + return d->location; +} + +QList<QVariant> QmlCustomParserProperty::assignedValues() const +{ + return d->values; +} + +void QmlCustomParser::clearErrors() +{ + exceptions.clear(); +} + +/*! + Reports an error in parsing \a prop, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QmlCustomParser::error(const QmlCustomParserProperty& prop, const QString& description) +{ + QmlError error; + QString exceptionDescription; + error.setLine(prop.location().line); + error.setColumn(prop.location().column); + error.setDescription(description); + exceptions << error; +} + +/*! + Reports an error in parsing \a node, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QmlCustomParser::error(const QmlCustomParserNode& node, const QString& description) +{ + QmlError error; + QString exceptionDescription; + error.setLine(node.location().line); + error.setColumn(node.location().column); + error.setDescription(description); + exceptions << error; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h new file mode 100644 index 0000000..9502b08 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCUSTOMPARSER_H +#define QMLCUSTOMPARSER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlmetatype.h" +#include "qmlerror.h" +#include "qmlparser_p.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qxmlstream.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlCustomParserPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlCustomParserProperty +{ +public: + QmlCustomParserProperty(); + QmlCustomParserProperty(const QmlCustomParserProperty &); + QmlCustomParserProperty &operator=(const QmlCustomParserProperty &); + ~QmlCustomParserProperty(); + + QByteArray name() const; + QmlParser::Location location() const; + + bool isList() const; + // Will be one of QmlParser::Variant, QmlCustomParserProperty or + // QmlCustomParserNode + QList<QVariant> assignedValues() const; + +private: + friend class QmlCustomParserNodePrivate; + friend class QmlCustomParserPropertyPrivate; + QmlCustomParserPropertyPrivate *d; +}; + +class QmlCustomParserNodePrivate; +class Q_DECLARATIVE_EXPORT QmlCustomParserNode +{ +public: + QmlCustomParserNode(); + QmlCustomParserNode(const QmlCustomParserNode &); + QmlCustomParserNode &operator=(const QmlCustomParserNode &); + ~QmlCustomParserNode(); + + QByteArray name() const; + QmlParser::Location location() const; + + QList<QmlCustomParserProperty> properties() const; + +private: + friend class QmlCustomParserNodePrivate; + QmlCustomParserNodePrivate *d; +}; + +class Q_DECLARATIVE_EXPORT QmlCustomParser +{ +public: + virtual ~QmlCustomParser() {} + + void clearErrors(); + + virtual QByteArray compile(const QList<QmlCustomParserProperty> &)=0; + virtual void setCustomData(QObject *, const QByteArray &)=0; + + QList<QmlError> errors() const { return exceptions; } + +protected: + void error(const QmlCustomParserProperty&, const QString& description); + void error(const QmlCustomParserNode&, const QString& description); + +private: + QList<QmlError> exceptions; +}; + +#if defined(Q_OS_SYMBIAN) +# define QML_DEFINE_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ + static int defineCustomType##NAME = qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE); +#else +# define QML_DEFINE_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN)>::instance(qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE)); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QmlCustomParserProperty) +Q_DECLARE_METATYPE(QmlCustomParserNode) + +QT_END_HEADER + +#endif diff --git a/src/declarative/qml/qmlcustomparser_p_p.h b/src/declarative/qml/qmlcustomparser_p_p.h new file mode 100644 index 0000000..c27a5bc --- /dev/null +++ b/src/declarative/qml/qmlcustomparser_p_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCUSTOMPARSER_P_H +#define QMLCUSTOMPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlcustomparser_p.h" + +#include "qmlparser_p.h" + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlCustomParserNodePrivate +{ +public: + QByteArray name; + QList<QmlCustomParserProperty> properties; + QmlParser::Location location; + + static QmlCustomParserNode fromObject(QmlParser::Object *); + static QmlCustomParserProperty fromProperty(QmlParser::Property *); +}; + +class QmlCustomParserPropertyPrivate +{ +public: + QmlCustomParserPropertyPrivate() + : isList(false) {} + + QByteArray name; + bool isList; + QmlParser::Location location; + QList<QVariant> values; +}; + +QT_END_NAMESPACE + +#endif // QMLCUSTOMPARSER_P_H diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h new file mode 100644 index 0000000..e2717e0 --- /dev/null +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDECLARATIVEDATA_P_H +#define QMLDECLARATIVEDATA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptvalue.h> +#include <private/qobject_p.h> +#include "qmlguard_p.h" + +QT_BEGIN_NAMESPACE + +class QmlCompiledData; +class QmlAbstractBinding; +class QmlContext; +class QmlPropertyCache; +class Q_AUTOTEST_EXPORT QmlDeclarativeData : public QDeclarativeData +{ +public: + QmlDeclarativeData(QmlContext *ctxt = 0) + : context(ctxt), bindings(0), nextContextObject(0), prevContextObject(0), + bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), + columnNumber(0), deferredComponent(0), deferredIdx(0), attachedProperties(0), + propertyCache(0), guards(0) {} + + virtual void destroyed(QObject *); + + QmlContext *context; + QmlAbstractBinding *bindings; + + // Linked list for QmlContext::contextObjects + QmlDeclarativeData *nextContextObject; + QmlDeclarativeData**prevContextObject; + + int bindingBitsSize; + quint32 *bindingBits; + bool hasBindingBit(int) const; + void clearBindingBit(int); + void setBindingBit(QObject *obj, int); + + QmlContext *outerContext; // Can't this be found from context? + ushort lineNumber; + ushort columnNumber; + + QmlCompiledData *deferredComponent; // Can't this be found from the context? + unsigned int deferredIdx; + + QHash<int, QObject *> *attachedProperties; + + QScriptValue scriptValue; + QmlPropertyCache *propertyCache; + + QmlGuard<QObject> *guards; + + static QmlDeclarativeData *get(const QObject *object, bool create = false) { + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + if (priv->declarativeData) { + return static_cast<QmlDeclarativeData *>(priv->declarativeData); + } else if (create) { + priv->declarativeData = new QmlDeclarativeData; + return static_cast<QmlDeclarativeData *>(priv->declarativeData); + } else { + return 0; + } + } +}; + +template<class T> +void QmlGuard<T>::addGuard() +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(o, true); + next = data->guards; + if (next) reinterpret_cast<QmlGuard<T> *>(next)->prev = &next; + data->guards = reinterpret_cast<QmlGuard<QObject> *>(this); + prev = &data->guards; +} + +template<class T> +void QmlGuard<T>::remGuard() +{ + if (next) reinterpret_cast<QmlGuard<T> *>(next)->prev = prev; + *prev = next; + next = 0; + prev = 0; +} + +QT_END_NAMESPACE + +#endif // QMLDECLARATIVEDATA_P_H diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp new file mode 100644 index 0000000..52530db --- /dev/null +++ b/src/declarative/qml/qmldom.cpp @@ -0,0 +1,1837 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmldom.h" +#include "qmldom_p.h" + +#include "qmlcompositetypedata_p.h" +#include "qmlcompiler_p.h" +#include "qmlengine_p.h" +#include "qmlscriptparser_p.h" +#include "qmlglobal_p.h" + +#include <QtCore/QByteArray> +#include <QtCore/QDebug> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +QmlDomDocumentPrivate::QmlDomDocumentPrivate() +: root(0) +{ +} + +QmlDomDocumentPrivate::~QmlDomDocumentPrivate() +{ + if (root) root->release(); +} + +/*! + \class QmlDomDocument + \internal + \brief The QmlDomDocument class represents the root of a QML document + + A QML document is a self-contained snippet of QML, usually contained in a + single file. Each document has a root object, accessible through + QmlDomDocument::rootObject(). + + The QmlDomDocument class allows the programmer to inspect a QML document by + calling QmlDomDocument::load(). + + The following example loads a QML file from disk, and prints out its root + object type and the properties assigned in the root object. + \code + QFile file(inputFileName); + file.open(QIODevice::ReadOnly); + QByteArray xmlData = file.readAll(); + + QmlDomDocument document; + document.load(qmlengine, xmlData); + + QmlDomObject rootObject = document.rootObject(); + qDebug() << rootObject.objectType(); + foreach(QmlDomProperty property, rootObject.properties()) + qDebug() << property.propertyName(); + \endcode +*/ + +/*! + Construct an empty QmlDomDocument. +*/ +QmlDomDocument::QmlDomDocument() +: d(new QmlDomDocumentPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomDocument. +*/ +QmlDomDocument::QmlDomDocument(const QmlDomDocument &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomDocument +*/ +QmlDomDocument::~QmlDomDocument() +{ +} + +/*! + Assign \a other to this QmlDomDocument. +*/ +QmlDomDocument &QmlDomDocument::operator=(const QmlDomDocument &other) +{ + d = other.d; + return *this; +} + +/*! + Returns all import statements in qml. +*/ +QList<QmlDomImport> QmlDomDocument::imports() const +{ + return d->imports; +} + +/*! + Loads a QmlDomDocument from \a data. \a data should be valid QML + data. On success, true is returned. If the \a data is malformed, false + is returned and QmlDomDocument::errors() contains an error description. + + \sa QmlDomDocument::loadError() +*/ +bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data, const QUrl &url) +{ + d->errors.clear(); + d->imports.clear(); + + QmlCompiledData *component = new QmlCompiledData(engine); + QmlCompiler compiler; + + QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, url); + + if(td->status == QmlCompositeTypeData::Error) { + d->errors = td->errors; + td->release(); + component->release(); + return false; + } else if(td->status == QmlCompositeTypeData::Waiting || + td->status == QmlCompositeTypeData::WaitingResources) { + QmlError error; + error.setDescription(QLatin1String("QmlDomDocument supports local types only")); + d->errors << error; + td->release(); + component->release(); + return false; + } + + compiler.compile(engine, td, component); + + if (compiler.isError()) { + d->errors = compiler.errors(); + td->release(); + component->release(); + return false; + } + + for (int i = 0; i < td->data.imports().size(); ++i) { + QmlScriptParser::Import parserImport = td->data.imports().at(i); + QmlDomImport domImport; + domImport.d->type = static_cast<QmlDomImportPrivate::Type>(parserImport.type); + domImport.d->uri = parserImport.uri; + domImport.d->qualifier = parserImport.qualifier; + domImport.d->version = parserImport.version; + d->imports += domImport; + } + + if (td->data.tree()) { + d->root = td->data.tree(); + d->root->addref(); + } + + component->release(); + return true; +} + +/*! + Returns the last load errors. The load errors will be reset after a + successful call to load(). + + \sa load() +*/ +QList<QmlError> QmlDomDocument::errors() const +{ + return d->errors; +} + +/*! + Returns the document's root object, or an invalid QmlDomObject if the + document has no root. + + In the sample QML below, the root object will be the QmlGraphicsItem type. + \qml +Item { + Text { + text: "Hello World" + } +} + \endqml +*/ +QmlDomObject QmlDomDocument::rootObject() const +{ + QmlDomObject rv; + rv.d->object = d->root; + if (rv.d->object) rv.d->object->addref(); + return rv; +} + +QmlDomPropertyPrivate::QmlDomPropertyPrivate() +: property(0) +{ +} + +QmlDomPropertyPrivate::~QmlDomPropertyPrivate() +{ + if (property) property->release(); +} + +QmlDomDynamicPropertyPrivate::QmlDomDynamicPropertyPrivate(): + valid(false) +{ +} + +QmlDomDynamicPropertyPrivate::~QmlDomDynamicPropertyPrivate() +{ + if (valid && property.defaultValue) property.defaultValue->release(); +} + +/*! + \class QmlDomProperty + \internal + \brief The QmlDomProperty class represents one property assignment in the + QML DOM tree + + Properties in QML can be assigned QML \l {QmlDomValue}{values}. + + \sa QmlDomObject +*/ + +/*! + Construct an invalid QmlDomProperty. +*/ +QmlDomProperty::QmlDomProperty() +: d(new QmlDomPropertyPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomProperty. +*/ +QmlDomProperty::QmlDomProperty(const QmlDomProperty &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomProperty. +*/ +QmlDomProperty::~QmlDomProperty() +{ +} + +/*! + Assign \a other to this QmlDomProperty. +*/ +QmlDomProperty &QmlDomProperty::operator=(const QmlDomProperty &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this is a valid QmlDomProperty, false otherwise. +*/ +bool QmlDomProperty::isValid() const +{ + return d->property != 0; +} + + +/*! + Return the name of this property. + + \qml +Text { + x: 10 + y: 10 + font.bold: true +} + \endqml + + As illustrated above, a property name can be a simple string, such as "x" or + "y", or a more complex "dot property", such as "font.bold". In both cases + the full name is returned ("x", "y" and "font.bold") by this method. + + For dot properties, a split version of the name can be accessed by calling + QmlDomProperty::propertyNameParts(). + + \sa QmlDomProperty::propertyNameParts() +*/ +QByteArray QmlDomProperty::propertyName() const +{ + return d->propertyName; +} + +/*! + Return the name of this property, split into multiple parts in the case + of dot properties. + + \qml +Text { + x: 10 + y: 10 + font.bold: true +} + \endqml + + For each of the properties shown above, this method would return ("x"), + ("y") and ("font", "bold"). + + \sa QmlDomProperty::propertyName() +*/ +QList<QByteArray> QmlDomProperty::propertyNameParts() const +{ + if (d->propertyName.isEmpty()) return QList<QByteArray>(); + else return d->propertyName.split('.'); +} + +/*! + Return true if this property is used as a default property in the QML + document. + + \qml +<Text text="hello"/> +<Text>hello</Text> + \endqml + + The above two examples return the same DOM tree, except that the second has + the default property flag set on the text property. Observe that whether + or not a property has isDefaultProperty set is determined by how the + property is used, and not only by whether the property is the types default + property. +*/ +bool QmlDomProperty::isDefaultProperty() const +{ + return d->property && d->property->isDefault; +} + +/*! + Returns the QmlDomValue that is assigned to this property, or an invalid + QmlDomValue if no value is assigned. +*/ +QmlDomValue QmlDomProperty::value() const +{ + QmlDomValue rv; + if (d->property) { + rv.d->property = d->property; + rv.d->value = d->property->values.at(0); + rv.d->property->addref(); + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns the position in the input data where the property ID startd, or -1 if + the property is invalid. +*/ +int QmlDomProperty::position() const +{ + if (d && d->property) { + return d->property->location.range.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the property ID started upto + the end of it, or -1 if the property is invalid. +*/ +int QmlDomProperty::length() const +{ + if (d && d->property) + return d->property->location.range.length; + else + return -1; +} + +/*! + Construct an invalid QmlDomDynamicProperty. +*/ +QmlDomDynamicProperty::QmlDomDynamicProperty(): + d(new QmlDomDynamicPropertyPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomDynamicProperty. +*/ +QmlDomDynamicProperty::QmlDomDynamicProperty(const QmlDomDynamicProperty &other): + d(other.d) +{ +} + +/*! + Destroy the QmlDomDynamicProperty. +*/ +QmlDomDynamicProperty::~QmlDomDynamicProperty() +{ +} + +/*! + Assign \a other to this QmlDomDynamicProperty. +*/ +QmlDomDynamicProperty &QmlDomDynamicProperty::operator=(const QmlDomDynamicProperty &other) +{ + d = other.d; + return *this; +} + +bool QmlDomDynamicProperty::isValid() const +{ + return d && d->valid; +} + +/*! + Return the name of this dynamic property. + + \qml +Item { + property int count: 10; +} + \endqml + + As illustrated above, a dynamic property name can have a name and a + default value ("10"). +*/ +QByteArray QmlDomDynamicProperty::propertyName() const +{ + if (isValid()) + return d->property.name; + else + return QByteArray(); +} + +/*! + Returns the type of the dynamic property. Note that when the property is an + alias property, this will return -1. Use QmlDomProperty::isAlias() to check + if the property is an alias. +*/ +int QmlDomDynamicProperty::propertyType() const +{ + if (isValid()) { + switch (d->property.type) { + case QmlParser::Object::DynamicProperty::Bool: + return QMetaType::type("bool"); + + case QmlParser::Object::DynamicProperty::Color: + return QMetaType::type("QColor"); + + case QmlParser::Object::DynamicProperty::Date: + return QMetaType::type("QDate"); + + case QmlParser::Object::DynamicProperty::Int: + return QMetaType::type("int"); + + case QmlParser::Object::DynamicProperty::Real: + return QMetaType::type("double"); + + case QmlParser::Object::DynamicProperty::String: + return QMetaType::type("QString"); + + case QmlParser::Object::DynamicProperty::Url: + return QMetaType::type("QUrl"); + + case QmlParser::Object::DynamicProperty::Variant: + return QMetaType::type("QVariant"); + + default: + break; + } + } + + return -1; +} + +QByteArray QmlDomDynamicProperty::propertyTypeName() const +{ + if (isValid()) + return d->property.customType; + + return QByteArray(); +} + +/*! + Return true if this property is used as a default property in the QML + document. + + \qml +<Text text="hello"/> +<Text>hello</Text> + \endqml + + The above two examples return the same DOM tree, except that the second has + the default property flag set on the text property. Observe that whether + or not a property has isDefaultProperty set is determined by how the + property is used, and not only by whether the property is the types default + property. +*/ +bool QmlDomDynamicProperty::isDefaultProperty() const +{ + if (isValid()) + return d->property.isDefaultProperty; + else + return false; +} + +/*! + Returns the default value as a QmlDomProperty. +*/ +QmlDomProperty QmlDomDynamicProperty::defaultValue() const +{ + QmlDomProperty rp; + + if (isValid() && d->property.defaultValue) { + rp.d->property = d->property.defaultValue; + rp.d->propertyName = propertyName(); + rp.d->property->addref(); + } + + return rp; +} + +/*! + Returns true if this dynamic property is an alias for another property, + false otherwise. +*/ +bool QmlDomDynamicProperty::isAlias() const +{ + if (isValid()) + return d->property.type == QmlParser::Object::DynamicProperty::Alias; + else + return false; +} + +/*! + Returns the position in the input data where the property ID startd, or 0 if + the property is invalid. +*/ +int QmlDomDynamicProperty::position() const +{ + if (isValid()) { + return d->property.location.range.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the property ID started upto + the end of it, or 0 if the property is invalid. +*/ +int QmlDomDynamicProperty::length() const +{ + if (isValid()) + return d->property.location.range.length; + else + return -1; +} + +QmlDomObjectPrivate::QmlDomObjectPrivate() +: object(0) +{ +} + +QmlDomObjectPrivate::~QmlDomObjectPrivate() +{ + if (object) object->release(); +} + +QmlDomObjectPrivate::Properties +QmlDomObjectPrivate::properties() const +{ + Properties rv; + + for (QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + object->properties.begin(); + iter != object->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + return rv; +} + +QmlDomObjectPrivate::Properties +QmlDomObjectPrivate::properties(QmlParser::Property *property) const +{ + Properties rv; + + if (property->value) { + + for (QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + property->value->properties.begin(); + iter != property->value->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + + QByteArray name(property->name + '.'); + for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter) + iter->second.prepend(name); + + } else { + rv << qMakePair(property, property->name); + } + + return rv; +} + +/*! + \class QmlDomObject + \internal + \brief The QmlDomObject class represents an object instantiation. + + Each object instantiated in a QML file has a corresponding QmlDomObject + node in the QML DOM. + + In addition to the type information that determines the object to + instantiate, QmlDomObject's also have a set of associated QmlDomProperty's. + Each QmlDomProperty represents a QML property assignment on the instantiated + object. For example, + + \qml +QGraphicsWidget { + opacity: 0.5 + size: "100x100" +} + \endqml + + describes a single QmlDomObject - "QGraphicsWidget" - with two properties, + "opacity" and "size". Obviously QGraphicsWidget has many more properties than just + these two, but the QML DOM representation only contains those assigned + values (or bindings) in the QML file. +*/ + +/*! + Construct an invalid QmlDomObject. +*/ +QmlDomObject::QmlDomObject() +: d(new QmlDomObjectPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomObject. +*/ +QmlDomObject::QmlDomObject(const QmlDomObject &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomObject. +*/ +QmlDomObject::~QmlDomObject() +{ +} + +/*! + Assign \a other to this QmlDomObject. +*/ +QmlDomObject &QmlDomObject::operator=(const QmlDomObject &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this is a valid QmlDomObject, false otherwise. +*/ +bool QmlDomObject::isValid() const +{ + return d->object != 0; +} + +/*! + Returns the fully-qualified type name of this object. + + For example, the type of this object would be "Qt/4.6/Rectangle". + \qml +Rectangle { } + \endqml +*/ +QByteArray QmlDomObject::objectType() const +{ + if (d->object) return d->object->typeName; + else return QByteArray(); +} + +/*! + Returns the type name as referenced in the qml file. + + For example, the type of this object would be "Rectangle". + \qml +Rectangle { } + \endqml +*/ +QByteArray QmlDomObject::objectClassName() const +{ + if (d->object) + return d->object->className; + else + return QByteArray(); +} + +int QmlDomObject::objectTypeMajorVersion() const +{ + if (d->object) + return d->object->majorVersion; + else + return -1; +} + +int QmlDomObject::objectTypeMinorVersion() const +{ + if (d->object) + return d->object->minorVersion; + else + return -1; +} + +/*! + Returns the QML id assigned to this object, or an empty QByteArray if no id + has been assigned. + + For example, the object id of this object would be "MyText". + \qml +Text { id: myText } + \endqml +*/ +QString QmlDomObject::objectId() const +{ + if (d->object) { + return d->object->id; + } else { + return QString(); + } +} + +/*! + Returns the list of assigned properties on this object. + + In the following example, "text" and "x" properties would be returned. + \qml +Text { + text: "Hello world!" + x: 100 +} + \endqml +*/ +QList<QmlDomProperty> QmlDomObject::properties() const +{ + QList<QmlDomProperty> rv; + + if (!d->object || isComponent()) + return rv; + + QmlDomObjectPrivate::Properties properties = d->properties(); + for (int ii = 0; ii < properties.count(); ++ii) { + + QmlDomProperty domProperty; + domProperty.d->property = properties.at(ii).first; + domProperty.d->property->addref(); + domProperty.d->propertyName = properties.at(ii).second; + rv << domProperty; + + } + + if (d->object->defaultProperty) { + QmlDomProperty domProperty; + domProperty.d->property = d->object->defaultProperty; + domProperty.d->property->addref(); + domProperty.d->propertyName = d->object->defaultProperty->name; + rv << domProperty; + } + + return rv; +} + +/*! + Returns the object's \a name property if a value has been assigned to + it, or an invalid QmlDomProperty otherwise. + + In the example below, \c {object.property("source")} would return a valid + QmlDomProperty, and \c {object.property("tile")} an invalid QmlDomProperty. + + \qml +Image { source: "sample.jpg" } + \endqml +*/ +QmlDomProperty QmlDomObject::property(const QByteArray &name) const +{ + QList<QmlDomProperty> props = properties(); + for (int ii = 0; ii < props.count(); ++ii) + if (props.at(ii).propertyName() == name) + return props.at(ii); + return QmlDomProperty(); +} + +QList<QmlDomDynamicProperty> QmlDomObject::dynamicProperties() const +{ + QList<QmlDomDynamicProperty> properties; + + for (int i = 0; i < d->object->dynamicProperties.size(); ++i) { + QmlDomDynamicProperty p; + p.d = new QmlDomDynamicPropertyPrivate; + p.d->property = d->object->dynamicProperties.at(i); + p.d->valid = true; + + if (p.d->property.defaultValue) + p.d->property.defaultValue->addref(); + + properties.append(p); + } + + return properties; +} + +QmlDomDynamicProperty QmlDomObject::dynamicProperty(const QByteArray &name) const +{ + QmlDomDynamicProperty p; + + if (!isValid()) + return p; + + for (int i = 0; i < d->object->dynamicProperties.size(); ++i) { + if (d->object->dynamicProperties.at(i).name == name) { + p.d = new QmlDomDynamicPropertyPrivate; + p.d->property = d->object->dynamicProperties.at(i); + if (p.d->property.defaultValue) p.d->property.defaultValue->addref(); + p.d->valid = true; + } + } + + return p; +} + +/*! + Returns true if this object is a custom type. Custom types are special + types that allow embeddeding non-QML data, such as SVG or HTML data, + directly into QML files. + + \note Currently this method will always return false, and is a placekeeper + for future functionality. + + \sa QmlDomObject::customTypeData() +*/ +bool QmlDomObject::isCustomType() const +{ + return false; +} + +/*! + If this object represents a custom type, returns the data associated with + the custom type, otherwise returns an empty QByteArray(). + QmlDomObject::isCustomType() can be used to check if this object represents + a custom type. +*/ +QByteArray QmlDomObject::customTypeData() const +{ + return QByteArray(); +} + +/*! + Returns true if this object is a sub-component object. Sub-component + objects can be converted into QmlDomComponent instances by calling + QmlDomObject::toComponent(). + + \sa QmlDomObject::toComponent() +*/ +bool QmlDomObject::isComponent() const +{ + return (d->object && d->object->typeName == "Qt/Component"); +} + +/*! + Returns a QmlDomComponent for this object if it is a sub-component, or + an invalid QmlDomComponent if not. QmlDomObject::isComponent() can be used + to check if this object represents a sub-component. + + \sa QmlDomObject::isComponent() +*/ +QmlDomComponent QmlDomObject::toComponent() const +{ + QmlDomComponent rv; + if (isComponent()) + rv.d = d; + return rv; +} + +/*! + Returns the position in the input data where the property assignment started +, or -1 if the property is invalid. +*/ +int QmlDomObject::position() const +{ + if (d && d->object) + return d->object->location.range.offset; + else + return -1; +} + +/*! + Returns the length in the input data from where the property assignment star +ted upto the end of it, or -1 if the property is invalid. +*/ +int QmlDomObject::length() const +{ + if (d && d->object) + return d->object->location.range.length; + else + return -1; +} + +// Returns the URL of the type, if it is an external type, or an empty URL if +// not +QUrl QmlDomObject::url() const +{ + if (d && d->object) + return d->object->url; + else + return QUrl(); +} + +QmlDomBasicValuePrivate::QmlDomBasicValuePrivate() +: value(0) +{ +} + +QmlDomBasicValuePrivate::~QmlDomBasicValuePrivate() +{ + if (value) value->release(); +} + +/*! + \class QmlDomValueLiteral + \internal + \brief The QmlDomValueLiteral class represents a literal value. + + A literal value is a simple value, written inline with the QML. In the + example below, the "x", "y" and "color" properties are being assigned + literal values. + + \qml +Rectangle { + x: 10 + y: 10 + color: "red" +} + \endqml +*/ + +/*! + Construct an empty QmlDomValueLiteral. +*/ +QmlDomValueLiteral::QmlDomValueLiteral(): + d(new QmlDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValueLiteral. +*/ +QmlDomValueLiteral::QmlDomValueLiteral(const QmlDomValueLiteral &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueLiteral. +*/ +QmlDomValueLiteral::~QmlDomValueLiteral() +{ +} + +/*! + Assign \a other to this QmlDomValueLiteral. +*/ +QmlDomValueLiteral &QmlDomValueLiteral::operator=(const QmlDomValueLiteral &other) +{ + d = other.d; + return *this; +} + +/*! + Return the literal value. + + In the example below, the literal value will be the string "10". + \qml +Rectangle { x: 10 } + \endqml +*/ +QString QmlDomValueLiteral::literal() const +{ + if (d->value) return d->value->primitive(); + else return QString(); +} + +/*! + \class QmlDomValueBinding + \internal + \brief The QmlDomValueBinding class represents a property binding. + + A property binding is an ECMAScript expression assigned to a property. In + the example below, the "x" property is being assigned a property binding. + + \qml +Rectangle { x: Other.x } + \endqml +*/ + +/*! + Construct an empty QmlDomValueBinding. +*/ +QmlDomValueBinding::QmlDomValueBinding(): + d(new QmlDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValueBinding. +*/ +QmlDomValueBinding::QmlDomValueBinding(const QmlDomValueBinding &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueBinding. +*/ +QmlDomValueBinding::~QmlDomValueBinding() +{ +} + +/*! + Assign \a other to this QmlDomValueBinding. +*/ +QmlDomValueBinding &QmlDomValueBinding::operator=(const QmlDomValueBinding &other) +{ + d = other.d; + return *this; +} + +/*! + Return the binding expression. + + In the example below, the string "Other.x" will be returned. + \qml +Rectangle { x: Other.x } + \endqml +*/ +QString QmlDomValueBinding::binding() const +{ + if (d->value) + return d->value->value.asScript(); + else + return QString(); +} + +/*! + \class QmlDomValueValueSource + \internal + \brief The QmlDomValueValueSource class represents a value source assignment value. + + In QML, value sources are special value generating types that may be + assigned to properties. Value sources inherit the QmlPropertyValueSource + class. In the example below, the "x" property is being assigned the + NumberAnimation value source. + + \qml +Rectangle { + x: NumberAnimation { + from: 0 + to: 100 + repeat: true + running: true + } +} + \endqml +*/ + +/*! + Construct an empty QmlDomValueValueSource. +*/ +QmlDomValueValueSource::QmlDomValueValueSource(): + d(new QmlDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValueValueSource. +*/ +QmlDomValueValueSource::QmlDomValueValueSource(const QmlDomValueValueSource &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueValueSource. +*/ +QmlDomValueValueSource::~QmlDomValueValueSource() +{ +} + +/*! + Assign \a other to this QmlDomValueValueSource. +*/ +QmlDomValueValueSource &QmlDomValueValueSource::operator=(const QmlDomValueValueSource &other) +{ + d = other.d; + return *this; +} + +/*! + Return the value source object. + + In the example below, an object representing the NumberAnimation will be + returned. + \qml +Rectangle { + x: NumberAnimation { + from: 0 + to: 100 + repeat: true + running: true + } +} + \endqml +*/ +QmlDomObject QmlDomValueValueSource::object() const +{ + QmlDomObject rv; + if (d->value) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +/*! + \class QmlDomValueValueInterceptor + \internal + \brief The QmlDomValueValueInterceptor class represents a value interceptor assignment value. + + In QML, value interceptor are special write-intercepting types that may be + assigned to properties. Value interceptor inherit the QmlPropertyValueInterceptor + class. In the example below, the "x" property is being assigned the + Behavior value interceptor. + + \qml +Rectangle { + x: Behavior { NumberAnimation { duration: 500 } } +} + \endqml +*/ + +/*! + Construct an empty QmlDomValueValueInterceptor. +*/ +QmlDomValueValueInterceptor::QmlDomValueValueInterceptor(): + d(new QmlDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValueValueInterceptor. +*/ +QmlDomValueValueInterceptor::QmlDomValueValueInterceptor(const QmlDomValueValueInterceptor &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueValueInterceptor. +*/ +QmlDomValueValueInterceptor::~QmlDomValueValueInterceptor() +{ +} + +/*! + Assign \a other to this QmlDomValueValueInterceptor. +*/ +QmlDomValueValueInterceptor &QmlDomValueValueInterceptor::operator=(const QmlDomValueValueInterceptor &other) +{ + d = other.d; + return *this; +} + +/*! + Return the value interceptor object. + + In the example below, an object representing the Behavior will be + returned. + \qml +Rectangle { + x: Behavior { NumberAnimation { duration: 500 } } +} + \endqml +*/ +QmlDomObject QmlDomValueValueInterceptor::object() const +{ + QmlDomObject rv; + if (d->value) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +QmlDomValuePrivate::QmlDomValuePrivate() +: property(0), value(0) +{ +} + +QmlDomValuePrivate::~QmlDomValuePrivate() +{ + if (property) property->release(); + if (value) value->release(); +} + +/*! + \class QmlDomValue + \internal + \brief The QmlDomValue class represents a generic Qml value. + + QmlDomValue's can be assigned to QML \l {QmlDomProperty}{properties}. In + QML, properties can be assigned various different values, including basic + literals, property bindings, property value sources, objects and lists of + values. The QmlDomValue class allows a programmer to determine the specific + value type being assigned and access more detailed information through a + corresponding value type class. + + For example, in the following example, + + \qml +Text { + text: "Hello World!" + y: Other.y +} + \endqml + + The text property is being assigned a literal, and the y property a property + binding. To output the values assigned to the text and y properties in the + above example from C++, + + \code + QmlDomDocument document; + QmlDomObject root = document.rootObject(); + + QmlDomProperty text = root.property("text"); + if (text.value().isLiteral()) { + QmlDomValueLiteral literal = text.value().toLiteral(); + qDebug() << literal.literal(); + } + + QmlDomProperty y = root.property("y"); + if (y.value().isBinding()) { + QmlDomValueBinding binding = y.value().toBinding(); + qDebug() << binding.binding(); + } + \endcode +*/ + +/*! + Construct an invalid QmlDomValue. +*/ +QmlDomValue::QmlDomValue() +: d(new QmlDomValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValue. +*/ +QmlDomValue::QmlDomValue(const QmlDomValue &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValue +*/ +QmlDomValue::~QmlDomValue() +{ +} + +/*! + Assign \a other to this QmlDomValue. +*/ +QmlDomValue &QmlDomValue::operator=(const QmlDomValue &other) +{ + d = other.d; + return *this; +} + +/*! + \enum QmlDomValue::Type + + The type of the QmlDomValue node. + + \value Invalid The QmlDomValue is invalid. + \value Literal The QmlDomValue is a literal value assignment. Use QmlDomValue::toLiteral() to access the type instance. + \value PropertyBinding The QmlDomValue is a property binding. Use QmlDomValue::toBinding() to access the type instance. + \value ValueSource The QmlDomValue is a property value source. Use QmlDomValue::toValueSource() to access the type instance. + \value ValueInterceptor The QmlDomValue is a property value interceptor. Use QmlDomValue::toValueInterceptor() to access the type instance. + \value Object The QmlDomValue is an object assignment. Use QmlDomValue::toObject() to access the type instnace. + \value List The QmlDomValue is a list of other values. Use QmlDomValue::toList() to access the type instance. +*/ + +/*! + Returns the type of this QmlDomValue. +*/ +QmlDomValue::Type QmlDomValue::type() const +{ + if (d->property) + if (QmlMetaType::isList(d->property->type) || + QmlMetaType::isQmlList(d->property->type) || + (d->property && d->property->values.count() > 1)) + return List; + + QmlParser::Value *value = d->value; + if (!value && !d->property) + return Invalid; + + switch(value->type) { + case QmlParser::Value::Unknown: + return Invalid; + case QmlParser::Value::Literal: + return Literal; + case QmlParser::Value::PropertyBinding: + return PropertyBinding; + case QmlParser::Value::ValueSource: + return ValueSource; + case QmlParser::Value::ValueInterceptor: + return ValueInterceptor; + case QmlParser::Value::CreatedObject: + return Object; + case QmlParser::Value::SignalObject: + return Invalid; + case QmlParser::Value::SignalExpression: + return Literal; + case QmlParser::Value::Id: + return Literal; + } + return Invalid; +} + +/*! + Returns true if this is an invalid value, otherwise false. +*/ +bool QmlDomValue::isInvalid() const +{ + return type() == Invalid; +} + +/*! + Returns true if this is a literal value, otherwise false. +*/ +bool QmlDomValue::isLiteral() const +{ + return type() == Literal; +} + +/*! + Returns true if this is a property binding value, otherwise false. +*/ +bool QmlDomValue::isBinding() const +{ + return type() == PropertyBinding; +} + +/*! + Returns true if this is a value source value, otherwise false. +*/ +bool QmlDomValue::isValueSource() const +{ + return type() == ValueSource; +} + +/*! + Returns true if this is a value interceptor value, otherwise false. +*/ +bool QmlDomValue::isValueInterceptor() const +{ + return type() == ValueInterceptor; +} + +/*! + Returns true if this is an object value, otherwise false. +*/ +bool QmlDomValue::isObject() const +{ + return type() == Object; +} + +/*! + Returns true if this is a list value, otherwise false. +*/ +bool QmlDomValue::isList() const +{ + return type() == List; +} + +/*! + Returns a QmlDomValueLiteral if this value is a literal type, otherwise + returns an invalid QmlDomValueLiteral. + + \sa QmlDomValue::type() +*/ +QmlDomValueLiteral QmlDomValue::toLiteral() const +{ + QmlDomValueLiteral rv; + if (type() == Literal) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomValueBinding if this value is a property binding type, + otherwise returns an invalid QmlDomValueBinding. + + \sa QmlDomValue::type() +*/ +QmlDomValueBinding QmlDomValue::toBinding() const +{ + QmlDomValueBinding rv; + if (type() == PropertyBinding) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomValueValueSource if this value is a property value source + type, otherwise returns an invalid QmlDomValueValueSource. + + \sa QmlDomValue::type() +*/ +QmlDomValueValueSource QmlDomValue::toValueSource() const +{ + QmlDomValueValueSource rv; + if (type() == ValueSource) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomValueValueInterceptor if this value is a property value interceptor + type, otherwise returns an invalid QmlDomValueValueInterceptor. + + \sa QmlDomValue::type() +*/ +QmlDomValueValueInterceptor QmlDomValue::toValueInterceptor() const +{ + QmlDomValueValueInterceptor rv; + if (type() == ValueInterceptor) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomObject if this value is an object assignment type, otherwise + returns an invalid QmlDomObject. + + \sa QmlDomValue::type() +*/ +QmlDomObject QmlDomValue::toObject() const +{ + QmlDomObject rv; + if (type() == Object) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +/*! + Returns a QmlDomList if this value is a list type, otherwise returns an + invalid QmlDomList. + + \sa QmlDomValue::type() +*/ +QmlDomList QmlDomValue::toList() const +{ + QmlDomList rv; + if (type() == List) { + rv.d = d; + } + return rv; +} + +/*! + Returns the position in the input data where the property value startd, or -1 + if the value is invalid. +*/ +int QmlDomValue::position() const +{ + if (type() == Invalid) + return -1; + else + return d->value->location.range.offset; +} + +/*! + Returns the length in the input data from where the property value started u +pto the end of it, or -1 if the value is invalid. +*/ +int QmlDomValue::length() const +{ + if (type() == Invalid) + return -1; + else + return d->value->location.range.length; +} + +/*! + \class QmlDomList + \internal + \brief The QmlDomList class represents a list of values assigned to a QML property. + + Lists of values can be assigned to properties. For example, the following + example assigns multiple objects to Item's "children" property + \qml +Item { + children: [ + Text { }, + Rectangle { } + ] +} + \endqml + + Lists can also be implicitly created by assigning multiple + \l {QmlDomValueValueSource}{value sources} or constants to a property. + \qml +Item { + x: 10 + x: NumberAnimation { + running: false + from: 0 + to: 100 + } +} + \endqml +*/ + +/*! + Construct an empty QmlDomList. +*/ +QmlDomList::QmlDomList() +{ +} + +/*! + Create a copy of \a other QmlDomList. +*/ +QmlDomList::QmlDomList(const QmlDomList &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomList. +*/ +QmlDomList::~QmlDomList() +{ +} + +/*! + Assign \a other to this QmlDomList. +*/ +QmlDomList &QmlDomList::operator=(const QmlDomList &other) +{ + d = other.d; + return *this; +} + +/*! + Returns the list of QmlDomValue's. +*/ +QList<QmlDomValue> QmlDomList::values() const +{ + QList<QmlDomValue> rv; + if (!d->property) + return rv; + + for (int ii = 0; ii < d->property->values.count(); ++ii) { + QmlDomValue v; + v.d->value = d->property->values.at(ii); + v.d->value->addref(); + rv << v; + } + + return rv; +} + +/*! + Returns the position in the input data where the list started, or -1 if + the property is invalid. +*/ +int QmlDomList::position() const +{ + if (d && d->property) { + return d->property->listValueRange.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the list started upto + the end of it, or 0 if the property is invalid. +*/ +int QmlDomList::length() const +{ + if (d && d->property) + return d->property->listValueRange.length; + else + return -1; +} + +/*! + Returns a list of positions of the commas in the QML file. +*/ +QList<int> QmlDomList:: commaPositions() const +{ + if (d && d->property) + return d->property->listCommaPositions; + else + return QList<int>(); +} + +/*! + \class QmlDomComponent + \internal + \brief The QmlDomComponent class represents sub-component within a QML document. + + Sub-components are QmlComponents defined within a QML document. The + following example shows the definition of a sub-component with the id + "listDelegate". + + \qml +Item { + Component { + id: listDelegate + Text { + text: modelData.text + } + } +} + \endqml + + Like QmlDomDocument's, components contain a single root object. +*/ + +/*! + Construct an empty QmlDomComponent. +*/ +QmlDomComponent::QmlDomComponent() +{ +} + +/*! + Create a copy of \a other QmlDomComponent. +*/ +QmlDomComponent::QmlDomComponent(const QmlDomComponent &other) +: QmlDomObject(other) +{ +} + +/*! + Destroy the QmlDomComponent. +*/ +QmlDomComponent::~QmlDomComponent() +{ +} + +/*! + Assign \a other to this QmlDomComponent. +*/ +QmlDomComponent &QmlDomComponent::operator=(const QmlDomComponent &other) +{ + static_cast<QmlDomObject &>(*this) = other; + return *this; +} + +/*! + Returns the component's root object. + + In the example below, the root object is the "Text" object. + \qml +Item { + Component { + id: listDelegate + Text { + text: modelData.text + } + } +} + \endqml +*/ +QmlDomObject QmlDomComponent::componentRoot() const +{ + QmlDomObject rv; + if (d->object) { + QmlParser::Object *obj = 0; + if (d->object->defaultProperty && + d->object->defaultProperty->values.count() == 1 && + d->object->defaultProperty->values.at(0)->object) + obj = d->object->defaultProperty->values.at(0)->object; + + if (obj) { + rv.d->object = obj; + rv.d->object->addref(); + } + } + + return rv; +} + +QmlDomImportPrivate::QmlDomImportPrivate() +: type(File) +{ +} + +QmlDomImportPrivate::~QmlDomImportPrivate() +{ +} + +/*! + \class QmlDomImport + \internal + \brief The QmlDomImport class represents an import statement. +*/ + +/*! + Construct an empty QmlDomImport. +*/ +QmlDomImport::QmlDomImport() +: d(new QmlDomImportPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomImport. +*/ +QmlDomImport::QmlDomImport(const QmlDomImport &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomImport. +*/ +QmlDomImport::~QmlDomImport() +{ +} + +/*! + Assign \a other to this QmlDomImport. +*/ +QmlDomImport &QmlDomImport::operator=(const QmlDomImport &other) +{ + d = other.d; + return *this; +} + +/*! + Returns the type of the import. + */ +QmlDomImport::Type QmlDomImport::type() const +{ + return static_cast<QmlDomImport::Type>(d->type); +} + +/*! + Returns the URI of the import (e.g. 'subdir' or 'com.nokia.Qt') + */ +QString QmlDomImport::uri() const +{ + return d->uri; +} + +/*! + Returns the version specified by the import. An empty string if no version was specified. + */ +QString QmlDomImport::version() const +{ + return d->version; +} + +/*! + Returns the (optional) qualifier string (the token following the 'as' keyword) of the import. + */ +QString QmlDomImport::qualifier() const +{ + return d->qualifier; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h new file mode 100644 index 0000000..8442f49 --- /dev/null +++ b/src/declarative/qml/qmldom.h @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDOM_H +#define QMLDOM_H + +#include "qmlerror.h" + +#include <QtCore/qlist.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QByteArray; +class QmlDomObject; +class QmlDomList; +class QmlDomValue; +class QmlEngine; +class QmlDomComponent; +class QmlDomImport; +class QIODevice; + +class QmlDomDocumentPrivate; + +class Q_DECLARATIVE_EXPORT QmlDomDocument +{ +public: + QmlDomDocument(); + QmlDomDocument(const QmlDomDocument &); + ~QmlDomDocument(); + QmlDomDocument &operator=(const QmlDomDocument &); + + QList<QmlDomImport> imports() const; + + QList<QmlError> errors() const; + bool load(QmlEngine *, const QByteArray &, const QUrl & = QUrl()); + + QmlDomObject rootObject() const; + +private: + QSharedDataPointer<QmlDomDocumentPrivate> d; +}; + +class QmlDomPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlDomProperty +{ +public: + QmlDomProperty(); + QmlDomProperty(const QmlDomProperty &); + ~QmlDomProperty(); + QmlDomProperty &operator=(const QmlDomProperty &); + + bool isValid() const; + + QByteArray propertyName() const; + QList<QByteArray> propertyNameParts() const; + + bool isDefaultProperty() const; + + QmlDomValue value() const; + + int position() const; + int length() const; + +private: + friend class QmlDomObject; + friend class QmlDomDynamicProperty; + QSharedDataPointer<QmlDomPropertyPrivate> d; +}; + +class QmlDomDynamicPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlDomDynamicProperty +{ +public: + QmlDomDynamicProperty(); + QmlDomDynamicProperty(const QmlDomDynamicProperty &); + ~QmlDomDynamicProperty(); + QmlDomDynamicProperty &operator=(const QmlDomDynamicProperty &); + + bool isValid() const; + + QByteArray propertyName() const; + int propertyType() const; + QByteArray propertyTypeName() const; + + bool isDefaultProperty() const; + QmlDomProperty defaultValue() const; + + bool isAlias() const; + + int position() const; + int length() const; + +private: + friend class QmlDomObject; + QSharedDataPointer<QmlDomDynamicPropertyPrivate> d; +}; + +class QmlDomObjectPrivate; +class Q_DECLARATIVE_EXPORT QmlDomObject +{ +public: + QmlDomObject(); + QmlDomObject(const QmlDomObject &); + ~QmlDomObject(); + QmlDomObject &operator=(const QmlDomObject &); + + bool isValid() const; + + QByteArray objectType() const; + QByteArray objectClassName() const; + + int objectTypeMajorVersion() const; + int objectTypeMinorVersion() const; + + QString objectId() const; + + QList<QmlDomProperty> properties() const; + QmlDomProperty property(const QByteArray &) const; + + QList<QmlDomDynamicProperty> dynamicProperties() const; + QmlDomDynamicProperty dynamicProperty(const QByteArray &) const; + + bool isCustomType() const; + QByteArray customTypeData() const; + + bool isComponent() const; + QmlDomComponent toComponent() const; + + int position() const; + int length() const; + + QUrl url() const; +private: + friend class QmlDomDocument; + friend class QmlDomComponent; + friend class QmlDomValue; + friend class QmlDomValueValueSource; + friend class QmlDomValueValueInterceptor; + QSharedDataPointer<QmlDomObjectPrivate> d; +}; + +class QmlDomValuePrivate; +class QmlDomBasicValuePrivate; +class Q_DECLARATIVE_EXPORT QmlDomValueLiteral +{ +public: + QmlDomValueLiteral(); + QmlDomValueLiteral(const QmlDomValueLiteral &); + ~QmlDomValueLiteral(); + QmlDomValueLiteral &operator=(const QmlDomValueLiteral &); + + QString literal() const; + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValueBinding +{ +public: + QmlDomValueBinding(); + QmlDomValueBinding(const QmlDomValueBinding &); + ~QmlDomValueBinding(); + QmlDomValueBinding &operator=(const QmlDomValueBinding &); + + QString binding() const; + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValueValueSource +{ +public: + QmlDomValueValueSource(); + QmlDomValueValueSource(const QmlDomValueValueSource &); + ~QmlDomValueValueSource(); + QmlDomValueValueSource &operator=(const QmlDomValueValueSource &); + + QmlDomObject object() const; + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValueValueInterceptor +{ +public: + QmlDomValueValueInterceptor(); + QmlDomValueValueInterceptor(const QmlDomValueValueInterceptor &); + ~QmlDomValueValueInterceptor(); + QmlDomValueValueInterceptor &operator=(const QmlDomValueValueInterceptor &); + + QmlDomObject object() const; + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + + +class Q_DECLARATIVE_EXPORT QmlDomComponent : public QmlDomObject +{ +public: + QmlDomComponent(); + QmlDomComponent(const QmlDomComponent &); + ~QmlDomComponent(); + QmlDomComponent &operator=(const QmlDomComponent &); + + QmlDomObject componentRoot() const; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValue +{ +public: + enum Type { + Invalid, + Literal, + PropertyBinding, + ValueSource, + ValueInterceptor, + Object, + List + }; + + QmlDomValue(); + QmlDomValue(const QmlDomValue &); + ~QmlDomValue(); + QmlDomValue &operator=(const QmlDomValue &); + + Type type() const; + + bool isInvalid() const; + bool isLiteral() const; + bool isBinding() const; + bool isValueSource() const; + bool isValueInterceptor() const; + bool isObject() const; + bool isList() const; + + QmlDomValueLiteral toLiteral() const; + QmlDomValueBinding toBinding() const; + QmlDomValueValueSource toValueSource() const; + QmlDomValueValueInterceptor toValueInterceptor() const; + QmlDomObject toObject() const; + QmlDomList toList() const; + + int position() const; + int length() const; + +private: + friend class QmlDomProperty; + friend class QmlDomList; + QSharedDataPointer<QmlDomValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomList +{ +public: + QmlDomList(); + QmlDomList(const QmlDomList &); + ~QmlDomList(); + QmlDomList &operator=(const QmlDomList &); + + QList<QmlDomValue> values() const; + + int position() const; + int length() const; + + QList<int> commaPositions() const; + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomValuePrivate> d; +}; + +class QmlDomImportPrivate; +class Q_DECLARATIVE_EXPORT QmlDomImport +{ +public: + enum Type { Library, File }; + + QmlDomImport(); + QmlDomImport(const QmlDomImport &); + ~QmlDomImport(); + QmlDomImport &operator=(const QmlDomImport &); + + Type type() const; + QString uri() const; + QString version() const; + QString qualifier() const; + +private: + friend class QmlDomDocument; + QSharedDataPointer<QmlDomImportPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLDOM_H diff --git a/src/declarative/qml/qmldom_p.h b/src/declarative/qml/qmldom_p.h new file mode 100644 index 0000000..df6a980 --- /dev/null +++ b/src/declarative/qml/qmldom_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDOM_P_H +#define QMLDOM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlparser_p.h" + +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE + +class QmlDomDocumentPrivate : public QSharedData +{ +public: + QmlDomDocumentPrivate(); + QmlDomDocumentPrivate(const QmlDomDocumentPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomDocumentPrivate(); + + QList<QmlError> errors; + QList<QmlDomImport> imports; + QmlParser::Object *root; + QList<int> automaticSemicolonOffsets; +}; + +class QmlDomObjectPrivate : public QSharedData +{ +public: + QmlDomObjectPrivate(); + QmlDomObjectPrivate(const QmlDomObjectPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomObjectPrivate(); + + typedef QList<QPair<QmlParser::Property *, QByteArray> > Properties; + Properties properties() const; + Properties properties(QmlParser::Property *) const; + + QmlParser::Object *object; +}; + +class QmlDomPropertyPrivate : public QSharedData +{ +public: + QmlDomPropertyPrivate(); + QmlDomPropertyPrivate(const QmlDomPropertyPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomPropertyPrivate(); + + QByteArray propertyName; + QmlParser::Property *property; +}; + +class QmlDomDynamicPropertyPrivate : public QSharedData +{ +public: + QmlDomDynamicPropertyPrivate(); + QmlDomDynamicPropertyPrivate(const QmlDomDynamicPropertyPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomDynamicPropertyPrivate(); + + bool valid; + QmlParser::Object::DynamicProperty property; +}; + +class QmlDomValuePrivate : public QSharedData +{ +public: + QmlDomValuePrivate(); + QmlDomValuePrivate(const QmlDomValuePrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomValuePrivate(); + + QmlParser::Property *property; + QmlParser::Value *value; +}; + +class QmlDomBasicValuePrivate : public QSharedData +{ +public: + QmlDomBasicValuePrivate(); + QmlDomBasicValuePrivate(const QmlDomBasicValuePrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomBasicValuePrivate(); + + QmlParser::Value *value; +}; + +class QmlDomImportPrivate : public QSharedData +{ +public: + QmlDomImportPrivate(); + QmlDomImportPrivate(const QmlDomImportPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QmlDomImportPrivate(); + + enum Type { Library, File }; + + Type type; + QString uri; + QString version; + QString qualifier; +}; + +QT_END_NAMESPACE + +#endif // QMLDOM_P_H + diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp new file mode 100644 index 0000000..372821e --- /dev/null +++ b/src/declarative/qml/qmlengine.cpp @@ -0,0 +1,1645 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlengine_p.h" +#include "qmlengine.h" + +#include "qmlcontext_p.h" +#include "qmlcompiler_p.h" +#include "qmlglobalscriptclass_p.h" +#include "qml.h" +#include "qmlcontext.h" +#include "qmlexpression.h" +#include "qmlcomponent.h" +#include "qmlmetaproperty_p.h" +#include "qmlmoduleplugin.h" +#include "qmlbinding_p.h" +#include "qmlvme_p.h" +#include "qmlenginedebug_p.h" +#include "qmlstringconverters_p.h" +#include "qmlxmlhttprequest_p.h" +#include "qmlsqldatabase_p.h" +#include "qmltypenamescriptclass_p.h" +#include "qmllistscriptclass_p.h" +#include "qmlscriptstring.h" +#include "qmlglobal_p.h" +#include "qmlworkerscript_p.h" +#include "qmlcomponent_p.h" +#include "qmlscriptclass_p.h" +#include "qmlnetworkaccessmanagerfactory.h" + +#include <qfxperf_p_p.h> + +#include <QtCore/qmetaobject.h> +#include <QScriptClass> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QNetworkAccessManager> +#include <QDesktopServices> +#include <QTimer> +#include <QList> +#include <QPair> +#include <QDebug> +#include <QMetaObject> +#include <QStack> +#include <QtCore/qlibraryinfo.h> +#include <QtCore/qthreadstorage.h> +#include <QtCore/qthread.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtGui/qcolor.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qsound.h> +#include <QGraphicsObject> +#include <QtCore/qcryptographichash.h> + +#include <private/qfactoryloader_p.h> +#include <private/qobject_p.h> +#include <private/qscriptdeclarativeclass_p.h> + +#ifdef Q_OS_WIN // for %APPDATA% +#include <qt_windows.h> +#include <qlibrary.h> + +#define CSIDL_APPDATA 0x001a // <username>\Application Data +#endif + +Q_DECLARE_METATYPE(QmlMetaProperty) +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) + +QML_DEFINE_TYPE(Qt,4,6,QtObject,QObject) +/*! + \qmlclass QtObject QObject + \brief The QtObject element is the most basic element in QML + + The QtObject element is a non-visual element which contains only + the objectName property. It is useful for when you need an extremely + lightweight element to place your own custom properties in. + + It can also be useful for C++ integration, as it is just a plain QObject. See + the QObject documentation for further details. +*/ +/*! + \qmlproperty string QtObject::objectName + This property allows you to give a name to this specific object instance. + + See \l{scripting.html#accessing-child-qobjects}{Accessing Child QObjects} + in the scripting documentation for details how objectName can be used from + scripts. +*/ + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + +QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) +: captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false), + contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), + globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0), + scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), inBeginCreate(false), + networkAccessManager(0), networkAccessManagerFactory(0), + typeManager(e), uniqueId(1) +{ + globalClass = new QmlGlobalScriptClass(&scriptEngine); + fileImportPath.append(QLibraryInfo::location(QLibraryInfo::DataPath)+QDir::separator()+QLatin1String("qml")); +} + +QUrl QmlScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url) +{ + if (p) { + QmlContext *ctxt = QmlEnginePrivate::get(this)->getContext(context); + Q_ASSERT(ctxt); + return ctxt->resolvedUrl(url); + } + return baseUrl.resolved(url); +} + +QmlScriptEngine::QmlScriptEngine(QmlEnginePrivate *priv) +: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0) +{ + // Note that all documentation for stuff put on the global object goes in + // doc/src/declarative/globalobject.qdoc + + bool mainthread = priv != 0; + + QScriptValue qtObject = + newQMetaObject(StaticQtMetaObject::get()); + globalObject().setProperty(QLatin1String("Qt"), qtObject); + + offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator()) + + QDir::separator() + QLatin1String("QML") + + QDir::separator() + QLatin1String("OfflineStorage"); + + + qt_add_qmlxmlhttprequest(this); + qt_add_qmlsqldatabase(this); + // XXX A Multimedia "Qt.Sound" class also needs to be made available, + // XXX but we don't want a dependency in that cirection. + // XXX When the above a done some better way, that way should also be + // XXX used to add Qt.Sound class. + + + //types + qtObject.setProperty(QLatin1String("rgba"), newFunction(QmlEnginePrivate::rgba, 4)); + qtObject.setProperty(QLatin1String("hsla"), newFunction(QmlEnginePrivate::hsla, 4)); + qtObject.setProperty(QLatin1String("rect"), newFunction(QmlEnginePrivate::rect, 4)); + qtObject.setProperty(QLatin1String("point"), newFunction(QmlEnginePrivate::point, 2)); + qtObject.setProperty(QLatin1String("size"), newFunction(QmlEnginePrivate::size, 2)); + qtObject.setProperty(QLatin1String("vector3d"), newFunction(QmlEnginePrivate::vector, 3)); + + if (mainthread) { + //color helpers + qtObject.setProperty(QLatin1String("lighter"), newFunction(QmlEnginePrivate::lighter, 1)); + qtObject.setProperty(QLatin1String("darker"), newFunction(QmlEnginePrivate::darker, 1)); + qtObject.setProperty(QLatin1String("tint"), newFunction(QmlEnginePrivate::tint, 2)); + } + + //misc methods + qtObject.setProperty(QLatin1String("closestAngle"), newFunction(QmlEnginePrivate::closestAngle, 2)); + qtObject.setProperty(QLatin1String("playSound"), newFunction(QmlEnginePrivate::playSound, 1)); + qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QmlEnginePrivate::desktopOpenUrl, 1)); + qtObject.setProperty(QLatin1String("md5"),newFunction(QmlEnginePrivate::md5, 1)); + qtObject.setProperty(QLatin1String("btoa"),newFunction(QmlEnginePrivate::btoa, 1)); + qtObject.setProperty(QLatin1String("atob"),newFunction(QmlEnginePrivate::atob, 1)); + qtObject.setProperty(QLatin1String("quit"), newFunction(QmlEnginePrivate::quit, 0)); + qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QmlScriptEngine::resolvedUrl, 1)); + + //firebug/webkit compat + QScriptValue consoleObject = newObject(); + consoleObject.setProperty(QLatin1String("log"),newFunction(QmlEnginePrivate::consoleLog, 1)); + consoleObject.setProperty(QLatin1String("debug"),newFunction(QmlEnginePrivate::consoleLog, 1)); + globalObject().setProperty(QLatin1String("console"), consoleObject); + + if (mainthread) { + globalObject().setProperty(QLatin1String("createQmlObject"), + newFunction(QmlEnginePrivate::createQmlObject, 1)); + globalObject().setProperty(QLatin1String("createComponent"), + newFunction(QmlEnginePrivate::createComponent, 1)); + } + + // translation functions need to be installed + // before the global script class is constructed (QTBUG-6437) + installTranslatorFunctions(); +} + +QmlScriptEngine::~QmlScriptEngine() +{ + delete sqlQueryClass; + delete nodeListClass; + delete namedNodeMapClass; +} + +QScriptValue QmlScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine) +{ + QString arg = ctxt->argument(0).toString(); + QUrl r = QmlScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg)); + return QScriptValue(r.toString()); +} + +QNetworkAccessManager *QmlScriptEngine::networkAccessManager() +{ + return p->getNetworkAccessManager(); +} + +QmlEnginePrivate::~QmlEnginePrivate() +{ + while (cleanup) { + QmlCleanup *c = cleanup; + cleanup = c->next; + if (cleanup) cleanup->prev = &cleanup; + c->next = 0; + c->prev = 0; + c->clear(); + } + + delete rootContext; + rootContext = 0; + delete contextClass; + contextClass = 0; + delete objectClass; + objectClass = 0; + delete valueTypeClass; + valueTypeClass = 0; + delete typeNameClass; + typeNameClass = 0; + delete listClass; + listClass = 0; + delete globalClass; + globalClass = 0; + + for(int ii = 0; ii < bindValues.count(); ++ii) + clear(bindValues[ii]); + for(int ii = 0; ii < parserStatus.count(); ++ii) + clear(parserStatus[ii]); + for(QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) + (*iter)->release(); + for(QHash<const QMetaObject *, QmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + +} + +void QmlEnginePrivate::clear(SimpleList<QmlAbstractBinding> &bvs) +{ + bvs.clear(); +} + +void QmlEnginePrivate::clear(SimpleList<QmlParserStatus> &pss) +{ + for (int ii = 0; ii < pss.count; ++ii) { + QmlParserStatus *ps = pss.at(ii); + if(ps) + ps->d = 0; + } + pss.clear(); +} + +Q_GLOBAL_STATIC(QmlEngineDebugServer, qmlEngineDebugServer); + +void QmlEnginePrivate::init() +{ + Q_Q(QmlEngine); + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QmlScriptString>("QmlScriptString"); + qRegisterMetaType<QScriptValue>("QScriptValue"); + + contextClass = new QmlContextScriptClass(q); + objectClass = new QmlObjectScriptClass(q); + valueTypeClass = new QmlValueTypeScriptClass(q); + typeNameClass = new QmlTypeNameScriptClass(q); + listClass = new QmlListScriptClass(q); + rootContext = new QmlContext(q,true); + + if (QCoreApplication::instance()->thread() == q->thread() && + QmlEngineDebugServer::isDebuggingEnabled()) { + qmlEngineDebugServer(); + isDebugging = true; + QmlEngineDebugServer::addEngine(q); + + qmlEngineDebugServer()->waitForClients(); + } +} + +QmlWorkerScriptEngine *QmlEnginePrivate::getWorkerScriptEngine() +{ + Q_Q(QmlEngine); + if (!workerScriptEngine) + workerScriptEngine = new QmlWorkerScriptEngine(q); + return workerScriptEngine; +} + +/*! + \class QmlEngine + \brief The QmlEngine class provides an environment for instantiating QML components. + \mainclass + + Each QML component is instantiated in a QmlContext. QmlContext's are + essential for passing data to QML components. In QML, contexts are arranged + hierarchically and this hierarchy is managed by the QmlEngine. + + Prior to creating any QML components, an application must have created a + QmlEngine to gain access to a QML context. The following example shows how + to create a simple Text item. + + \code + QmlEngine engine; + QmlComponent component(&engine); + component.setData("import Qt 4.6\nText { text: \"Hello world!\" }", QUrl()); + QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(component.create()); + + //add item to view, etc + ... + \endcode + + In this case, the Text item will be created in the engine's + \l {QmlEngine::rootContext()}{root context}. + + \sa QmlComponent QmlContext +*/ + +/*! + Create a new QmlEngine with the given \a parent. +*/ +QmlEngine::QmlEngine(QObject *parent) +: QObject(*new QmlEnginePrivate(this), parent) +{ + Q_D(QmlEngine); + d->init(); +} + +/*! + Destroys the QmlEngine. + + Any QmlContext's created on this engine will be invalidated, but not + destroyed (unless they are parented to the QmlEngine object). +*/ +QmlEngine::~QmlEngine() +{ + Q_D(QmlEngine); + if (d->isDebugging) + QmlEngineDebugServer::remEngine(this); +} + +/*! + Clears the engine's internal component cache. + + Normally the QmlEngine caches components loaded from qml files. This method + clears this cache and forces the component to be reloaded. + */ +void QmlEngine::clearComponentCache() +{ + Q_D(QmlEngine); + d->typeManager.clearCache(); +} + +/*! + Returns the engine's root context. + + The root context is automatically created by the QmlEngine. Data that + should be available to all QML component instances instantiated by the + engine should be put in the root context. + + Additional data that should only be available to a subset of component + instances should be added to sub-contexts parented to the root context. +*/ +QmlContext *QmlEngine::rootContext() +{ + Q_D(QmlEngine); + return d->rootContext; +} + +/*! + Sets the \a factory to use for creating QNetworkAccessManager(s). + + QNetworkAccessManager is used for all network access by QML. + By implementing a factory it is possible to create custom + QNetworkAccessManager with specialized caching, proxy and + cookie support. + + The factory must be set before exceuting the engine. +*/ +void QmlEngine::setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *factory) +{ + Q_D(QmlEngine); + d->networkAccessManagerFactory = factory; +} + +/*! + Returns the current QmlNetworkAccessManagerFactory. + + \sa setNetworkAccessManagerFactory() +*/ +QmlNetworkAccessManagerFactory *QmlEngine::networkAccessManagerFactory() const +{ + Q_D(const QmlEngine); + return d->networkAccessManagerFactory; +} + +QNetworkAccessManager *QmlEnginePrivate::getNetworkAccessManager() const +{ + Q_Q(const QmlEngine); + + if (!networkAccessManager) { + if (networkAccessManagerFactory) { + networkAccessManager = networkAccessManagerFactory->create(const_cast<QmlEngine*>(q)); + } else { + networkAccessManager = new QNetworkAccessManager(const_cast<QmlEngine*>(q)); + } + } + return networkAccessManager; +} + +/*! + Returns a common QNetworkAccessManager which can be used by any QML element + instantiated by this engine. + + If a QmlNetworkAccessManagerFactory has been set and a QNetworkAccessManager + has not yet been created, the QmlNetworkAccessManagerFactory will be used + to create the QNetworkAccessManager; otherwise the returned QNetworkAccessManager + will have no proxy or cache set. + + \sa setNetworkAccessManagerFactory() +*/ +QNetworkAccessManager *QmlEngine::networkAccessManager() const +{ + Q_D(const QmlEngine); + return d->getNetworkAccessManager(); +} + +/*! + Return the base URL for this engine. The base URL is only used to resolve + components when a relative URL is passed to the QmlComponent constructor. + + If a base URL has not been explicitly set, this method returns the + application's current working directory. + + \sa setBaseUrl() +*/ +QUrl QmlEngine::baseUrl() const +{ + Q_D(const QmlEngine); + if (d->baseUrl.isEmpty()) { + return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator()); + } else { + return d->baseUrl; + } +} + +/*! + Set the base URL for this engine to \a url. + + \sa baseUrl() +*/ +void QmlEngine::setBaseUrl(const QUrl &url) +{ + Q_D(QmlEngine); + d->baseUrl = url; +} + +/*! + Returns the QmlContext for the \a object, or 0 if no context has been set. + + When the QmlEngine instantiates a QObject, the context is set automatically. + */ +QmlContext *QmlEngine::contextForObject(const QObject *object) +{ + if(!object) + return 0; + + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(priv->declarativeData); + + if (!data) + return 0; + else if (data->outerContext) + return data->outerContext; + else + return data->context; +} + +/*! + Sets the QmlContext for the \a object to \a context. + If the \a object already has a context, a warning is + output, but the context is not changed. + + When the QmlEngine instantiates a QObject, the context is set automatically. + */ +void QmlEngine::setContextForObject(QObject *object, QmlContext *context) +{ + if (!object || !context) + return; + + QmlDeclarativeData *data = QmlDeclarativeData::get(object, true); + if (data->context) { + qWarning("QmlEngine::setContextForObject(): Object already has a QmlContext"); + return; + } + + data->context = context; + data->nextContextObject = context->d_func()->contextObjects; + if (data->nextContextObject) + data->nextContextObject->prevContextObject = &data->nextContextObject; + data->prevContextObject = &context->d_func()->contextObjects; + context->d_func()->contextObjects = data; +} + +void qmlExecuteDeferred(QObject *object) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object); + + if (data && data->deferredComponent) { + + QmlEnginePrivate *ep = QmlEnginePrivate::get(data->context->engine()); + + QmlComponentPrivate::ConstructionState state; + QmlComponentPrivate::beginDeferred(data->context, ep, object, &state); + + data->deferredComponent->release(); + data->deferredComponent = 0; + + QmlComponentPrivate::complete(ep, &state); + + if (!state.errors.isEmpty()) + qWarning() << state.errors; + + } +} + +QmlContext *qmlContext(const QObject *obj) +{ + return QmlEngine::contextForObject(obj); +} + +QmlEngine *qmlEngine(const QObject *obj) +{ + QmlContext *context = QmlEngine::contextForObject(obj); + return context?context->engine():0; +} + +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object); + if (!data) + return 0; // Attached properties are only on objects created by QML + + QObject *rv = data->attachedProperties?data->attachedProperties->value(id):0; + if (rv || !create) + return rv; + + QmlAttachedPropertiesFunc pf = QmlMetaType::attachedPropertiesFuncById(id); + if (!pf) + return 0; + + rv = pf(const_cast<QObject *>(object)); + + if (rv) { + if (!data->attachedProperties) + data->attachedProperties = new QHash<int, QObject *>(); + data->attachedProperties->insert(id, rv); + } + + return rv; +} + +void QmlDeclarativeData::destroyed(QObject *object) +{ + if (deferredComponent) + deferredComponent->release(); + if (attachedProperties) + delete attachedProperties; + + if (nextContextObject) + nextContextObject->prevContextObject = prevContextObject; + if (prevContextObject) + *prevContextObject = nextContextObject; + + QmlAbstractBinding *binding = bindings; + while (binding) { + QmlAbstractBinding *next = binding->m_nextBinding; + binding->m_prevBinding = 0; + binding->m_nextBinding = 0; + binding->destroy(); + binding = next; + } + + if (bindingBits) + free(bindingBits); + + if (propertyCache) + propertyCache->release(); + + QmlGuard<QObject> *guard = guards; + while (guard) { + QmlGuard<QObject> *g = guard; + guard = guard->next; + g->o = 0; + g->prev = 0; + g->next = 0; + g->objectDestroyed(object); + } + + delete this; +} + +bool QmlDeclarativeData::hasBindingBit(int bit) const +{ + if (bindingBitsSize > bit) + return bindingBits[bit / 32] & (1 << (bit % 32)); + else + return false; +} + +void QmlDeclarativeData::clearBindingBit(int bit) +{ + if (bindingBitsSize > bit) + bindingBits[bit / 32] &= ~(1 << (bit % 32)); +} + +void QmlDeclarativeData::setBindingBit(QObject *obj, int bit) +{ + if (bindingBitsSize <= bit) { + int props = obj->metaObject()->propertyCount(); + Q_ASSERT(bit < props); + + int arraySize = (props + 31) / 32; + int oldArraySize = bindingBitsSize / 32; + + bindingBits = (quint32 *)realloc(bindingBits, + arraySize * sizeof(quint32)); + + memset(bindingBits + oldArraySize, + 0x00, + sizeof(quint32) * (arraySize - oldArraySize)); + + bindingBitsSize = arraySize * 32; + } + + bindingBits[bit / 32] |= (1 << (bit % 32)); +} + +/*! + Creates a QScriptValue allowing you to use \a object in QML script. + \a engine is the QmlEngine it is to be created in. + + The QScriptValue returned is a QtScript Object, not a QtScript QObject, due + to the special needs of QML requiring more functionality than a standard + QtScript QObject. +*/ +QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, + QmlEngine* engine) +{ + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + return enginePriv->objectClass->newQObject(object); +} + +/*! + Returns the QmlContext for the executing QScript \a ctxt. +*/ +QmlContext *QmlEnginePrivate::getContext(QScriptContext *ctxt) +{ + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); + return contextClass->contextFromValue(scopeNode); +} + +QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, + QScriptEngine *engine) +{ + QmlEnginePrivate *activeEnginePriv = + static_cast<QmlScriptEngine*>(engine)->p; + QmlEngine* activeEngine = activeEnginePriv->q_func(); + + QmlContext* context = activeEnginePriv->getContext(ctxt); + Q_ASSERT(context); + if(ctxt->argumentCount() != 1) { + return engine->nullValue(); + }else{ + QString arg = ctxt->argument(0).toString(); + if (arg.isEmpty()) + return engine->nullValue(); + QUrl url = QUrl(context->resolvedUrl(QUrl(arg))); + QmlComponent *c = new QmlComponent(activeEngine, url, activeEngine); + c->setCreationContext(context); + return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QmlComponent*>()); + } +} + +QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine) +{ + QmlEnginePrivate *activeEnginePriv = + static_cast<QmlScriptEngine*>(engine)->p; + QmlEngine* activeEngine = activeEnginePriv->q_func(); + + if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3) + return engine->nullValue(); + + QmlContext* context = activeEnginePriv->getContext(ctxt); + Q_ASSERT(context); + + QString qml = ctxt->argument(0).toString(); + if (qml.isEmpty()) + return engine->nullValue(); + + QUrl url; + if(ctxt->argumentCount() > 2) + url = QUrl(ctxt->argument(2).toString()); + else + url = QUrl(QLatin1String("inline")); + + if (url.isValid() && url.isRelative()) + url = context->resolvedUrl(url); + + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); + if(!parentArg) + return engine->nullValue(); + + QmlComponent component(activeEngine); + component.setData(qml.toUtf8(), url); + + if(component.isError()) { + QList<QmlError> errors = component.errors(); + qWarning().nospace() << "QmlEngine::createQmlObject():"; + foreach (const QmlError &error, errors) + qWarning().nospace() << " " << error; + + return engine->nullValue(); + } + + if (!component.isReady()) { + qWarning().nospace() << "QmlEngine::createQmlObject(): Component is not ready"; + + return engine->nullValue(); + } + + QObject *obj = component.create(context); + + if(component.isError()) { + QList<QmlError> errors = component.errors(); + qWarning().nospace() << "QmlEngine::createQmlObject():"; + foreach (const QmlError &error, errors) + qWarning().nospace() << " " << error; + + return engine->nullValue(); + } + + Q_ASSERT(obj); + + obj->setParent(parentArg); + QGraphicsObject* gobj = qobject_cast<QGraphicsObject*>(obj); + QGraphicsObject* gparent = qobject_cast<QGraphicsObject*>(parentArg); + if(gobj && gparent) + gobj->setParentItem(gparent); + + return qmlScriptObject(obj, activeEngine); +} + +QScriptValue QmlEnginePrivate::vector(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 3) + return engine->nullValue(); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + qsreal z = ctxt->argument(2).toNumber(); + return engine->newVariant(qVariantFromValue(QVector3D(x, y, z))); +} + +QScriptValue QmlEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3 || argCount > 4) + return engine->nullValue(); + qsreal r = ctxt->argument(0).toNumber(); + qsreal g = ctxt->argument(1).toNumber(); + qsreal b = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + + if (r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1 || a < 0 || a > 1) + return engine->nullValue(); + + return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromRgbF(r, g, b, a))); +} + +QScriptValue QmlEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3 || argCount > 4) + return engine->nullValue(); + qsreal h = ctxt->argument(0).toNumber(); + qsreal s = ctxt->argument(1).toNumber(); + qsreal l = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + + if (h < 0 || h > 1 || s < 0 || s > 1 || l < 0 || l > 1 || a < 0 || a > 1) + return engine->nullValue(); + + return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromHslF(h, s, l, a))); +} + +QScriptValue QmlEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 4) + return engine->nullValue(); + + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + qsreal w = ctxt->argument(2).toNumber(); + qsreal h = ctxt->argument(3).toNumber(); + + if (w < 0 || h < 0) + return engine->nullValue(); + + return qScriptValueFromValue(engine, qVariantFromValue(QRectF(x, y, w, h))); +} + +QScriptValue QmlEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return engine->nullValue(); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + return qScriptValueFromValue(engine, qVariantFromValue(QPointF(x, y))); +} + +QScriptValue QmlEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return engine->nullValue(); + qsreal w = ctxt->argument(0).toNumber(); + qsreal h = ctxt->argument(1).toNumber(); + return qScriptValueFromValue(engine, qVariantFromValue(QSizeF(w, h))); +} + +QScriptValue QmlEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 1) + return engine->nullValue(); + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QmlStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + color = color.lighter(); + return qScriptValueFromValue(engine, qVariantFromValue(color)); +} + +QScriptValue QmlEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 1) + return engine->nullValue(); + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QmlStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + color = color.darker(); + return qScriptValueFromValue(engine, qVariantFromValue(color)); +} + +QScriptValue QmlEnginePrivate::playSound(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() != 1) + return engine->undefinedValue(); + + QUrl url(ctxt->argument(0).toString()); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + if (url.isRelative()) { + QmlContext *context = enginePriv->getContext(ctxt); + if (!context) + return engine->undefinedValue(); + + url = context->resolvedUrl(url); + } + + if (url.scheme() == QLatin1String("file")) { + + QSound::play(url.toLocalFile()); + + } + return engine->undefinedValue(); +} + +QScriptValue QmlEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() < 1) + return e->newVariant(QVariant(false)); + bool ret = QDesktopServices::openUrl(QUrl(ctxt->argument(0).toString())); + return e->newVariant(QVariant(ret)); +} + +QScriptValue QmlEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *) +{ + QByteArray data; + + if (ctxt->argumentCount() >= 1) + data = ctxt->argument(0).toString().toUtf8(); + + QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5); + + return QScriptValue(QLatin1String(result.toHex())); +} + +QScriptValue QmlEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *) +{ + QByteArray data; + + if (ctxt->argumentCount() >= 1) + data = ctxt->argument(0).toString().toUtf8(); + + return QScriptValue(QLatin1String(data.toBase64())); +} + +QScriptValue QmlEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *) +{ + QByteArray data; + + if (ctxt->argumentCount() >= 1) + data = ctxt->argument(0).toString().toUtf8(); + + return QScriptValue(QLatin1String(QByteArray::fromBase64(data))); +} + +QScriptValue QmlEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() < 1) + return e->newVariant(QVariant(false)); + + QByteArray msg; + + for (int i=0; i<ctxt->argumentCount(); ++i) { + if (!msg.isEmpty()) msg += ' '; + msg += ctxt->argument(i).toString().toLocal8Bit(); + // does not support firebug "%[a-z]" formatting, since firebug really + // does just ignore the format letter, which makes it pointless. + } + + qDebug("%s",msg.constData()); + + return e->newVariant(QVariant(true)); +} + +void QmlEnginePrivate::sendQuit () +{ + Q_Q(QmlEngine); + emit q->quit (); +} + +QScriptValue QmlEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e) +{ + QmlEnginePrivate *qe = get (e); + qe->sendQuit (); + return QScriptValue(); +} + +QScriptValue QmlEnginePrivate::closestAngle(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() < 2) + return e->newVariant(QVariant(0.0)); + qreal a = ctxt->argument(0).toNumber(); + qreal b = ctxt->argument(1).toNumber(); + qreal ret = b; + qreal diff = b-a; + while(diff > 180.0){ + ret -= 360.0; + diff -= 360.0; + } + while(diff < -180.0){ + ret += 360.0; + diff += 360.0; + } + return e->newVariant(QVariant(ret)); +} + +QScriptValue QmlEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return engine->nullValue(); + //get color + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QmlStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + + //get tint color + v = ctxt->argument(1).toVariant(); + QColor tintColor; + if (v.userType() == QVariant::Color) + tintColor = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + tintColor = QmlStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + + //tint + QColor finalColor; + int a = tintColor.alpha(); + if (a == 0xFF) + finalColor = tintColor; + else if (a == 0x00) + finalColor = color; + else { + uint src = tintColor.rgba(); + uint dest = color.rgba(); + + uint res = (((a * (src & 0xFF00FF)) + + ((0xFF - a) * (dest & 0xFF00FF))) >> 8) & 0xFF00FF; + res |= (((a * ((src >> 8) & 0xFF00FF)) + + ((0xFF - a) * ((dest >> 8) & 0xFF00FF)))) & 0xFF00FF00; + if ((src & 0xFF000000) == 0xFF000000) + res |= 0xFF000000; + + finalColor = QColor::fromRgba(res); + } + + return qScriptValueFromValue(engine, qVariantFromValue(finalColor)); +} + + +QScriptValue QmlEnginePrivate::scriptValueFromVariant(const QVariant &val) +{ + if (QmlMetaType::isObject(val.userType())) { + QObject *rv = *(QObject **)val.constData(); + return objectClass->newQObject(rv); + } else { + return qScriptValueFromValue(&scriptEngine, val); + } +} + +QVariant QmlEnginePrivate::scriptValueToVariant(const QScriptValue &val) +{ + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == objectClass) + return QVariant::fromValue(objectClass->toQObject(val)); + else if (dc == contextClass) + return QVariant(); + + QScriptDeclarativeClass *sc = QScriptDeclarativeClass::scriptClass(val); + if (!sc) { + return val.toVariant(); + } else if (sc == valueTypeClass) { + return valueTypeClass->toVariant(val); + } else { + return QVariant(); + } +} + +QmlScriptClass::QmlScriptClass(QScriptEngine *engine) +: QScriptDeclarativeClass(engine) +{ +} + +QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) +{ + QmlEnginePrivate *ep = + static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine)); + + return ep->scriptValueToVariant(val); +} + +// XXX this beyonds in QUrl::toLocalFile() +static QString toLocalFileOrQrc(const QUrl& url) +{ + QString r = url.toLocalFile(); + if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) + r = QLatin1Char(':') + url.path(); + return r; +} + +///////////////////////////////////////////////////////////// +struct QmlEnginePrivate::ImportedNamespace { + QStringList uris; + QStringList urls; + QList<int> majversions; + QList<int> minversions; + QList<bool> isLibrary; + QList<bool> isBuiltin; // Types provided by C++ code (including plugins) + QList<QString> qmlDirContent; + + bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) const + { + for (int i=0; i<urls.count(); ++i) { + int vmaj = majversions.at(i); + int vmin = minversions.at(i); + + if (isBuiltin.at(i)) { + QByteArray qt = uris.at(i).toUtf8(); + qt += '/'; + qt += type; + if (qmlImportTrace()) + qDebug() << "Look in" << qt; + QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin); + if (vmajor) *vmajor = vmaj; + if (vminor) *vminor = vmin; + if (t) { + if (qmlImportTrace()) + qDebug() << "Found" << qt; + if (type_return) + *type_return = t; + return true; + } + } + QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); + QString qmldircontent = qmlDirContent.at(i); + if (vmaj>=0 || !qmldircontent.isEmpty()) { + // Check version file - XXX cache these in QmlEngine! + if (qmldircontent.isEmpty()) { + QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); + if (qmldir.open(QIODevice::ReadOnly)) { + qmldircontent = QString::fromUtf8(qmldir.readAll()); + } + } + QString typespace = QString::fromUtf8(type)+QLatin1Char(' '); + QStringList lines = qmldircontent.split(QLatin1Char('\n')); + foreach (QString line, lines) { + if (line.isEmpty() || line.at(0) == QLatin1Char('#')) + continue; + if (line.startsWith(typespace)) { + int space1 = line.indexOf(QLatin1Char(' ')); + int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; + QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-1:space2-space1-1); + int dot = mapversions.indexOf(QLatin1Char('.')); + int mapvmaj = mapversions.left(dot).toInt(); + if (mapvmaj<=vmaj) { + if (mapvmaj<vmaj || vmin >= mapversions.mid(dot+1).toInt()) { + QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-1); + if (url_return) + *url_return = url.resolved(QUrl(mapfile.toString())); + return true; + } + } + } + } + } else { + // XXX search non-files too! (eg. zip files, see QT-524) + QFileInfo f(toLocalFileOrQrc(url)); + if (f.exists()) { + if (url_return) + *url_return = url; + return true; + } + } + } + return false; + } +}; + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QmlModuleFactoryInterface_iid, QLatin1String("/qmlmodules"))) + +class QmlImportsPrivate { +public: + QmlImportsPrivate() : ref(1) + { + } + + ~QmlImportsPrivate() + { + foreach (QmlEnginePrivate::ImportedNamespace* s, set.values()) + delete s; + } + + bool add(const QUrl& base, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType, const QStringList& importPath) + { + QmlEnginePrivate::ImportedNamespace *s; + if (prefix.isEmpty()) { + s = &unqualifiedset; + } else { + s = set.value(prefix); + if (!s) + set.insert(prefix,(s=new QmlEnginePrivate::ImportedNamespace)); + } + QString url = uri; + bool isbuiltin = false; + if (importType == QmlScriptParser::Import::Library) { + url.replace(QLatin1Char('.'),QLatin1Char('/')); + bool found = false; + foreach (QString p, importPath) { + QString dir = p+QLatin1Char('/')+url; + QFileInfo fi(dir+QLatin1String("/qmldir")); + if (fi.isFile()) { + url = QUrl::fromLocalFile(fi.absolutePath()).toString(); + found = true; + break; + } + } + if (!found) { + // XXX assume it is a built-in type qualifier + isbuiltin = true; + } + QFactoryLoader *l = loader(); + QmlModuleFactoryInterface *factory = + qobject_cast<QmlModuleFactoryInterface*>(l->instance(uri)); + if (factory) { + factory->defineModuleOnce(uri); + isbuiltin = true; + } + } else { + url = base.resolved(QUrl(url)).toString(); + } + s->uris.prepend(uri); + s->urls.prepend(url); + s->majversions.prepend(vmaj); + s->minversions.prepend(vmin); + s->isLibrary.prepend(importType == QmlScriptParser::Import::Library); + s->isBuiltin.prepend(isbuiltin); + s->qmlDirContent.prepend(qmldircontent); + return true; + } + + bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) + { + QmlEnginePrivate::ImportedNamespace *s = 0; + int slash = type.indexOf('/'); + if (slash >= 0) { + s = set.value(QString::fromUtf8(type.left(slash))); + if (!s) + return false; // qualifier must be a namespace + int nslash = type.indexOf('/',slash+1); + if (nslash > 0) + return false; // only single qualification allowed + } else { + s = &unqualifiedset; + } + QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower) + if (s) { + if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return)) + return true; + if (s->urls.count() == 1 && !s->isBuiltin[0] && !s->isLibrary[0] && url_return) { + *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml"))); + return true; + } + } + if (url_return) { + *url_return = base.resolved(QUrl(QString::fromUtf8(type + ".qml"))); + return true; + } else { + return false; + } + } + + QmlEnginePrivate::ImportedNamespace *findNamespace(const QString& type) + { + return set.value(type); + } + + QUrl base; + int ref; + +private: + friend struct QmlEnginePrivate::Imports; + QmlEnginePrivate::ImportedNamespace unqualifiedset; + QHash<QString,QmlEnginePrivate::ImportedNamespace* > set; +}; + +QmlEnginePrivate::Imports::Imports(const Imports ©) : + d(copy.d) +{ + ++d->ref; +} + +QmlEnginePrivate::Imports &QmlEnginePrivate::Imports::operator =(const Imports ©) +{ + ++copy.d->ref; + if (--d->ref == 0) + delete d; + d = copy.d; + return *this; +} + +QmlEnginePrivate::Imports::Imports() : + d(new QmlImportsPrivate) +{ +} + +QmlEnginePrivate::Imports::~Imports() +{ + if (--d->ref == 0) + delete d; +} + +#include "qmlmetatype.h" +#include "qmltypenamecache_p.h" + +static QmlTypeNameCache *cacheForNamespace(QmlEngine *engine, const QmlEnginePrivate::ImportedNamespace &set, QmlTypeNameCache *cache) +{ + if (!cache) + cache = new QmlTypeNameCache(engine); + + QList<QmlType *> types = QmlMetaType::qmlTypes(); + + for (int ii = 0; ii < set.uris.count(); ++ii) { + if (!set.isBuiltin.at(ii)) + continue; + + QByteArray base = set.uris.at(ii).toUtf8() + '/'; + int major = set.majversions.at(ii); + int minor = set.minversions.at(ii); + + foreach (QmlType *type, types) { + if (type->qmlTypeName().startsWith(base) && + type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) && + type->availableInVersion(major,minor)) + { + QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length())); + + cache->add(name, type); + } + } + } + + return cache; +} + +QmlTypeNameCache *QmlEnginePrivate::Imports::cache(QmlEngine *engine) const +{ + const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset; + + QmlTypeNameCache *cache = new QmlTypeNameCache(engine); + + for (QHash<QString,QmlEnginePrivate::ImportedNamespace* >::ConstIterator iter = d->set.begin(); + iter != d->set.end(); ++iter) { + + QmlTypeNameCache::Data *d = cache->data(iter.key()); + if (d) { + if (!d->typeNamespace) + cacheForNamespace(engine, *(*iter), d->typeNamespace); + } else { + QmlTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0); + cache->add(iter.key(), nc); + nc->release(); + } + } + + cacheForNamespace(engine, set, cache); + + return cache; +} + +/* +QStringList QmlEnginePrivate::Imports::unqualifiedSet() const +{ + QStringList rv; + + const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset; + + for (int ii = 0; ii < set.urls.count(); ++ii) { + if (set.isBuiltin.at(ii)) + rv << set.urls.at(ii); + } + + return rv; +} +*/ + +/*! + Sets the base URL to be used for all relative file imports added. +*/ +void QmlEnginePrivate::Imports::setBaseUrl(const QUrl& url) +{ + d->base = url; +} + +/*! + Returns the base URL to be used for all relative file imports added. +*/ +QUrl QmlEnginePrivate::Imports::baseUrl() const +{ + return d->base; +} + +/*! + Adds \a path as a directory where installed QML components are + defined in a URL-based directory structure. + + For example, if you add \c /opt/MyApp/lib/qml and then load QML + that imports \c com.mycompany.Feature, then QmlEngine will look + in \c /opt/MyApp/lib/qml/com/mycompany/Feature/ for the components + provided by that module (and in the case of versioned imports, + for the \c qmldir file definiting the type version mapping. + + By default, only the "qml" subdirectory of QLibraryInfo::location(QLibraryInfo::DataPath) + is included on the import path. +*/ +void QmlEngine::addImportPath(const QString& path) +{ + if (qmlImportTrace()) + qDebug() << "QmlEngine::addImportPath" << path; + Q_D(QmlEngine); + d->fileImportPath.prepend(path); +} + +/*! + \property QmlEngine::offlineStoragePath + \brief the directory for storing offline user data + + Returns the directory where SQL and other offline + storage is placed. + + QmlGraphicsWebView and the SQL databases created with openDatabase() + are stored here. + + The default is QML/OfflineStorage in the platform-standard + user application data directory. + + Note that the path may not currently exist on the filesystem, so + callers wanting to \e create new files at this location should create + it first - see QDir::mkpath(). +*/ +void QmlEngine::setOfflineStoragePath(const QString& dir) +{ + Q_D(QmlEngine); + d->scriptEngine.offlineStoragePath = dir; +} + +QString QmlEngine::offlineStoragePath() const +{ + Q_D(const QmlEngine); + return d->scriptEngine.offlineStoragePath; +} + + +/*! + \internal + + Adds information to \a imports such that subsequent calls to resolveType() + will resolve types qualified by \a prefix by considering types found at the given \a uri. + + The uri is either a directory (if importType is FileImport), or a URI resolved using paths + added via addImportPath() (if importType is LibraryImport). + + The \a prefix may be empty, in which case the import location is considered for + unqualified types. + + The base URL must already have been set with Import::setBaseUrl(). +*/ +bool QmlEnginePrivate::addToImport(Imports* imports, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const +{ + bool ok = imports->d->add(imports->d->base,qmldircontent,uri,prefix,vmaj,vmin,importType,fileImportPath); + if (qmlImportTrace()) + qDebug() << "QmlEngine::addToImport(" << imports << uri << prefix << vmaj << '.' << vmin << (importType==QmlScriptParser::Import::Library? "Library" : "File") << ": " << ok; + return ok; +} + +/*! + \internal + + Using the given \a imports, the given (namespace qualified) \a type is resolved to either + an ImportedNamespace stored at \a ns_return, + a QmlType stored at \a type_return, or + a component located at \a url_return. + + If any return pointer is 0, the corresponding search is not done. + + \sa addToImport() +*/ +bool QmlEnginePrivate::resolveType(const Imports& imports, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin, ImportedNamespace** ns_return) const +{ + ImportedNamespace* ns = imports.d->findNamespace(QString::fromUtf8(type)); + if (ns) { + if (qmlImportTrace()) + qDebug() << "QmlEngine::resolveType" << type << "is namespace for" << ns->urls; + if (ns_return) + *ns_return = ns; + return true; + } + if (type_return || url_return) { + if (imports.d->find(type,vmaj,vmin,type_return,url_return)) { + if (qmlImportTrace()) { + if (type_return && *type_return) + qDebug() << "QmlEngine::resolveType" << type << '=' << (*type_return)->typeName(); + if (url_return) + qDebug() << "QmlEngine::resolveType" << type << '=' << *url_return; + } + return true; + } + if (qmlImportTrace()) + qDebug() << "QmlEngine::resolveType" << type << "not found"; + } + return false; +} + +/*! + \internal + + Searching \e only in the namespace \a ns (previously returned in a call to + resolveType(), \a type is found and returned to either + a QmlType stored at \a type_return, or + a component located at \a url_return. + + If either return pointer is 0, the corresponding search is not done. +*/ +void QmlEnginePrivate::resolveTypeInNamespace(ImportedNamespace* ns, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin ) const +{ + ns->find(type,vmaj,vmin,type_return,url_return); +} + +static void voidptr_destructor(void *v) +{ + void **ptr = (void **)v; + delete ptr; +} + +static void *voidptr_constructor(const void *v) +{ + if (!v) { + return new void*; + } else { + return new void*(*(void **)v); + } +} + +void QmlEnginePrivate::registerCompositeType(QmlCompiledData *data) +{ + QByteArray name = data->root->className(); + + QByteArray ptr = name + '*'; + QByteArray lst = "QmlList<" + ptr + ">*"; + + int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor, + voidptr_constructor); + int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor, + voidptr_constructor); + + m_qmlLists.insert(lst_type, ptr_type); + m_compositeTypes.insert(ptr_type, data); + data->addref(); +} + +bool QmlEnginePrivate::isQmlList(int t) const +{ + return m_qmlLists.contains(t) || QmlMetaType::isQmlList(t); +} + +bool QmlEnginePrivate::isObject(int t) +{ + return m_compositeTypes.contains(t) || QmlMetaType::isObject(t); +} + +int QmlEnginePrivate::qmlListType(int t) const +{ + QHash<int, int>::ConstIterator iter = m_qmlLists.find(t); + if (iter != m_qmlLists.end()) + return *iter; + else + return QmlMetaType::qmlListType(t); +} + +QmlMetaType::TypeCategory QmlEnginePrivate::typeCategory(int t) const +{ + if (m_compositeTypes.contains(t)) + return QmlMetaType::Object; + else if (m_qmlLists.contains(t)) + return QmlMetaType::QmlList; + else + return QmlMetaType::typeCategory(t); +} + +const QMetaObject *QmlEnginePrivate::rawMetaObjectForType(int t) const +{ + QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + return QmlMetaType::rawMetaObjectForType(t); + } +} + +const QMetaObject *QmlEnginePrivate::metaObjectForType(int t) const +{ + QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + return QmlMetaType::metaObjectForType(t); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h new file mode 100644 index 0000000..7ee014a --- /dev/null +++ b/src/declarative/qml/qmlengine.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLENGINE_H +#define QMLENGINE_H + +#include <QtCore/qurl.h> +#include <QtCore/qobject.h> +#include <QtCore/qmap.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlComponent; +class QmlEnginePrivate; +class QmlImportsPrivate; +class QmlExpression; +class QmlContext; +class QmlType; +class QUrl; +class QScriptEngine; +class QScriptContext; +class QNetworkAccessManager; +class QmlNetworkAccessManagerFactory; +class Q_DECLARATIVE_EXPORT QmlEngine : public QObject +{ + Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) + Q_OBJECT +public: + QmlEngine(QObject *p = 0); + virtual ~QmlEngine(); + + QmlContext *rootContext(); + + void clearComponentCache(); + + void addImportPath(const QString& dir); + + void setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *); + QmlNetworkAccessManagerFactory *networkAccessManagerFactory() const; + + QNetworkAccessManager *networkAccessManager() const; + + void setOfflineStoragePath(const QString& dir); + QString offlineStoragePath() const; + + QUrl baseUrl() const; + void setBaseUrl(const QUrl &); + + static QmlContext *contextForObject(const QObject *); + static void setContextForObject(QObject *, QmlContext *); + +Q_SIGNALS: + void quit (); + +private: + Q_DECLARE_PRIVATE(QmlEngine) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLENGINE_H diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h new file mode 100644 index 0000000..8349090 --- /dev/null +++ b/src/declarative/qml/qmlengine_p.h @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLENGINE_P_H +#define QMLENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlengine.h" + +#include "qmlclassfactory_p.h" +#include "qmlcompositetypemanager_p.h" +#include "qpodvector_p.h" +#include "qml.h" +#include "qmlvaluetype_p.h" +#include "qmlcontext.h" +#include "qmlexpression.h" +#include "qmlmetaproperty_p.h" +#include "qmlpropertycache_p.h" +#include "qmlobjectscriptclass_p.h" +#include "qmlcontextscriptclass_p.h" +#include "qmlvaluetypescriptclass_p.h" + +#include <QtScript/QScriptClass> +#include <QtScript/QScriptValue> +#include <QtScript/QScriptString> +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qstack.h> +#include <QtScript/qscriptengine.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlEngine; +class QmlContextPrivate; +class QmlExpression; +class QmlContextScriptClass; +class QmlObjectScriptClass; +class QmlTypeNameScriptClass; +class QmlValueTypeScriptClass; +class QScriptEngineDebugger; +class QNetworkReply; +class QNetworkAccessManager; +class QmlNetworkAccessManagerFactory; +class QmlAbstractBinding; +class QScriptDeclarativeClass; +class QmlTypeNameScriptClass; +class QmlTypeNameCache; +class QmlComponentAttached; +class QmlListScriptClass; +class QmlCleanup; +class QmlDelayedError; +class QmlWorkerScriptEngine; +class QmlGlobalScriptClass; + +class QmlScriptEngine : public QScriptEngine +{ +public: + QmlScriptEngine(QmlEnginePrivate *priv); + virtual ~QmlScriptEngine(); + + QUrl resolvedUrl(QScriptContext *context, const QUrl& url); // resolved against p's context, or baseUrl if no p + static QScriptValue resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine); + + static QmlScriptEngine *get(QScriptEngine* e) { return static_cast<QmlScriptEngine*>(e); } + + QmlEnginePrivate *p; + + // User by SQL API + QScriptClass *sqlQueryClass; + QString offlineStoragePath; + + // Used by DOM Core 3 API + QScriptClass *namedNodeMapClass; + QScriptClass *nodeListClass; + + QUrl baseUrl; + + virtual QNetworkAccessManager *networkAccessManager(); +}; + +class Q_AUTOTEST_EXPORT QmlEnginePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlEngine) +public: + QmlEnginePrivate(QmlEngine *); + ~QmlEnginePrivate(); + + void init(); + + struct CapturedProperty { + CapturedProperty(QObject *o, int c, int n) + : object(o), coreIndex(c), notifyIndex(n) {} + + QObject *object; + int coreIndex; + int notifyIndex; + }; + bool captureProperties; + QPODVector<CapturedProperty> capturedProperties; + + QmlContext *rootContext; + QmlExpression *currentExpression; + bool isDebugging; + + struct ImportedNamespace; + QmlContextScriptClass *contextClass; + QmlContext *sharedContext; + QObject *sharedScope; + QmlObjectScriptClass *objectClass; + QmlValueTypeScriptClass *valueTypeClass; + QmlTypeNameScriptClass *typeNameClass; + QmlListScriptClass *listClass; + // Global script class + QmlGlobalScriptClass *globalClass; + + // Registered cleanup handlers + QmlCleanup *cleanup; + + // Bindings that have had errors during startup + QmlDelayedError *erroredBindings; + int inProgressCreations; + + QmlScriptEngine scriptEngine; + + QmlWorkerScriptEngine *getWorkerScriptEngine(); + QmlWorkerScriptEngine *workerScriptEngine; + + QUrl baseUrl; + + template<class T> + struct SimpleList { + SimpleList() + : count(0), values(0) {} + SimpleList(int r) + : count(0), values(new T*[r]) {} + + int count; + T **values; + + void append(T *v) { + values[count++] = v; + } + + T *at(int idx) const { + return values[idx]; + } + + void clear() { + delete [] values; + } + }; + + static void clear(SimpleList<QmlAbstractBinding> &); + static void clear(SimpleList<QmlParserStatus> &); + + QList<SimpleList<QmlAbstractBinding> > bindValues; + QList<SimpleList<QmlParserStatus> > parserStatus; + QmlComponentAttached *componentAttacheds; + + bool inBeginCreate; + + QNetworkAccessManager *getNetworkAccessManager() const; + mutable QNetworkAccessManager *networkAccessManager; + mutable QmlNetworkAccessManagerFactory *networkAccessManagerFactory; + + QmlCompositeTypeManager typeManager; + QStringList fileImportPath; + QString offlineStoragePath; + + mutable quint32 uniqueId; + quint32 getUniqueId() const { + return uniqueId++; + } + + QmlValueTypeFactory valueTypes; + + QHash<const QMetaObject *, QmlPropertyCache *> propertyCache; + QmlPropertyCache *cache(QObject *obj) { + Q_Q(QmlEngine); + if (!obj || QObjectPrivate::get(obj)->metaObject) return 0; + const QMetaObject *mo = obj->metaObject(); + QmlPropertyCache *rv = propertyCache.value(mo); + if (!rv) { + rv = QmlPropertyCache::create(q, mo); + propertyCache.insert(mo, rv); + } + return rv; + } + + // ### This whole class is embarrassing + struct Imports { + Imports(); + ~Imports(); + Imports(const Imports ©); + Imports &operator =(const Imports ©); + + void setBaseUrl(const QUrl& url); + QUrl baseUrl() const; + + QmlTypeNameCache *cache(QmlEngine *) const; + + private: + friend class QmlEnginePrivate; + QmlImportsPrivate *d; + }; + + bool addToImport(Imports*, const QString& qmlDirContent,const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const; + bool resolveType(const Imports&, const QByteArray& type, + QmlType** type_return, QUrl* url_return, + int *version_major, int *version_minor, + ImportedNamespace** ns_return) const; + void resolveTypeInNamespace(ImportedNamespace*, const QByteArray& type, + QmlType** type_return, QUrl* url_return, + int *version_major, int *version_minor ) const; + + + void registerCompositeType(QmlCompiledData *); + bool isQmlList(int) const; + bool isObject(int); + int qmlListType(int) const; + QmlMetaType::TypeCategory typeCategory(int) const; + const QMetaObject *rawMetaObjectForType(int) const; + const QMetaObject *metaObjectForType(int) const; + QHash<int, int> m_qmlLists; + QHash<int, QmlCompiledData *> m_compositeTypes; + + QScriptValue scriptValueFromVariant(const QVariant &); + QVariant scriptValueToVariant(const QScriptValue &); + + void sendQuit (); + + static QScriptValue qmlScriptObject(QObject*, QmlEngine*); + + static QScriptValue createComponent(QScriptContext*, QScriptEngine*); + static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); + static QScriptValue vector(QScriptContext*, QScriptEngine*); + static QScriptValue rgba(QScriptContext*, QScriptEngine*); + static QScriptValue hsla(QScriptContext*, QScriptEngine*); + static QScriptValue point(QScriptContext*, QScriptEngine*); + static QScriptValue size(QScriptContext*, QScriptEngine*); + static QScriptValue rect(QScriptContext*, QScriptEngine*); + + static QScriptValue lighter(QScriptContext*, QScriptEngine*); + static QScriptValue darker(QScriptContext*, QScriptEngine*); + static QScriptValue tint(QScriptContext*, QScriptEngine*); + + static QScriptValue closestAngle(QScriptContext*, QScriptEngine*); + static QScriptValue playSound(QScriptContext*, QScriptEngine*); + static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*); + static QScriptValue md5(QScriptContext*, QScriptEngine*); + static QScriptValue btoa(QScriptContext*, QScriptEngine*); + static QScriptValue atob(QScriptContext*, QScriptEngine*); + static QScriptValue consoleLog(QScriptContext*, QScriptEngine*); + static QScriptValue quit(QScriptContext*, QScriptEngine*); + + static QScriptEngine *getScriptEngine(QmlEngine *e) { return &e->d_func()->scriptEngine; } + static QmlEngine *getEngine(QScriptEngine *e) { return static_cast<QmlScriptEngine*>(e)->p->q_func(); } + static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } + static QmlEnginePrivate *get(QScriptEngine *e) { return static_cast<QmlScriptEngine*>(e)->p; } + static QmlEngine *get(QmlEnginePrivate *p) { return p->q_func(); } + QmlContext *getContext(QScriptContext *); +}; + + +QT_END_NAMESPACE + +#endif // QMLENGINE_P_H diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp new file mode 100644 index 0000000..2abd6e6 --- /dev/null +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlenginedebug_p.h" + +#include "qmlboundsignal_p.h" +#include "qmlengine.h" +#include "qmlmetatype.h" +#include "qmlmetaproperty.h" +#include "qmlbinding.h" +#include "qmlcontext_p.h" +#include "qmlwatcher_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qmetaobject.h> + +QT_BEGIN_NAMESPACE + +QList<QmlEngine *> QmlEngineDebugServer::m_engines; +QmlEngineDebugServer::QmlEngineDebugServer(QObject *parent) +: QmlDebugService(QLatin1String("QmlEngine"), parent), + m_watch(new QmlWatcher(this)) +{ + QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)), + this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant))); +} + +QDataStream &operator<<(QDataStream &ds, + const QmlEngineDebugServer::QmlObjectData &data) +{ + ds << data.url << data.lineNumber << data.columnNumber << data.objectName + << data.objectType << data.objectId << data.contextId; + return ds; +} + +QDataStream &operator>>(QDataStream &ds, + QmlEngineDebugServer::QmlObjectData &data) +{ + ds >> data.url >> data.lineNumber >> data.columnNumber >> data.objectName + >> data.objectType >> data.objectId >> data.contextId; + return ds; +} + +QDataStream &operator<<(QDataStream &ds, + const QmlEngineDebugServer::QmlObjectProperty &data) +{ + ds << (int)data.type << data.name << data.value << data.valueTypeName + << data.binding << data.hasNotifySignal; + return ds; +} + +QDataStream &operator>>(QDataStream &ds, + QmlEngineDebugServer::QmlObjectProperty &data) +{ + int type; + ds >> type >> data.name >> data.value >> data.valueTypeName + >> data.binding >> data.hasNotifySignal; + data.type = (QmlEngineDebugServer::QmlObjectProperty::Type)type; + return ds; +} + +QmlEngineDebugServer::QmlObjectProperty +QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) +{ + QmlObjectProperty rv; + + QMetaProperty prop = obj->metaObject()->property(propIdx); + + rv.type = QmlObjectProperty::Unknown; + rv.valueTypeName = QString::fromUtf8(prop.typeName()); + rv.name = QString::fromUtf8(prop.name()); + rv.hasNotifySignal = prop.hasNotifySignal(); + QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding(); + if (binding) + rv.binding = binding->expression(); + + QVariant value = prop.read(obj); + rv.value = valueContents(value); + + if (QVariant::Type(prop.userType()) < QVariant::UserType) { + rv.type = QmlObjectProperty::Basic; + } else if (QmlMetaType::isObject(prop.userType())) { + rv.type = QmlObjectProperty::Object; + } else if (QmlMetaType::isList(prop.userType()) || + QmlMetaType::isQmlList(prop.userType())) { + rv.type = QmlObjectProperty::List; + } + + return rv; +} + +QVariant QmlEngineDebugServer::valueContents(const QVariant &value) const +{ + int userType = value.userType(); + if (QVariant::Type(userType) < QVariant::UserType) + return value; + + + if (QmlMetaType::isList(userType) || QmlMetaType::isQmlList(userType)) { + int count = QmlMetaType::listCount(value); + QVariantList contents; + for (int i=0; i<count; i++) + contents << valueContents(QmlMetaType::listAt(value, i)); + return contents; + } else if (QmlMetaType::isObject(userType)) { + QObject *o = QmlMetaType::toQObject(value); + if (o) { + QString name = o->objectName(); + if (name.isEmpty()) + name = QLatin1String("<unnamed object>"); + return name; + } + } + + return QLatin1String("<unknown value>"); +} + +void QmlEngineDebugServer::buildObjectDump(QDataStream &message, + QObject *object, bool recur) +{ + message << objectData(object); + + // Some children aren't added to an object until particular properties are read + // - e.g. child state objects aren't added until the 'states' property is read - + // but this should only affect internal objects that aren't shown by the + // debugger anyway. + + QObjectList children = object->children(); + + int childrenCount = children.count(); + for (int ii = 0; ii < children.count(); ++ii) { + if (qobject_cast<QmlContext*>(children[ii]) || QmlBoundSignal::cast(children[ii])) + --childrenCount; + } + + message << childrenCount << recur; + + QList<QmlObjectProperty> fakeProperties; + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + if (qobject_cast<QmlContext*>(child)) + continue; + QmlBoundSignal *signal = QmlBoundSignal::cast(child); + if (signal) { + QmlObjectProperty prop; + prop.type = QmlObjectProperty::SignalProperty; + prop.hasNotifySignal = false; + QmlExpression *expr = signal->expression(); + if (expr) { + prop.value = expr->expression(); + QObject *scope = expr->scopeObject(); + if (scope) { + QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature()); + int lparen = sig.indexOf(QLatin1Char('(')); + if (lparen >= 0) { + QString methodName = sig.mid(0, lparen); + prop.name = QLatin1String("on") + methodName[0].toUpper() + + methodName.mid(1); + } + } + } + fakeProperties << prop; + } else { + if (recur) + buildObjectDump(message, child, recur); + else + message << objectData(child); + } + } + + message << (object->metaObject()->propertyCount() + fakeProperties.count()); + + for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) + message << propertyData(object, ii); + + for (int ii = 0; ii < fakeProperties.count(); ++ii) + message << fakeProperties[ii]; +} + +void QmlEngineDebugServer::buildObjectList(QDataStream &message, + QmlContext *ctxt) +{ + QmlContextPrivate *p = (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + QString ctxtName = ctxt->objectName(); + int ctxtId = QmlDebugService::idForObject(ctxt); + + message << ctxtName << ctxtId; + + int count = 0; + + for (QSet<QmlContext *>::ConstIterator iter = p->childContexts.begin(); + iter != p->childContexts.end(); ++iter) { + QmlContextPrivate *p = (QmlContextPrivate *)QObjectPrivate::get(*iter); + if (p->isInternal) + continue; + ++count; + } + + message << count; + + for (QSet<QmlContext *>::ConstIterator iter = p->childContexts.begin(); + iter != p->childContexts.end(); ++iter) { + QmlContextPrivate *p = (QmlContextPrivate *)QObjectPrivate::get(*iter); + if (p->isInternal) + continue; + buildObjectList(message, *iter); + } + + // Clean deleted objects + for (int ii = 0; ii < p->instances.count(); ++ii) { + if (!p->instances.at(ii)) { + p->instances.removeAt(ii); + --ii; + } + } + + message << p->instances.count(); + for (int ii = 0; ii < p->instances.count(); ++ii) { + message << objectData(p->instances.at(ii)); + } +} + +QmlEngineDebugServer::QmlObjectData +QmlEngineDebugServer::objectData(QObject *object) +{ + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object); + QmlObjectData rv; + if (ddata) { + rv.url = ddata->outerContext->baseUrl(); + rv.lineNumber = ddata->lineNumber; + rv.columnNumber = ddata->columnNumber; + } else { + rv.lineNumber = -1; + rv.columnNumber = -1; + } + + rv.objectName = object->objectName(); + rv.objectId = QmlDebugService::idForObject(object); + rv.contextId = QmlDebugService::idForObject(qmlContext(object)); + + QmlType *type = QmlMetaType::qmlType(object->metaObject()); + if (type) { + QString typeName = QLatin1String(type->qmlTypeName()); + int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); + } else { + rv.objectType = QString::fromUtf8(object->metaObject()->className()); + int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); + if (marker != -1) + rv.objectType = rv.objectType.left(marker); + } + + return rv; +} + +void QmlEngineDebugServer::messageReceived(const QByteArray &message) +{ + QDataStream ds(message); + + QByteArray type; + ds >> type; + + //qDebug() << "QmlEngineDebugServer::messageReceived()" << type; + + if (type == "LIST_ENGINES") { + int queryId; + ds >> queryId; + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("LIST_ENGINES_R"); + rs << queryId << m_engines.count(); + + for (int ii = 0; ii < m_engines.count(); ++ii) { + QmlEngine *engine = m_engines.at(ii); + + QString engineName = engine->objectName(); + int engineId = QmlDebugService::idForObject(engine); + + rs << engineName << engineId; + } + + sendMessage(reply); + } else if (type == "LIST_OBJECTS") { + int queryId; + int engineId = -1; + ds >> queryId >> engineId; + + QmlEngine *engine = + qobject_cast<QmlEngine *>(QmlDebugService::objectForId(engineId)); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("LIST_OBJECTS_R") << queryId; + + if (engine) + buildObjectList(rs, engine->rootContext()); + + sendMessage(reply); + } else if (type == "FETCH_OBJECT") { + int queryId; + int objectId; + bool recurse; + + ds >> queryId >> objectId >> recurse; + + QObject *object = QmlDebugService::objectForId(objectId); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("FETCH_OBJECT_R") << queryId; + + if (object) + buildObjectDump(rs, object, recurse); + + sendMessage(reply); + } else if (type == "WATCH_OBJECT") { + int queryId; + int objectId; + + ds >> queryId >> objectId; + bool ok = m_watch->addWatch(queryId, objectId); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("WATCH_OBJECT_R") << queryId << ok; + + sendMessage(reply); + } else if (type == "WATCH_PROPERTY") { + int queryId; + int objectId; + QByteArray property; + + ds >> queryId >> objectId >> property; + bool ok = m_watch->addWatch(queryId, objectId, property); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok; + + sendMessage(reply); + } else if (type == "WATCH_EXPR_OBJECT") { + int queryId; + int debugId; + QString expr; + + ds >> queryId >> debugId >> expr; + bool ok = m_watch->addWatch(queryId, debugId, expr); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok; + + sendMessage(reply); + } else if (type == "NO_WATCH") { + int queryId; + + ds >> queryId; + m_watch->removeWatch(queryId); + } else if (type == "EVAL_EXPRESSION") { + int queryId; + int objectId; + QString expr; + + ds >> queryId >> objectId >> expr; + + QObject *object = QmlDebugService::objectForId(objectId); + QmlContext *context = qmlContext(object); + QVariant result; + if (object && context) { + QmlExpression *exprObj = new QmlExpression(context, expr, object); + bool undefined = false; + QVariant value = exprObj->value(&undefined); + if (undefined) + result = QLatin1String("<undefined>"); + else + result = valueContents(value); + delete exprObj; + } else { + result = QLatin1String("<unknown context>"); + } + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; + + sendMessage(reply); + } +} + +void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) +{ + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + + rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value); + + sendMessage(reply); +} + +void QmlEngineDebugServer::addEngine(QmlEngine *engine) +{ + Q_ASSERT(engine); + Q_ASSERT(!m_engines.contains(engine)); + + m_engines.append(engine); +} + +void QmlEngineDebugServer::remEngine(QmlEngine *engine) +{ + Q_ASSERT(engine); + Q_ASSERT(m_engines.contains(engine)); + + m_engines.removeAll(engine); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h new file mode 100644 index 0000000..7c48b8b --- /dev/null +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLENGINEDEBUG_P_H +#define QMLENGINEDEBUG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "../debugger/qmldebugservice_p.h" + +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlWatcher; +class QDataStream; + +class QmlEngineDebugServer : public QmlDebugService +{ + Q_OBJECT +public: + QmlEngineDebugServer(QObject * = 0); + + struct QmlObjectData { + QUrl url; + int lineNumber; + int columnNumber; + QString objectName; + QString objectType; + int objectId; + int contextId; + }; + + struct QmlObjectProperty { + enum Type { Unknown, Basic, Object, List, SignalProperty }; + Type type; + QString name; + QVariant value; + QString valueTypeName; + QString binding; + bool hasNotifySignal; + }; + + static void addEngine(QmlEngine *); + static void remEngine(QmlEngine *); + +protected: + virtual void messageReceived(const QByteArray &); + +private Q_SLOTS: + void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); + +private: + void buildObjectList(QDataStream &, QmlContext *); + void buildObjectDump(QDataStream &, QObject *, bool); + QmlObjectData objectData(QObject *); + QmlObjectProperty propertyData(QObject *, int); + QVariant valueContents(const QVariant &defaultValue) const; + + static QList<QmlEngine *> m_engines; + QmlWatcher *m_watch; +}; +Q_DECLARATIVE_EXPORT QDataStream &operator<<(QDataStream &, const QmlEngineDebugServer::QmlObjectData &); +Q_DECLARATIVE_EXPORT QDataStream &operator>>(QDataStream &, QmlEngineDebugServer::QmlObjectData &); +Q_DECLARATIVE_EXPORT QDataStream &operator<<(QDataStream &, const QmlEngineDebugServer::QmlObjectProperty &); +Q_DECLARATIVE_EXPORT QDataStream &operator>>(QDataStream &, QmlEngineDebugServer::QmlObjectProperty &); + +QT_END_NAMESPACE + +#endif // QMLENGINEDEBUG_P_H + diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp new file mode 100644 index 0000000..d9ca20d --- /dev/null +++ b/src/declarative/qml/qmlerror.cpp @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlerror.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QmlError + \brief The QmlError class encapsulates a QML error +*/ +class QmlErrorPrivate +{ +public: + QmlErrorPrivate(); + + QUrl url; + QString description; + int line; + int column; +}; + +QmlErrorPrivate::QmlErrorPrivate() +: line(-1), column(-1) +{ +} + +/*! + Create an empty error object. +*/ +QmlError::QmlError() +: d(0) +{ +} + +/*! + Create a copy of \a other. +*/ +QmlError::QmlError(const QmlError &other) +: d(0) +{ + *this = other; +} + +/*! + Assign \a other to this error object. +*/ +QmlError &QmlError::operator=(const QmlError &other) +{ + if (!other.d) { + delete d; + d = 0; + } else { + if (!d) d = new QmlErrorPrivate; + d->url = other.d->url; + d->description = other.d->description; + d->line = other.d->line; + d->column = other.d->column; + } + return *this; +} + +/*! + \internal +*/ +QmlError::~QmlError() +{ + delete d; d = 0; +} + +/*! + Return true if this error is valid, otherwise false. +*/ +bool QmlError::isValid() const +{ + return d != 0; +} + +/*! + Return the url for the file that caused this error. +*/ +QUrl QmlError::url() const +{ + if (d) return d->url; + else return QUrl(); +} + +/*! + Set the \a url for the file that caused this error. +*/ +void QmlError::setUrl(const QUrl &url) +{ + if (!d) d = new QmlErrorPrivate; + d->url = url; +} + +/*! + Return the error description. +*/ +QString QmlError::description() const +{ + if (d) return d->description; + else return QString(); +} + +/*! + Set the error \a description. +*/ +void QmlError::setDescription(const QString &description) +{ + if (!d) d = new QmlErrorPrivate; + d->description = description; +} + +/*! + Return the error line number. +*/ +int QmlError::line() const +{ + if (d) return d->line; + else return -1; +} + +/*! + Set the error \a line number. +*/ +void QmlError::setLine(int line) +{ + if (!d) d = new QmlErrorPrivate; + d->line = line; +} + +/*! + Return the error column number. +*/ +int QmlError::column() const +{ + if (d) return d->column; + else return -1; +} + +/*! + Set the error \a column number. +*/ +void QmlError::setColumn(int column) +{ + if (!d) d = new QmlErrorPrivate; + d->column = column; +} + +/*! + Return the error as a human readable string. +*/ +QString QmlError::toString() const +{ + QString rv; + rv = url().toString() + QLatin1Char(':') + QString::number(line()); + if(column() != -1) + rv += QLatin1Char(':') + QString::number(column()); + + rv += QLatin1String(": ") + description(); + + return rv; +} + +/*! + \relates QmlError + \fn QDebug operator<<(QDebug debug, const QmlError &error) + + Output a human readable version of \a error to \a debug. +*/ + +QDebug operator<<(QDebug debug, const QmlError &error) +{ + debug << qPrintable(error.toString()); + + QUrl url = error.url(); + + if (error.line() > 0 && url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); + stream.setCodec("UTF-8"); + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + debug << "\n " << qPrintable(line); + + if(error.column() > 0) { + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + debug << "\n " << ind.constData(); + } + } + } + } + return debug; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlerror.h b/src/declarative/qml/qmlerror.h new file mode 100644 index 0000000..c54f932 --- /dev/null +++ b/src/declarative/qml/qmlerror.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLERROR_H +#define QMLERROR_H + +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDebug; +class QmlErrorPrivate; +class Q_DECLARATIVE_EXPORT QmlError +{ +public: + QmlError(); + QmlError(const QmlError &); + QmlError &operator=(const QmlError &); + ~QmlError(); + + bool isValid() const; + + QUrl url() const; + void setUrl(const QUrl &); + QString description() const; + void setDescription(const QString &); + int line() const; + void setLine(int); + int column() const; + void setColumn(int); + + QString toString() const; +private: + QmlErrorPrivate *d; +}; + +QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, const QmlError &error); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLERROR_H diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp new file mode 100644 index 0000000..ff1705b --- /dev/null +++ b/src/declarative/qml/qmlexpression.cpp @@ -0,0 +1,826 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlexpression.h" +#include "qmlexpression_p.h" + +#include "qmlengine_p.h" +#include "qmlcontext_p.h" +#include "qmlrewrite_p.h" +#include "qmlcompiler_p.h" + +#include <QtCore/qdebug.h> +#include <QtScript/qscriptprogram.h> + +#include <private/qscriptdeclarativeclass_p.h> + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +bool QmlDelayedError::addError(QmlEnginePrivate *e) +{ + if (!e || prevError) return false; + + if (e->inProgressCreations == 0) return false; // Not in construction + + prevError = &e->erroredBindings; + nextError = e->erroredBindings; + e->erroredBindings = this; + if (nextError) nextError->prevError = &nextError; + + return true; +} + +QmlExpressionData::QmlExpressionData() +: expressionFunctionValid(false), expressionRewritten(false), me(0), + trackChange(true), isShared(false), line(-1), guardList(0), guardListLength(0) +{ +} + +QmlExpressionData::~QmlExpressionData() +{ + if (guardList) { delete [] guardList; guardList = 0; } +} + +QmlExpressionPrivate::QmlExpressionPrivate() +: data(new QmlExpressionData) +{ + data->q = this; +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpressionData *d) +: data(d) +{ + data->q = this; +} + +QmlExpressionPrivate::~QmlExpressionPrivate() +{ + if (data) { data->q = 0; data->release(); data = 0; } +} + +void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, + QObject *me) +{ + data->expression = expr; + + data->QmlAbstractExpression::setContext(ctxt); + data->me = me; +} + +void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, + QObject *me, const QString &url, int lineNumber) +{ + data->url = url; + data->line = lineNumber; + + quint32 *exprData = (quint32 *)expr; + QmlCompiledData *dd = (QmlCompiledData *)rc; + + data->expressionRewritten = true; + data->expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); + + int progIdx = *(exprData); + bool isShared = progIdx & 0x80000000; + progIdx &= 0x7FFFFFFF; + + QmlEngine *engine = ctxt->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (isShared) { + + if (!dd->cachedClosures.at(progIdx)) { + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + scriptContext->pushScope(ep->contextClass->newSharedContext()); + dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line)); + scriptEngine->popContext(); + } + + data->expressionFunction = *dd->cachedClosures.at(progIdx); + data->isShared = true; + data->expressionFunctionValid = true; + + } else { + +#if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work? + if (!dd->cachedPrograms.at(progIdx)) { + dd->cachedPrograms[progIdx] = + new QScriptProgram(data->expression, data->url, data->line); + } + + data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx)); +#else + data->expressionFunction = evalInObjectScope(ctxt, me, data->expression); +#endif + + data->expressionFunctionValid = true; + } + + data->QmlAbstractExpression::setContext(ctxt); + data->me = me; +} + +QScriptValue QmlExpressionPrivate::evalInObjectScope(QmlContext *context, QObject *object, + const QString &program) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(context->engine()); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + QScriptValue rv = ep->scriptEngine.evaluate(program); + ep->scriptEngine.popContext(); + return rv; +} + +QScriptValue QmlExpressionPrivate::evalInObjectScope(QmlContext *context, QObject *object, + const QScriptProgram &program) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(context->engine()); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + QScriptValue rv = ep->scriptEngine.evaluate(program); + ep->scriptEngine.popContext(); + return rv; +} + +/*! + \class QmlExpression + \brief The QmlExpression class evaluates JavaScript in a QML context. +*/ + +/*! + Create an invalid QmlExpression. + + As the expression will not have an associated QmlContext, this will be a + null expression object and its value will always be an invalid QVariant. + */ +QmlExpression::QmlExpression() +: QObject(*new QmlExpressionPrivate, 0) +{ +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, + QmlRefCount *rc, QObject *me, + const QString &url, int lineNumber, + QmlExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QmlExpression); + d->init(ctxt, expr, rc, me, url, lineNumber); +} + +/*! + Create a QmlExpression object. + + The \a expression JavaScript will be executed in the \a ctxt QmlContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope) +: QObject(*new QmlExpressionPrivate, 0) +{ + Q_D(QmlExpression); + d->init(ctxt, expression, scope); +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope, QmlExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QmlExpression); + d->init(ctxt, expression, scope); +} + +/*! + Destroy the QmlExpression instance. +*/ +QmlExpression::~QmlExpression() +{ +} + +/*! + Returns the QmlEngine this expression is associated with, or 0 if there + is no association or the QmlEngine has been destroyed. +*/ +QmlEngine *QmlExpression::engine() const +{ + Q_D(const QmlExpression); + return d->data->context()?d->data->context()->engine():0; +} + +/*! + Returns the QmlContext this expression is associated with, or 0 if there + is no association or the QmlContext has been destroyed. +*/ +QmlContext *QmlExpression::context() const +{ + Q_D(const QmlExpression); + return d->data->context(); +} + +/*! + Returns the expression string. +*/ +QString QmlExpression::expression() const +{ + Q_D(const QmlExpression); + return d->data->expression; +} + +/*! + Clear the expression. +*/ +void QmlExpression::clearExpression() +{ + setExpression(QString()); +} + +/*! + Set the expression to \a expression. +*/ +void QmlExpression::setExpression(const QString &expression) +{ + Q_D(QmlExpression); + + d->clearGuards(); + + d->data->expression = expression; + d->data->expressionFunctionValid = false; + d->data->expressionRewritten = false; + d->data->expressionFunction = QScriptValue(); +} + +void QmlExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, + QmlError &error) +{ + if (scriptEngine->hasUncaughtException() && + scriptEngine->uncaughtException().isError()) { + + QString fileName; + int lineNumber = scriptEngine->uncaughtExceptionLineNumber(); + + QScriptValue exception = scriptEngine->uncaughtException(); + QLatin1String fileNameProp("fileName"); + + if (!exception.property(fileNameProp).toString().isEmpty()){ + fileName = exception.property(fileNameProp).toString(); + } else { + fileName = QLatin1String("<Unknown File>"); + } + + error.setUrl(QUrl(fileName)); + error.setLine(lineNumber); + error.setColumn(-1); + error.setDescription(exception.toString()); + } else { + error = QmlError(); + } +} + +QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QmlPerfTimer<QmlPerf::BindValueQt> perfqt; +#endif + + QmlExpressionData *data = this->data; + QmlContextPrivate *ctxtPriv = data->context()->d_func(); + QmlEngine *engine = data->context()->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + if (secondaryScope) + ctxtPriv->defaultObjects.append(secondaryScope); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (!data->expressionFunctionValid) { + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + scriptContext->pushScope(ep->contextClass->newContext(data->context(), data->me)); + + if (data->expressionRewritten) { + data->expressionFunction = scriptEngine->evaluate(data->expression, + data->url, data->line); + } else { + QmlRewrite::RewriteBinding rewriteBinding; + + bool ok = true; + const QString code = rewriteBinding(data->expression, &ok); + if (!ok) { + scriptEngine->popContext(); + return QVariant(); + } + data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line); + } + + scriptEngine->popContext(); + data->expressionFunctionValid = true; + } + + QmlContext *oldSharedContext = 0; + QObject *oldSharedScope = 0; + if (data->isShared) { + oldSharedContext = ep->sharedContext; + oldSharedScope = ep->sharedScope; + ep->sharedContext = data->context(); + ep->sharedScope = data->me; + } + + QScriptValue svalue = data->expressionFunction.call(); + + if (data->isShared) { + ep->sharedContext = oldSharedContext; + ep->sharedScope = oldSharedScope; + } + + if (isUndefined) + *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); + + // Handle exception + if (scriptEngine->hasUncaughtException()) { + exceptionToError(scriptEngine, data->error); + scriptEngine->clearExceptions(); + return QVariant(); + } else { + data->error = QmlError(); + } + + if (secondaryScope) { + QObject *last = ctxtPriv->defaultObjects.takeLast(); + Q_ASSERT(last == secondaryScope); + Q_UNUSED(last); + } + + QVariant rv; + + if (svalue.isArray()) { + int length = svalue.property(QLatin1String("length")).toInt32(); + if (length && svalue.property(0).isObject()) { + QList<QObject *> list; + for (int ii = 0; ii < length; ++ii) { + QScriptValue arrayItem = svalue.property(ii); + QObject *d = arrayItem.toQObject(); + list << d; + } + rv = QVariant::fromValue(list); + } + } else if (svalue.isObject() && + ep->objectClass->scriptClass(svalue) == ep->objectClass) { + QObject *o = svalue.toQObject(); + int type = QMetaType::QObjectStar; + // If the object is null, we extract the predicted type. While this isn't + // 100% reliable, in many cases it gives us better error messages if we + // assign this null-object to an incompatible property + if (!o) type = ep->objectClass->objectType(svalue); + + return QVariant(type, &o); + } + + if (rv.isNull()) + rv = svalue.toVariant(); + + return rv; +} + +QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) +{ + Q_Q(QmlExpression); + + QVariant rv; + if (!q->engine()) { + qWarning("QmlExpression: Attempted to evaluate an expression in an invalid context"); + return rv; + } + + if (data->expression.isEmpty()) + return rv; + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QmlPerfTimer<QmlPerf::BindValue> perf; +#endif + + QmlEnginePrivate *ep = QmlEnginePrivate::get(q->engine()); + + QmlExpression *lastCurrentExpression = ep->currentExpression; + bool lastCaptureProperties = ep->captureProperties; + QPODVector<QmlEnginePrivate::CapturedProperty> lastCapturedProperties; + ep->capturedProperties.copyAndClear(lastCapturedProperties); + + ep->currentExpression = q; + ep->captureProperties = data->trackChange; + + // This object might be deleted during the eval + QmlExpressionData *localData = data; + localData->addref(); + + rv = evalQtScript(secondaryScope, isUndefined); + + ep->currentExpression = lastCurrentExpression; + ep->captureProperties = lastCaptureProperties; + + // Check if we were deleted + if (localData->q) { + if ((!data->trackChange || !ep->capturedProperties.count()) && data->guardList) { + clearGuards(); + } else if(data->trackChange) { + updateGuards(ep->capturedProperties); + } + } + + localData->release(); + + lastCapturedProperties.copyAndClear(ep->capturedProperties); + + return rv; +} + +/*! + Returns the value of the expression, or an invalid QVariant if the + expression is invalid or has an error. + + \a isUndefined is set to true if the expression resulted in an + undefined value. + + \sa hasError(), error() +*/ +QVariant QmlExpression::value(bool *isUndefined) +{ + Q_D(QmlExpression); + return d->value(0, isUndefined); +} + +/*! + Returns true if the expression results in a constant value. + QmlExpression::value() must have been invoked at least once before the + return from this method is valid. + */ +bool QmlExpression::isConstant() const +{ + Q_D(const QmlExpression); + return !d->data->guardList; +} + +/*! + Returns true if the changes are tracked in the expression's value. +*/ +bool QmlExpression::trackChange() const +{ + Q_D(const QmlExpression); + return d->data->trackChange; +} + +/*! + Set whether changes are tracked in the expression's value to \a trackChange. + + If true, the QmlExpression will monitor properties involved in the + expression's evaluation, and call QmlExpression::valueChanged() if they have + changed. This allows an application to ensure that any value associated + with the result of the expression remains up to date. + + If false, the QmlExpression will not montitor properties involved in the + expression's evaluation, and QmlExpression::valueChanged() will never be + called. This is more efficient if an application wants a "one off" + evaluation of the expression. + + By default, trackChange is true. +*/ +void QmlExpression::setTrackChange(bool trackChange) +{ + Q_D(QmlExpression); + d->data->trackChange = trackChange; +} + +/*! + Returns the source file URL for this expression. The source location must + have been previously set by calling setSourceLocation(). +*/ +QString QmlExpression::sourceFile() const +{ + Q_D(const QmlExpression); + return d->data->url; +} + +/*! + Returns the source file line number for this expression. The source location + must have been previously set by calling setSourceLocation(). +*/ +int QmlExpression::lineNumber() const +{ + Q_D(const QmlExpression); + return d->data->line; +} + +/*! + Set the location of this expression to \a line of \a url. This information + is used by the script engine. +*/ +void QmlExpression::setSourceLocation(const QString &url, int line) +{ + Q_D(QmlExpression); + d->data->url = url; + d->data->line = line; +} + +/*! + Returns the expression's scope object, if provided, otherwise 0. + + In addition to data provided by the expression's QmlContext, the scope + object's properties are also in scope during the expression's evaluation. +*/ +QObject *QmlExpression::scopeObject() const +{ + Q_D(const QmlExpression); + return d->data->me; +} + +/*! + Returns true if the last call to value() resulted in an error, + otherwise false. + + \sa error(), clearError() +*/ +bool QmlExpression::hasError() const +{ + Q_D(const QmlExpression); + return d->data->error.isValid(); +} + +/*! + Clear any expression errors. Calls to hasError() following this will + return false. + + \sa hasError(), error() +*/ +void QmlExpression::clearError() +{ + Q_D(QmlExpression); + d->data->error = QmlError(); +} + +/*! + Return any error from the last call to value(). If there was no error, + this returns an invalid QmlError instance. + + \sa hasError(), clearError() +*/ + +QmlError QmlExpression::error() const +{ + Q_D(const QmlExpression); + return d->data->error; +} + +/*! \internal */ +void QmlExpression::__q_notify() +{ + emitValueChanged(); +} + +void QmlExpressionPrivate::clearGuards() +{ + Q_Q(QmlExpression); + + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); + + for (int ii = 0; ii < data->guardListLength; ++ii) { + if (data->guardList[ii].data()) { +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#else + // QTBUG-6781 + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#endif + } + } + + delete [] data->guardList; data->guardList = 0; + data->guardListLength = 0; +} + +void QmlExpressionPrivate::updateGuards(const QPODVector<QmlEnginePrivate::CapturedProperty> &properties) +{ + //clearGuards(); + Q_Q(QmlExpression); + + static int notifyIdx = -1; + if (notifyIdx == -1) + notifyIdx = + QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); + + QmlExpressionData::SignalGuard *newGuardList = 0; + + if (properties.count() != data->guardListLength) + newGuardList = new QmlExpressionData::SignalGuard[properties.count()]; + + bool outputWarningHeader = false; + int hit = 0; + for (int ii = 0; ii < properties.count(); ++ii) { + const QmlEnginePrivate::CapturedProperty &property = properties.at(ii); + + bool needGuard = true; + if (ii >= data->guardListLength) { + // New guard + } else if(data->guardList[ii].data() == property.object && + data->guardList[ii].notifyIndex == property.notifyIndex) { + // Cache hit + if (!data->guardList[ii].isDuplicate || + (data->guardList[ii].isDuplicate && hit == ii)) { + needGuard = false; + ++hit; + } + } else if(data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { + // Cache miss +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#else + // QTBUG-6781 + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#endif + } + /* else { + // Cache miss, but nothing to do + } */ + + if (needGuard) { + if (!newGuardList) { + newGuardList = new QmlExpressionData::SignalGuard[properties.count()]; + for (int jj = 0; jj < ii; ++jj) + newGuardList[jj] = data->guardList[jj]; + } + + if (property.notifyIndex != -1) { + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + existing = newGuardList[jj].data() == property.object && + newGuardList[jj].notifyIndex == property.notifyIndex; + + newGuardList[ii] = property.object; + newGuardList[ii].notifyIndex = property.notifyIndex; + if (existing) + newGuardList[ii].isDuplicate = true; + else + QMetaObject::connect(property.object, property.notifyIndex, + q, notifyIdx); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QmlExpression: Expression" << q->expression() + << "depends on non-NOTIFYable properties:"; + } + + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); + + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } + } else if (newGuardList) { + newGuardList[ii] = data->guardList[ii]; + } + } + + for (int ii = properties.count(); ii < data->guardListLength; ++ii) { + if (data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#else + // QTBUG-6781 + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); +#endif + } + } + + if (newGuardList) { + if (data->guardList) delete [] data->guardList; + data->guardList = newGuardList; + data->guardListLength = properties.count(); + } +} + +/*! + \fn void QmlExpression::valueChanged() + + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QmlExpression::value()) before this signal will be emitted. +*/ + +/*! + Subclasses can capture the emission of the valueChanged() signal by overriding + this function. They can choose whether to then call valueChanged(). +*/ +void QmlExpression::emitValueChanged() +{ + emit valueChanged(); +} + +QmlAbstractExpression::QmlAbstractExpression() +: m_context(0), m_prevExpression(0), m_nextExpression(0) +{ +} + +QmlAbstractExpression::~QmlAbstractExpression() +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } +} + +QmlContext *QmlAbstractExpression::context() const +{ + return m_context; +} + +void QmlAbstractExpression::setContext(QmlContext *context) +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (m_context) { + QmlContextPrivate *cp = + static_cast<QmlContextPrivate *>(QObjectPrivate::get(m_context)); + m_nextExpression = cp->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &cp->expressions; + cp->expressions = this; + } +} + +void QmlAbstractExpression::refresh() +{ +} + +bool QmlAbstractExpression::isValid() const +{ + return m_context != 0; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h new file mode 100644 index 0000000..4df7641 --- /dev/null +++ b/src/declarative/qml/qmlexpression.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLEXPRESSION_H +#define QMLEXPRESSION_H + +#include "qmlerror.h" + +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QmlRefCount; +class QmlEngine; +class QmlContext; +class QmlExpressionPrivate; +class Q_DECLARATIVE_EXPORT QmlExpression : public QObject +{ + Q_OBJECT +public: + QmlExpression(); + QmlExpression(QmlContext *, const QString &, QObject *); + virtual ~QmlExpression(); + + QmlEngine *engine() const; + QmlContext *context() const; + + QString expression() const; + void clearExpression(); + virtual void setExpression(const QString &); + bool isConstant() const; + + bool trackChange() const; + void setTrackChange(bool); + + QString sourceFile() const; + int lineNumber() const; + void setSourceLocation(const QString &fileName, int line); + + QObject *scopeObject() const; + + bool hasError() const; + void clearError(); + QmlError error() const; + +public Q_SLOTS: + QVariant value(bool *isUndefined = 0); + +Q_SIGNALS: + void valueChanged(); + +protected: + virtual void emitValueChanged(); + + QmlExpression(QmlContext *, const QString &, QObject *, + QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, const QString &, + int, QmlExpressionPrivate &dd); + +private Q_SLOTS: + void __q_notify(); + +private: + Q_DECLARE_PRIVATE(QmlExpression) + friend class QmlDebugger; + friend class QmlContext; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLEXPRESSION_H + diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h new file mode 100644 index 0000000..1fbb075 --- /dev/null +++ b/src/declarative/qml/qmlexpression_p.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLEXPRESSION_P_H +#define QMLEXPRESSION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlexpression.h" + +#include "qmlengine_p.h" +#include "qmlguard_p.h" + +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_NAMESPACE + +class QmlAbstractExpression +{ +public: + QmlAbstractExpression(); + virtual ~QmlAbstractExpression(); + + bool isValid() const; + + QmlContext *context() const; + void setContext(QmlContext *); + + virtual void refresh(); + +private: + friend class QmlContext; + friend class QmlContextPrivate; + QmlContext *m_context; + QmlAbstractExpression **m_prevExpression; + QmlAbstractExpression *m_nextExpression; +}; + +class QmlDelayedError +{ +public: + inline QmlDelayedError() : nextError(0), prevError(0) {} + inline ~QmlDelayedError() { removeError(); } + + QmlError error; + + bool addError(QmlEnginePrivate *); + + inline void removeError() { + if (!prevError) return; + if (nextError) nextError->prevError = prevError; + *prevError = nextError; + nextError = 0; + prevError = 0; + } + +private: + QmlDelayedError *nextError; + QmlDelayedError **prevError; +}; + +class QmlExpressionData : public QmlAbstractExpression, public QmlDelayedError, public QmlRefCount +{ +public: + QmlExpressionData(); + virtual ~QmlExpressionData(); + + QmlExpressionPrivate *q; + + QString expression; + bool expressionFunctionValid:1; + bool expressionRewritten:1; + QScriptValue expressionFunction; + + QObject *me; + bool trackChange; + + bool isShared; + + QString url; // This is a QString for a reason. QUrls are slooooooow... + int line; + + struct SignalGuard : public QmlGuard<QObject> { + SignalGuard() : isDuplicate(false), notifyIndex(-1) {} + + SignalGuard &operator=(QObject *obj) { + QmlGuard<QObject>::operator=(obj); + return *this; + } + SignalGuard &operator=(const SignalGuard &o) { + QmlGuard<QObject>::operator=(o); + isDuplicate = o.isDuplicate; + notifyIndex = o.notifyIndex; + return *this; + } + + bool isDuplicate:1; + int notifyIndex:31; + }; + SignalGuard *guardList; + int guardListLength; +}; + +class QmlExpression; +class QString; +class QmlExpressionPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlExpression) +public: + QmlExpressionPrivate(); + QmlExpressionPrivate(QmlExpressionData *); + ~QmlExpressionPrivate(); + + void init(QmlContext *, const QString &, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *, const QString &, int); + + QmlExpressionData *data; + + QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); + QVariant evalQtScript(QObject *secondaryScope, bool *isUndefined = 0); + + void updateGuards(const QPODVector<QmlEnginePrivate::CapturedProperty> &properties); + void clearGuards(); + + static QmlExpressionPrivate *get(QmlExpression *expr) { + return static_cast<QmlExpressionPrivate *>(QObjectPrivate::get(expr)); + } + static QmlExpression *get(QmlExpressionPrivate *expr) { + return expr->q_func(); + } + + static void exceptionToError(QScriptEngine *, QmlError &); + static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QString &); + static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QScriptProgram &); +}; + +QT_END_NAMESPACE + +#endif // QMLEXPRESSION_P_H diff --git a/src/declarative/qml/qmlglobal_p.h b/src/declarative/qml/qmlglobal_p.h new file mode 100644 index 0000000..dc282bc --- /dev/null +++ b/src/declarative/qml/qmlglobal_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGLOBAL_H +#define QMLGLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +#define DEFINE_BOOL_CONFIG_OPTION(name, var) \ + static bool name() \ + { \ + static enum { Yes, No, Unknown } status = Unknown; \ + if (status == Unknown) { \ + QByteArray v = qgetenv(#var); \ + bool value = !v.isEmpty() && v != "0" && v != "false"; \ + if (value) status = Yes; \ + else status = No; \ + } \ + return status == Yes; \ + } + +struct QmlGraphics_DerivedObject : public QObject +{ + void setParent_noEvent(QObject *parent) { + bool sce = d_ptr->sendChildEvents; + d_ptr->sendChildEvents = false; + setParent(parent); + d_ptr->sendChildEvents = sce; + } +}; + +/*! + Makes the \a object a child of \a parent. Note that when using this method, + neither \a parent nor the object's previous parent (if it had one) will + receive ChildRemoved or ChildAdded events. +*/ +inline void QmlGraphics_setParent_noEvent(QObject *object, QObject *parent) +{ + static_cast<QmlGraphics_DerivedObject *>(object)->setParent_noEvent(parent); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLGLOBAL_H diff --git a/src/declarative/qml/qmlglobalscriptclass.cpp b/src/declarative/qml/qmlglobalscriptclass.cpp new file mode 100644 index 0000000..13c1017 --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlglobalscriptclass_p.h" + +#include <QtScript/qscriptstring.h> +#include <QtScript/qscriptengine.h> +#include <QtScript/qscriptvalueiterator.h> + +QT_BEGIN_NAMESPACE + +/* + Used to prevent any writes to the global object. +*/ +QmlGlobalScriptClass::QmlGlobalScriptClass(QScriptEngine *engine) +: QScriptClass(engine) +{ + QScriptValue v = engine->newObject(); + globalObject = engine->globalObject(); + + QScriptValueIterator iter(globalObject); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + v.setScriptClass(this); + engine->setGlobalObject(v); +} + +QScriptClass::QueryFlags +QmlGlobalScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(flags); + Q_UNUSED(id); + return HandlesReadAccess | HandlesWriteAccess; +} + +QScriptValue +QmlGlobalScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(id); + return engine()->undefinedValue(); +} + +void QmlGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + Q_UNUSED(object); + Q_UNUSED(id); + Q_UNUSED(value); + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1Char('\"'); + engine()->currentContext()->throwError(error); +} + +void QmlGlobalScriptClass::explicitSetProperty(const QString &name, const QScriptValue &value) +{ + QScriptValue v = engine()->newObject(); + globalObject = engine()->globalObject(); + + QScriptValueIterator iter(globalObject); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + v.setProperty(name, value); + v.setScriptClass(this); + engine()->setGlobalObject(v); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlglobalscriptclass_p.h b/src/declarative/qml/qmlglobalscriptclass_p.h new file mode 100644 index 0000000..56c91fe --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGLOBALSCRIPTCLASS_P_H +#define QMLGLOBALSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptclass.h> + +QT_BEGIN_NAMESPACE + +class Q_AUTOTEST_EXPORT QmlGlobalScriptClass : public QScriptClass +{ +public: + QmlGlobalScriptClass(QScriptEngine *); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + + virtual QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint id); + + virtual void setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value); + + void explicitSetProperty(const QString &, const QScriptValue &); + +private: + QScriptValue globalObject; +}; + +QT_END_NAMESPACE + +#endif // QMLGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlguard_p.h b/src/declarative/qml/qmlguard_p.h new file mode 100644 index 0000000..42a4406 --- /dev/null +++ b/src/declarative/qml/qmlguard_p.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGUARD_P_H +#define QMLGUARD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QObject; +template<class T> +class QmlGuard +{ + QObject *o; + QmlGuard<QObject> *next; + QmlGuard<QObject> **prev; + friend class QmlDeclarativeData; +public: + inline QmlGuard(); + inline QmlGuard(T *); + inline QmlGuard(const QmlGuard<T> &); + inline virtual ~QmlGuard(); + + inline QmlGuard<T> &operator=(const QmlGuard<T> &o); + inline QmlGuard<T> &operator=(T *); + + inline bool isNull() const + { return !o; } + + inline T* operator->() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T& operator*() const + { return *static_cast<T*>(const_cast<QObject*>(o)); } + inline operator T*() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T* data() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + +protected: + virtual void objectDestroyed(T *) {} + +private: + inline void addGuard(); + inline void remGuard(); +}; + +QT_END_NAMESPACE + +#include "qmldeclarativedata_p.h" + +QT_BEGIN_NAMESPACE + +template<class T> +QmlGuard<T>::QmlGuard() +: o(0), next(0), prev(0) +{ +} + +template<class T> +QmlGuard<T>::QmlGuard(T *g) +: o(g), next(0), prev(0) +{ + if (o) addGuard(); +} + +template<class T> +QmlGuard<T>::QmlGuard(const QmlGuard<T> &g) +: o(g.o), next(0), prev(0) +{ + if (o) addGuard(); +} + +template<class T> +QmlGuard<T>::~QmlGuard() +{ + if (prev) remGuard(); + o = 0; +} + +template<class T> +QmlGuard<T> &QmlGuard<T>::operator=(const QmlGuard<T> &g) +{ + if (g.o != o) { + if (prev) remGuard(); + o = g.o; + if (o) addGuard(); + } + return *this; +} + +template<class T> +QmlGuard<T> &QmlGuard<T>::operator=(T *g) +{ + if (g != o) { + if (prev) remGuard(); + o = g; + if (o) addGuard(); + } + return *this; +} + +QT_END_NAMESPACE + +#endif // QMLGUARD_P_H diff --git a/src/declarative/qml/qmlinfo.cpp b/src/declarative/qml/qmlinfo.cpp new file mode 100644 index 0000000..dabf944 --- /dev/null +++ b/src/declarative/qml/qmlinfo.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlinfo.h" + +#include "qmldeclarativedata_p.h" +#include "qmlcontext.h" +#include "qmlmetatype.h" + +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +/*! + \fn QmlInfo qmlInfo(const QObject *object) + + \brief Prints warnings messages that include the file and line number for QML types. + + When QML types display warning messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlInfo(object) << tr("component property is a write-once property"); + \endcode + + prints + + \code + QML MyCustomType (unknown location): component property is a write-once property + \endcode +*/ + +QmlInfo::QmlInfo(const QObject *object) +: QDebug(QtWarningMsg) +{ + QString pos = QLatin1String("QML"); + if (object) { + pos += QLatin1Char(' '); + + QString typeName; + QmlType *type = QmlMetaType::qmlType(object->metaObject()); + if (type) { + typeName = QLatin1String(type->qmlTypeName()); + int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + if (lastSlash != -1) + typeName = typeName.mid(lastSlash+1); + } else { + typeName = QString::fromUtf8(object->metaObject()->className()); + int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); + if (marker != -1) + typeName = typeName.left(marker); + } + + pos += typeName; + } + QmlDeclarativeData *ddata = object?QmlDeclarativeData::get(object):0; + pos += QLatin1String(" ("); + if (ddata) { + if (ddata->outerContext) { + pos += ddata->outerContext->baseUrl().toString(); + pos += QLatin1Char(':'); + pos += QString::number(ddata->lineNumber); + pos += QLatin1Char(':'); + pos += QString::number(ddata->columnNumber); + } else { + pos += QCoreApplication::translate("QmlInfo","unknown location"); + } + } else { + pos += QCoreApplication::translate("QmlInfo","unknown location"); + } + pos += QLatin1Char(')'); + *this << pos; + nospace(); +} + +QmlInfo::~QmlInfo() +{ +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinfo.h b/src/declarative/qml/qmlinfo.h new file mode 100644 index 0000000..fd56118 --- /dev/null +++ b/src/declarative/qml/qmlinfo.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINFO_H +#define QMLINFO_H + +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlInfo : public QDebug +{ +public: + QmlInfo(const QObject *); + ~QmlInfo(); + + inline QmlInfo &operator<<(QChar t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(QBool t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(bool t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(char t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(signed short t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(unsigned short t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(signed int t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(unsigned int t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(signed long t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(unsigned long t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(qint64 t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(quint64 t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(float t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(double t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; } + inline QmlInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); } + inline QmlInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; } + inline QmlInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; } + inline QmlInfo &operator<<(QTextStreamFunction f) { QDebug::operator<<(f); return *this; } + inline QmlInfo &operator<<(QTextStreamManipulator m) { QDebug::operator<<(m); return *this; } +}; + +Q_DECLARATIVE_EXPORT inline QmlInfo qmlInfo(const QObject *me) +{ + return QmlInfo(me); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLINFO_H diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp new file mode 100644 index 0000000..d99bf65 --- /dev/null +++ b/src/declarative/qml/qmlinstruction.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlinstruction_p.h" + +#include "qmlcompiler_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +void QmlCompiledData::dump(QmlInstruction *instr, int idx) +{ + QByteArray lineNumber = QByteArray::number(instr->line); + if (instr->line == (unsigned short)-1) + lineNumber = "NA"; + const char *line = lineNumber.constData(); + + switch(instr->type) { + case QmlInstruction::Init: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding; + break; + case QmlInstruction::CreateObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; + break; + case QmlInstruction::SetId: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value); + break; + case QmlInstruction::SetDefault: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "SET_DEFAULT"; + break; + case QmlInstruction::CreateComponent: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; + break; + case QmlInstruction::StoreMetaObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data; + break; + + case QmlInstruction::StoreFloat: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; + break; + case QmlInstruction::StoreDouble: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; + break; + case QmlInstruction::StoreInteger: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; + case QmlInstruction::StoreBool: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; + case QmlInstruction::StoreString: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QmlInstruction::StoreUrl: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << primitives.at(instr->storeUrl.value); + break; + case QmlInstruction::StoreColor: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16); + break; + case QmlInstruction::StoreDate: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value; + break; + case QmlInstruction::StoreTime: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex; + break; + case QmlInstruction::StoreDateTime: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex; + break; + case QmlInstruction::StorePoint: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StorePointF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSize: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSizeF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreRect: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreRectF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreVector3D: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.valueIndex; + break; + case QmlInstruction::StoreVariant: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QmlInstruction::StoreObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreVariantObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreInterface: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; + break; + + case QmlInstruction::StoreSignal: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); + break; + case QmlInstruction::StoreScript: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT\t\t" << instr->storeScript.value; + break; + case QmlInstruction::StoreScriptString: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope; + break; + + case QmlInstruction::AssignSignalObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); + break; + case QmlInstruction::AssignCustomType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; + + case QmlInstruction::StoreBinding: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; + case QmlInstruction::StoreCompiledBinding: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; + case QmlInstruction::StoreValueSource: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; + break; + case QmlInstruction::StoreValueInterceptor: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue; + break; + + case QmlInstruction::BeginObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue; + break; + case QmlInstruction::StoreObjectQmlList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT_QMLLIST"; + break; + case QmlInstruction::StoreObjectQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; + case QmlInstruction::AssignObjectList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_OBJECT_LIST"; + break; + case QmlInstruction::FetchAttached: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id; + break; + case QmlInstruction::FetchQmlList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_QMLLIST\t\t" << instr->fetchQmlList.property << "\t" << instr->fetchQmlList.type; + break; + case QmlInstruction::FetchQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property; + break; + case QmlInstruction::FetchObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property; + break; + case QmlInstruction::FetchValueType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; + break; + case QmlInstruction::PopFetchedObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP"; + break; + case QmlInstruction::PopQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_QLIST"; + break; + case QmlInstruction::PopValueType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; + break; + case QmlInstruction::Defer: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount; + break; + default: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "XXX UNKOWN INSTRUCTION" << "\t" << instr->type; + break; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h new file mode 100644 index 0000000..0639397 --- /dev/null +++ b/src/declarative/qml/qmlinstruction_p.h @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINSTRUCTION_P_H +#define QMLINSTRUCTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlCompiledData; +class Q_DECLARATIVE_EXPORT QmlInstruction +{ +public: + enum Type { + // + // Object Creation + // + // CreateObject - Create a new object instance and push it on the + // object stack + // SetId - Set the id of the object on the top of the object stack + // SetDefault - Sets the instance on the top of the object stack to + // be the context's default object. + // StoreMetaObject - Assign the dynamic metaobject to object on the + // top of the stack. + Init, /* init */ + CreateObject, /* create */ + SetId, /* setId */ + SetDefault, + CreateComponent, /* createComponent */ + StoreMetaObject, /* storeMeta */ + + // + // Precomputed single assignment + // + // StoreFloat - Store a float in a core property + // StoreDouble - Store a double in a core property + // StoreInteger - Store a int or uint in a core property + // StoreBool - Store a bool in a core property + // StoreString - Store a QString in a core property + // StoreUrl - Store a QUrl in a core property + // StoreColor - Store a QColor in a core property + // StoreDate - Store a QDate in a core property + // StoreTime - Store a QTime in a core property + // StoreDateTime - Store a QDateTime in a core property + // StoreVariant - Store a QVariant in a core property + // StoreObject - Pop the object on the top of the object stack and + // store it in a core property + StoreFloat, /* storeFloat */ + StoreDouble, /* storeDouble */ + StoreInteger, /* storeInteger */ + StoreBool, /* storeBool */ + StoreString, /* storeString */ + StoreUrl, /* storeUrl */ + StoreColor, /* storeColor */ + StoreDate, /* storeDate */ + StoreTime, /* storeTime */ + StoreDateTime, /* storeDateTime */ + StorePoint, /* storeRealPair */ + StorePointF, /* storeRealPair */ + StoreSize, /* storeRealPair */ + StoreSizeF, /* storeRealPair */ + StoreRect, /* storeRect */ + StoreRectF, /* storeRect */ + StoreVector3D, /* storeVector3D */ + StoreVariant, /* storeString */ + StoreObject, /* storeObject */ + StoreVariantObject, /* storeObject */ + StoreInterface, /* storeObject */ + + StoreSignal, /* storeSignal */ + StoreScript, /* storeScript */ + StoreScriptString, /* storeScriptString */ + + // + // Unresolved single assignment + // + AssignSignalObject, /* assignSignalObject */ + AssignCustomType, /* assignCustomType */ + + StoreBinding, /* assignBinding */ + StoreCompiledBinding, /* assignBinding */ + StoreValueSource, /* assignValueSource */ + StoreValueInterceptor, /* assignValueInterceptor */ + + BeginObject, /* begin */ + + StoreObjectQmlList, /* NA */ + StoreObjectQList, /* NA */ + AssignObjectList, /* NA */ + + FetchAttached, /* fetchAttached */ + FetchQmlList, /* fetchQmlList */ + FetchQList, /* fetch */ + FetchObject, /* fetch */ + FetchValueType, /* fetchValue */ + + // + // Stack manipulation + // + // PopFetchedObject - Remove an object from the object stack + // PopQList - Remove a list from the list stack + PopFetchedObject, + PopQList, + PopValueType, /* fetchValue */ + + // + // Deferred creation + // + Defer, /* defer */ + }; + QmlInstruction() + : line(0) {} + + Type type; + unsigned short line; + union { + struct { + int bindingsSize; + int parserStatusSize; + int contextCache; + int compiledBinding; + } init; + struct { + int type; + int data; + int bindingBits; + ushort column; + } create; + struct { + int data; + int aliasData; + int propertyCache; + } storeMeta; + struct { + int value; + int index; + } setId; + struct { + int property; + int owner; + int castValue; + } assignValueSource; + struct { + int property; + int owner; + int castValue; + } assignValueInterceptor; + struct { + unsigned int property; + int value; + short context; + short owner; + } assignBinding; + struct { + int property; + int id; + } assignIdOptBinding; + struct { + int property; + int contextIdx; + short context; + short notifyIdx; + } assignObjPropBinding; + struct { + int property; + } fetch; + struct { + int property; + int type; + } fetchValue; + struct { + int property; + int type; + } fetchQmlList; + struct { + int castValue; + } begin; + struct { + int propertyIndex; + float value; + } storeFloat; + struct { + int propertyIndex; + double value; + } storeDouble; + struct { + int propertyIndex; + int value; + } storeInteger; + struct { + int propertyIndex; + bool value; + } storeBool; + struct { + int propertyIndex; + int value; + } storeString; + struct { + int propertyIndex; + int value; + int scope; + } storeScriptString; + struct { + int value; + } storeScript; + struct { + int propertyIndex; + int value; + } storeUrl; + struct { + int propertyIndex; + unsigned int value; + } storeColor; + struct { + int propertyIndex; + int value; + } storeDate; + struct { + int propertyIndex; + int valueIndex; + } storeTime; + struct { + int propertyIndex; + int valueIndex; + } storeDateTime; + struct { + int propertyIndex; + int valueIndex; + } storeRealPair; + struct { + int propertyIndex; + int valueIndex; + } storeRect; + struct { + int propertyIndex; + int valueIndex; + } storeVector3D; + struct { + int propertyIndex; + } storeObject; + struct { + int propertyIndex; + int valueIndex; + } assignCustomType; + struct { + int signalIndex; + int value; + } storeSignal; + struct { + int signal; + } assignSignalObject; + struct { + int count; + ushort column; + int endLine; + int metaObject; + } createComponent; + struct { + int id; + } fetchAttached; + struct { + int deferCount; + } defer; + }; + + void dump(QmlCompiledData *); +}; + +QT_END_NAMESPACE + +#endif // QMLINSTRUCTION_P_H diff --git a/src/declarative/qml/qmlintegercache.cpp b/src/declarative/qml/qmlintegercache.cpp new file mode 100644 index 0000000..1968873 --- /dev/null +++ b/src/declarative/qml/qmlintegercache.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlintegercache_p.h" + +#include "qmlengine_p.h" +#include "qmlmetatype.h" + +QT_BEGIN_NAMESPACE + +QmlIntegerCache::QmlIntegerCache(QmlEngine *e) +: QmlCleanup(e), engine(e) +{ +} + +QmlIntegerCache::~QmlIntegerCache() +{ + clear(); +} + +void QmlIntegerCache::clear() +{ + qDeleteAll(stringCache); + stringCache.clear(); + identifierCache.clear(); + engine = 0; +} + +void QmlIntegerCache::add(const QString &id, int value) +{ + Q_ASSERT(!stringCache.contains(id)); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### use contextClass + Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value); + + stringCache.insert(id, d); + identifierCache.insert(d->identifier, d); +} + +int QmlIntegerCache::value(const QString &id) +{ + Data *d = stringCache.value(id); + return d?d->value:-1; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlintegercache_p.h b/src/declarative/qml/qmlintegercache_p.h new file mode 100644 index 0000000..d9df52a --- /dev/null +++ b/src/declarative/qml/qmlintegercache_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINTEGERCACHE_P_H +#define QMLINTEGERCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlrefcount_p.h" +#include "qmlcleanup_p.h" + +#include <QtCore/qhash.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlIntegerCache : public QmlRefCount, public QmlCleanup +{ +public: + QmlIntegerCache(QmlEngine *); + virtual ~QmlIntegerCache(); + + inline int count() const; + void add(const QString &, int); + int value(const QString &); + inline int value(const QScriptDeclarativeClass::Identifier &id) const; + +protected: + virtual void clear(); + +private: + struct Data : public QScriptDeclarativeClass::PersistentIdentifier { + Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v) + : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {} + + int value; + }; + + typedef QHash<QString, Data *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, Data *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +int QmlIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const +{ + Data *d = identifierCache.value(id); + return d?d->value:-1; +} + +int QmlIntegerCache::count() const +{ + return stringCache.count(); +} + +QT_END_NAMESPACE + +#endif // QMLINTEGERCACHE_P_H + diff --git a/src/declarative/qml/qmllist.h b/src/declarative/qml/qmllist.h new file mode 100644 index 0000000..ad2d874 --- /dev/null +++ b/src/declarative/qml/qmllist.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLLIST_H +#define QMLLIST_H + +#include "qmlprivate.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +template<typename T> +class QmlList : private QmlPrivate::ListInterface +{ +public: + virtual void append(T) = 0; + virtual void insert(int, T) = 0; + virtual void removeAt(int) = 0; + virtual T at(int) const = 0; + virtual int count() const = 0; + virtual void clear() = 0; + QmlList<T> &operator<<(T t) { append(t); return *this; } + +protected: + virtual int type() const { return qMetaTypeId<T>(); } + virtual void append(void *d) { const T &v = *(T *)d; append(v); } + virtual void insert(int i, void *d) { const T &v = *(T *)d; insert(i, v); } + virtual void at(int i, void *p) const { const T &v = at(i); *((T*)p) = v; } +}; + +template<typename T> +class QmlConcreteList : public QList<T>, public QmlList<T> +{ +public: + virtual void append(T v) { QList<T>::append(v); } + virtual void insert(int i, T v) { QList<T>::insert(i, v); } + virtual void clear() { QList<T>::clear(); } + virtual T at(int i) const { return QList<T>::at(i); } + virtual void removeAt(int i) { QList<T>::removeAt(i); } + virtual int count() const { return QList<T>::count(); } +}; + +#define QML_DECLARE_LIST_PROXY(ClassName, ListType, ListName) \ +class Qml_ProxyList_ ##ListName : public QmlList<ListType> \ +{ \ + public: \ + virtual void removeAt(int idx) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _removeAt(idx); \ + } \ + virtual int count() const \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + return p->ListName ## _count(); \ + } \ + virtual void append(ListType v) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _append(v); \ + } \ + virtual void insert(int idx, ListType v) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _insert(idx, v); \ + } \ + virtual ListType at(int idx) const \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + return p->ListName ## _at(idx); \ + } \ + virtual void clear() \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _clear(); \ + } \ +}; \ +friend class Qml_ProxyList_ ##ListName ; \ +Qml_ProxyList_##ListName ListName; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLLIST_H diff --git a/src/declarative/qml/qmllistscriptclass.cpp b/src/declarative/qml/qmllistscriptclass.cpp new file mode 100644 index 0000000..d4cdc6e --- /dev/null +++ b/src/declarative/qml/qmllistscriptclass.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmllistscriptclass_p.h" + +#include "qmlengine_p.h" +#include "qmlguard_p.h" + +QT_BEGIN_NAMESPACE + +struct ListData : public QScriptDeclarativeClass::Object { + QmlGuard<QObject> object; + int propertyIdx; + QmlListScriptClass::ListCategory type; + int propertyType; +}; + +QmlListScriptClass::QmlListScriptClass(QmlEngine *e) +: QmlScriptClass(QmlEnginePrivate::getScriptEngine(e)), engine(e) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + Q_UNUSED(scriptEngine); + + m_lengthId = createPersistentIdentifier(QLatin1String("length")); +} + +QmlListScriptClass::~QmlListScriptClass() +{ +} + +QScriptValue QmlListScriptClass::newList(QObject *object, int propId, ListCategory type, int propType) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (!object || propId == -1) + return scriptEngine->nullValue(); + + ListData *data = new ListData; + data->object = object; + data->propertyIdx = propId; + data->type = type; + data->propertyType = propType; + + return newObject(scriptEngine, this, data); +} + +QScriptClass::QueryFlags +QmlListScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(object); + Q_UNUSED(flags); + if (name == m_lengthId.identifier) + return QScriptClass::HandlesReadAccess; + + bool ok = false; + quint32 idx = toArrayIndex(name, &ok); + + if (ok) { + lastIndex = idx; + return QScriptClass::HandlesReadAccess; + } else { + return 0; + } +} + +QmlListScriptClass::ScriptValue QmlListScriptClass::property(Object *obj, const Identifier &name) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + ListData *data = (ListData *)obj; + if (!data->object) + return Value(); + + void *list = 0; + void *args[] = { &list, 0 }; + QMetaObject::metacall(data->object, QMetaObject::ReadProperty, + data->propertyIdx, args); + + if (!list) + return Value(); + + if (data->type == QListPtr) { + const QList<QObject *> &qlist = *((QList<QObject *>*)list); + + quint32 count = qlist.count(); + + if (name == m_lengthId.identifier) + return Value(scriptEngine, count); + else if (lastIndex < count) + return Value(scriptEngine, enginePriv->objectClass->newQObject(qlist.at(lastIndex))); + else + return Value(); + + } else { + Q_ASSERT(data->type == QmlListPtr); + const QmlList<QObject *> &qmllist = *((QmlList<QObject *>*)list); + + quint32 count = qmllist.count(); + + if (name == m_lengthId.identifier) + return Value(scriptEngine, count); + else if (lastIndex < count) + return Value(scriptEngine, enginePriv->objectClass->newQObject(qmllist.at(lastIndex))); + else + return Value(); + } +} + +QVariant QmlListScriptClass::toVariant(Object *obj, bool *ok) +{ + ListData *data = (ListData *)obj; + + if (!data->object) { + if (ok) *ok = false; + return QVariant(); + } + + void *list = 0; + void *args[] = { &list, 0 }; + QMetaObject::metacall(data->object, QMetaObject::ReadProperty, + data->propertyIdx, args); + + if (!list) { + if (ok) *ok = false; + return QVariant(); + } + + if (ok) *ok = true; + return QVariant(data->propertyType, &list); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmllistscriptclass_p.h b/src/declarative/qml/qmllistscriptclass_p.h new file mode 100644 index 0000000..e484b34 --- /dev/null +++ b/src/declarative/qml/qmllistscriptclass_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLLISTSCRIPTCLASS_P_H +#define QMLLISTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qmlscriptclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlListScriptClass : public QmlScriptClass +{ +public: + QmlListScriptClass(QmlEngine *); + ~QmlListScriptClass(); + + enum ListCategory { QListPtr, QmlListPtr }; + QScriptValue newList(QObject *, int, ListCategory, int); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual ScriptValue property(Object *, const Identifier &); + virtual QVariant toVariant(Object *, bool *ok); + +private: + PersistentIdentifier m_lengthId; + QmlEngine *engine; + + quint32 lastIndex; +}; + +QT_END_NAMESPACE + +#endif // QMLLISTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp new file mode 100644 index 0000000..09c936e --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -0,0 +1,1240 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetaproperty.h" +#include "qmlmetaproperty_p.h" + +#include "qmlcompositetypedata_p.h" +#include "qml.h" +#include "qmlbinding.h" +#include "qmlcontext.h" +#include "qmlcontext_p.h" +#include "qmlboundsignal_p.h" +#include "qmlengine.h" +#include "qmlengine_p.h" +#include "qmldeclarativedata_p.h" +#include "qmlstringconverters_p.h" + +#include <qfxperf_p_p.h> + +#include <QStringList> +#include <QtCore/qdebug.h> + +#include <math.h> + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +/*! + \class QmlMetaProperty + \brief The QmlMetaProperty class abstracts accessing QML properties. + \internal + */ + +/*! + Create an invalid QmlMetaProperty. +*/ +QmlMetaProperty::QmlMetaProperty() +: d(new QmlMetaPropertyPrivate) +{ + d->q = this; +} + +/*! \internal */ +QmlMetaProperty::~QmlMetaProperty() +{ + delete d; d = 0; +} + +/*! + Creates a QmlMetaProperty for the default property of \a obj. If there is no + default property, an invalid QmlMetaProperty will be created. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj) +: d(new QmlMetaPropertyPrivate) +{ + d->q = this; + d->initDefault(obj); +} + +/*! + \internal + Creates a QmlMetaProperty for the default property of \a obj. If there is no + default property, an invalid QmlMetaProperty will be created. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ + d->q = this; + d->context = ctxt; + d->initDefault(obj); +} + +/*! + Initialize from the default property of \a obj +*/ +void QmlMetaPropertyPrivate::initDefault(QObject *obj) +{ + if (!obj) + return; + + QMetaProperty p = QmlMetaType::defaultProperty(obj); + core.load(p); + if (core.isValid()) { + isDefaultProperty = true; + object = obj; + } +} + +/*! + Creates a QmlMetaProperty for the property \a name of \a obj. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, const QString &name) +: d(new QmlMetaPropertyPrivate) +{ + d->q = this; + d->initProperty(obj, name); + if (!isValid()) d->object = 0; +} + +/*! + \internal + Creates a QmlMetaProperty for the property \a name of \a obj. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, const QString &name, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ + d->q = this; + d->context = ctxt; + d->initProperty(obj, name); + if (!isValid()) { d->object = 0; d->context = 0; } +} + +void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) +{ + QmlEnginePrivate *enginePrivate = 0; + if (context && context->engine()) + enginePrivate = QmlEnginePrivate::get(context->engine()); + + object = obj; + + if (name.isEmpty() || !obj) + return; + + if (enginePrivate && name.at(0).isUpper()) { + // Attached property + // ### What about qualified types? + QmlTypeNameCache *tnCache = QmlContextPrivate::get(context)->imports; + if (tnCache) { + QmlTypeNameCache::Data *d = tnCache->data(name); + if (d && d->type && d->type->attachedPropertiesFunction()) { + attachedFunc = d->type->index(); + } + } + return; + + } else if (name.count() >= 3 && + name.at(0) == QChar(QLatin1Char('o')) && + name.at(1) == QChar(QLatin1Char('n')) && + name.at(2).isUpper()) { + // Signal + QString signalName = name.mid(2); + signalName[0] = signalName.at(0).toLower(); + + QMetaMethod method = findSignal(obj, signalName); + if (method.signature()) { + core.load(method); + return; + } + } + + // Property + QmlPropertyCache::Data local; + QmlPropertyCache::Data *property = + QmlPropertyCache::property(context?context->engine():0, obj, name, local); + if (property && !(property->flags & QmlPropertyCache::Data::IsFunction)) + core = *property; +} + +/*! + Create a copy of \a other. +*/ +QmlMetaProperty::QmlMetaProperty(const QmlMetaProperty &other) +: d(new QmlMetaPropertyPrivate(*other.d)) +{ + d->q = this; +} + +/*! + \enum QmlMetaProperty::PropertyCategory + + This enum specifies a category of QML property. + + \value Unknown The category is unknown. This will never be returned from propertyCategory() + \value InvalidProperty The property is invalid. + \value Bindable The property is a QmlBinding. + \value List The property is a QList pointer + \value QmlList The property is a QmlList pointer + \value Object The property is a QObject derived type pointer + \value Normal The property is none of the above. + */ + +/*! + \enum QmlMetaProperty::Type + + This enum specifies a type of QML property. + + \value Invalid The property is invalid. + \value Property The property is a regular Qt property. + \value SignalProperty The property is a signal property. + \value Default The property is the default property. + \value Attached The property is an attached property. +*/ + +/*! + Returns the property category. +*/ +QmlMetaProperty::PropertyCategory QmlMetaProperty::propertyCategory() const +{ + return d->propertyCategory(); +} + +QmlMetaProperty::PropertyCategory +QmlMetaPropertyPrivate::propertyCategory() const +{ + uint type = q->type(); + + if (type & QmlMetaProperty::ValueTypeProperty) { + return QmlMetaProperty::Normal; + } else if (type & QmlMetaProperty::Attached) { + return QmlMetaProperty::Object; + } else if (type & QmlMetaProperty::Property) { + int type = propertyType(); + if (type == QVariant::Invalid) + return QmlMetaProperty::InvalidProperty; + else if ((uint)type < QVariant::UserType) + return QmlMetaProperty::Normal; + else if (type == qMetaTypeId<QmlBinding *>()) + return QmlMetaProperty::Bindable; + else if (core.flags & QmlPropertyCache::Data::IsQObjectDerived) + return QmlMetaProperty::Object; + else if (core.flags & QmlPropertyCache::Data::IsQmlList) + return QmlMetaProperty::QmlList; + else if (core.flags & QmlPropertyCache::Data::IsQList) + return QmlMetaProperty::List; + else + return QmlMetaProperty::Normal; + } else { + return QmlMetaProperty::InvalidProperty; + } +} + +/*! + Returns the type name of the property, or 0 if the property has no type + name. +*/ +const char *QmlMetaProperty::propertyTypeName() const +{ + if (type() & ValueTypeProperty) { + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName(); + + if (!ep) delete valueType; + + return rv; + } else if (d->object && type() & Property && d->core.isValid()) { + return d->object->metaObject()->property(d->core.coreIndex).typeName(); + } else { + return 0; + } +} + +/*! + Returns true if \a other and this QmlMetaProperty represent the same + property. +*/ +bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const +{ + // category is intentially omitted here as it is generated + // from the other members + return d->object == other.d->object && + d->core == other.d->core && + d->valueType == other.d->valueType && + d->attachedFunc == other.d->attachedFunc; +} + +/*! + Returns the QVariant type of the property, or QVariant::Invalid if the + property has no QVariant type. +*/ +int QmlMetaProperty::propertyType() const +{ + return d->propertyType(); +} + +int QmlMetaPropertyPrivate::propertyType() const +{ + uint type = q->type(); + if (type & QmlMetaProperty::ValueTypeProperty) { + return valueType.valueTypePropType; + } else if (type & QmlMetaProperty::Attached) { + return qMetaTypeId<QObject *>(); + } else if (type & QmlMetaProperty::Property) { + if (core.propType == (int)QVariant::LastType) + return qMetaTypeId<QVariant>(); + else + return core.propType; + } else { + return QVariant::Invalid; + } +} + +/*! + Returns the type of the property. +*/ +QmlMetaProperty::Type QmlMetaProperty::type() const +{ + if (d->core.flags & QmlPropertyCache::Data::IsFunction) + return SignalProperty; + else if (d->attachedFunc != -1) + return Attached; + else if (d->valueType.valueTypeCoreIdx != -1) + return (Type)(Property | ValueTypeProperty); + else if (d->core.isValid()) + return (Type)(Property | ((d->isDefaultProperty)?Default:0)); + else + return Invalid; +} + +/*! + Returns true if this QmlMetaProperty represents a regular Qt property. +*/ +bool QmlMetaProperty::isProperty() const +{ + return type() & Property; +} + +/*! + Returns true if this QmlMetaProperty represents a default property. +*/ +bool QmlMetaProperty::isDefault() const +{ + return type() & Default; +} + +/*! + Returns the QmlMetaProperty's QObject. +*/ +QObject *QmlMetaProperty::object() const +{ + return d->object; +} + +/*! + Assign \a other to this QmlMetaProperty. +*/ +QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) +{ + d->context = other.d->context; + d->object = other.d->object; + + d->isDefaultProperty = other.d->isDefaultProperty; + d->core = other.d->core; + + d->valueType = other.d->valueType; + + d->attachedFunc = other.d->attachedFunc; + return *this; +} + +/*! + Returns true if the property is writable, otherwise false. +*/ +bool QmlMetaProperty::isWritable() const +{ + QmlMetaProperty::PropertyCategory category = propertyCategory(); + + if (!d->object) + return false; + if (category == List || category == QmlList) + return true; + else if (type() & SignalProperty) + return false; + else if (d->core.isValid() && d->object) + return d->core.flags & QmlPropertyCache::Data::IsWritable; + else + return false; +} + +/*! + Returns true if the property is designable, otherwise false. +*/ +bool QmlMetaProperty::isDesignable() const +{ + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); + else + return false; +} + +/*! + Returns true if the property is resettable, otherwise false. +*/ +bool QmlMetaProperty::isResettable() const +{ + if (type() & Property && d->core.isValid() && d->object) + return d->core.flags & QmlPropertyCache::Data::IsResettable; + else + return false; +} + +/*! + Returns true if the QmlMetaProperty refers to a valid property, otherwise + false. +*/ +bool QmlMetaProperty::isValid() const +{ + return type() != Invalid; +} + +/*! + Return the name of this QML property. +*/ +QString QmlMetaProperty::name() const +{ + if (!d->isNameCached) { + // ### + if (!d->object) { + } else if (type() & ValueTypeProperty) { + QString rv = d->core.name(d->object) + QLatin1Char('.'); + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name()); + + if (!ep) delete valueType; + + d->nameCache = rv; + } else if (type() & SignalProperty) { + QString name = QLatin1String("on") + d->core.name(d->object); + name[2] = name.at(2).toUpper(); + d->nameCache = name; + } else { + d->nameCache = d->core.name(d->object); + } + d->isNameCached = true; + } + + return d->nameCache; +} + +/*! + Returns the \l{QMetaProperty} {Qt property} associated with + this QML property. + */ +QMetaProperty QmlMetaProperty::property() const +{ + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex); + else + return QMetaProperty(); +} + +/*! + Return the QMetaMethod for this property if it is a SignalProperty, + otherwise returns an invalid QMetaMethod. +*/ +QMetaMethod QmlMetaProperty::method() const +{ + if (type() & SignalProperty && d->object) + return d->object->metaObject()->method(d->core.coreIndex); + else + return QMetaMethod(); +} + + +/*! + Returns the binding associated with this property, or 0 if no binding + exists. +*/ +QmlAbstractBinding *QmlMetaProperty::binding() const +{ + if (!isProperty() || (type() & Attached) || !d->object) + return 0; + + QmlDeclarativeData *data = QmlDeclarativeData::get(d->object); + if (!data) + return 0; + + if (!data->hasBindingBit(d->core.coreIndex)) + return 0; + + QmlAbstractBinding *binding = data->bindings; + while (binding) { + // ### This wont work for value types + if (binding->propertyIndex() == d->core.coreIndex) + return binding; + binding = binding->m_nextBinding; + } + return 0; +} + +/*! + Set the binding associated with this property to \a newBinding. Returns + the existing binding (if any), otherwise 0. + + \a newBinding will be enabled, and the returned binding (if any) will be + disabled. + + Ownership of \a newBinding transfers to QML. Ownership of the return value + is assumed by the caller. + + \a flags is passed through to the binding and is used for the initial update (when + the binding sets the intial value, it will use these flags for the write). +*/ +QmlAbstractBinding * +QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding, QmlMetaProperty::WriteFlags flags) const +{ + if (!isProperty() || (type() & Attached) || !d->object) { + if (newBinding) + newBinding->destroy(); + return 0; + } + + return d->setBinding(d->object, d->core, newBinding, flags); +} + +QmlAbstractBinding * +QmlMetaPropertyPrivate::setBinding(QObject *object, const QmlPropertyCache::Data &core, + QmlAbstractBinding *newBinding, QmlMetaProperty::WriteFlags flags) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object, 0 != newBinding); + + if (data && data->hasBindingBit(core.coreIndex)) { + QmlAbstractBinding *binding = data->bindings; + while (binding) { + // ### This wont work for value types + if (binding->propertyIndex() == core.coreIndex) { + binding->setEnabled(false); + + if (newBinding) + newBinding->setEnabled(true, flags); + + return binding; // ### QmlAbstractBinding; + } + + binding = binding->m_nextBinding; + } + } + + if (newBinding) + newBinding->setEnabled(true, flags); + + return 0; +} +/*! + Returns the expression associated with this signal property, or 0 if no + signal expression exists. +*/ +QmlExpression *QmlMetaProperty::signalExpression() const +{ + if (!(type() & SignalProperty)) + return 0; + + const QObjectList &children = d->object->children(); + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + + QmlBoundSignal *signal = QmlBoundSignal::cast(child); + if (signal && signal->index() == coreIndex()) + return signal->expression(); + } + + return 0; +} + +/*! + Set the signal expression associated with this signal property to \a expr. + Returns the existing signal expression (if any), otherwise 0. + + Ownership of \a expr transfers to QML. Ownership of the return value is + assumed by the caller. +*/ +QmlExpression *QmlMetaProperty::setSignalExpression(QmlExpression *expr) const +{ + if (!(type() & SignalProperty)) { + delete expr; + return 0; + } + + const QObjectList &children = d->object->children(); + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + + QmlBoundSignal *signal = QmlBoundSignal::cast(child); + if (signal && signal->index() == coreIndex()) + return signal->setExpression(expr); + } + + if (expr) { + QmlBoundSignal *signal = new QmlBoundSignal(d->object, method(), d->object); + return signal->setExpression(expr); + } else { + return 0; + } +} + +QMetaMethod QmlMetaPropertyPrivate::findSignal(QObject *obj, const QString &name) +{ + const QMetaObject *mo = obj->metaObject(); + + int methods = mo->methodCount(); + for (int ii = methods - 1; ii >= 0; --ii) { + QMetaMethod method = mo->method(ii); + QString methodName = QString::fromUtf8(method.signature()); + int idx = methodName.indexOf(QLatin1Char('(')); + methodName = methodName.left(idx); + + if (methodName == name) + return method; + } + return QMetaMethod(); +} + +QObject *QmlMetaPropertyPrivate::attachedObject() const +{ + if (attachedFunc == -1) + return 0; + else + return qmlAttachedPropertiesObjectById(attachedFunc, object); +} + +/*! + Returns the property value. +*/ +QVariant QmlMetaProperty::read() const +{ + if (!d->object) + return QVariant(); + + if (type() & SignalProperty) { + + return QVariant(); + + } else if (type() & Property || type() & Attached) { + + return d->readValueProperty(); + + } + return QVariant(); +} + +QVariant QmlMetaPropertyPrivate::readValueProperty() +{ + uint type = q->type(); + if (type & QmlMetaProperty::Attached) { + + return QVariant::fromValue(attachedObject()); + + } else if(type & QmlMetaProperty::ValueTypeProperty) { + + QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[core.propType]; + else valueType = QmlValueTypeFactory::valueType(core.propType); + Q_ASSERT(valueType); + + valueType->read(object, core.coreIndex); + + QVariant rv = + valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType); + + if (!ep) delete valueType; + return rv; + + } else { + + return object->metaObject()->property(core.coreIndex).read(object.data()); + + } +} + +//### +//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC! +//### +bool QmlMetaPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags) +{ + if (!object || !prop.isWritable()) + return false; + + QVariant v = value; + if (prop.isEnumType()) { + QMetaEnum menum = prop.enumerator(); + if (v.userType() == QVariant::String +#ifdef QT3_SUPPORT + || v.userType() == QVariant::CString +#endif + ) { + if (prop.isFlagType()) + v = QVariant(menum.keysToValue(value.toByteArray())); + else + v = QVariant(menum.keyToValue(value.toByteArray())); + } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) { + int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope()) + "::" + menum.name()); + if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData()) + return false; + v = QVariant(*reinterpret_cast<const int *>(v.constData())); + } + v.convert(QVariant::Int); + } + + // the status variable is changed by qt_metacall to indicate what it did + // this feature is currently only used by QtDBus and should not be depended + // upon. Don't change it without looking into QDBusAbstractInterface first + // -1 (unchanged): normal qt_metacall, result stored in argv[0] + // changed: result stored directly in value, return the value of status + int status = -1; + void *argv[] = { v.data(), &v, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv); + return status; +} + +bool QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, + QmlMetaProperty::WriteFlags flags) +{ + // Remove any existing bindings on this property + if (!(flags & QmlMetaProperty::DontRemoveBinding)) + delete q->setBinding(0); + + bool rv = false; + uint type = q->type(); + if (type & QmlMetaProperty::ValueTypeProperty) { + QmlEnginePrivate *ep = + context?static_cast<QmlEnginePrivate *>(QObjectPrivate::get(context->engine())):0; + + QmlValueType *writeBack = 0; + if (ep) { + writeBack = ep->valueTypes[core.propType]; + } else { + writeBack = QmlValueTypeFactory::valueType(core.propType); + } + + writeBack->read(object, core.coreIndex); + + QmlPropertyCache::Data data = core; + data.coreIndex = valueType.valueTypeCoreIdx; + data.propType = valueType.valueTypePropType; + rv = write(writeBack, data, value, context, flags); + + writeBack->write(object, core.coreIndex, flags); + if (!ep) delete writeBack; + + } else { + + rv = write(object, core, value, context, flags); + + } + + return rv; +} + +bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property, + const QVariant &value, QmlContext *context, + QmlMetaProperty::WriteFlags flags) +{ + int coreIdx = property.coreIndex; + int status = -1; //for dbus + + if (property.flags & QmlPropertyCache::Data::IsEnumType) { + QMetaProperty prop = object->metaObject()->property(property.coreIndex); + QVariant v = value; + // Enum values come through the script engine as doubles + if (value.userType() == QVariant::Double) { + double integral; + double fractional = modf(value.toDouble(), &integral); + if (qFuzzyIsNull(fractional)) + v.convert(QVariant::Int); + } + return writeEnumProperty(prop, coreIdx, object, v, flags); + } + + int t = property.propType; + int vt = value.userType(); + + QmlEnginePrivate *enginePriv = 0; + if (context && context->engine()) + enginePriv = QmlEnginePrivate::get(context->engine()); + + if (t == QVariant::Url) { + + QUrl u; + bool found = false; + if (vt == QVariant::Url) { + u = value.toUrl(); + found = true; + } else if (vt == QVariant::ByteArray) { + u = QUrl(QString::fromUtf8(value.toByteArray())); + found = true; + } else if (vt == QVariant::String) { + u = QUrl(value.toString()); + found = true; + } + + if (!found) + return false; + + if (context && u.isRelative() && !u.isEmpty()) + u = context->resolvedUrl(u); + int status = -1; + void *argv[] = { &u, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); + + } else if (vt == t) { + + void *a[] = { (void *)value.constData(), 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + + } else if (qMetaTypeId<QVariant>() == t) { + + void *a[] = { (void *)&value, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + + } else if (property.flags & QmlPropertyCache::Data::IsQObjectDerived) { + + const QMetaObject *valMo = 0; + if (enginePriv) valMo = enginePriv->rawMetaObjectForType(value.userType()); + else valMo = QmlMetaType::rawMetaObjectForType(value.userType()); + + if (!valMo) + return false; + + QObject *o = *(QObject **)value.constData(); + const QMetaObject *propMo = 0; + if (enginePriv) propMo = enginePriv->rawMetaObjectForType(t); + else propMo = QmlMetaType::rawMetaObjectForType(t); + + if (o) valMo = o->metaObject(); + + if (canConvert(valMo, propMo)) { + void *args[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, + args); + } else if (!o && canConvert(propMo, valMo)) { + // In the case of a null QObject, we assign the null if there is + // any change that the null variant type could be up or down cast to + // the property type. + void *args[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, + args); + } else { + return false; + } + + } else if (property.flags & QmlPropertyCache::Data::IsQList) { + + int listType = QmlMetaType::listType(t); + QMetaProperty prop = object->metaObject()->property(property.coreIndex); + + if (value.userType() == qMetaTypeId<QList<QObject *> >()) { + const QList<QObject *> &list = + qvariant_cast<QList<QObject *> >(value); + QVariant listVar = prop.read(object); + QmlMetaType::clear(listVar); + for (int ii = 0; ii < list.count(); ++ii) { + QVariant v = QmlMetaType::fromObject(list.at(ii), listType); + QmlMetaType::append(listVar, v); + } + + } else if (vt == listType || + value.userType() == listType) { + QVariant listVar = prop.read(object); + QmlMetaType::append(listVar, value); + } + + } else if (property.flags & QmlPropertyCache::Data::IsQmlList) { + + // XXX - optimize! + QMetaProperty prop = object->metaObject()->property(property.coreIndex); + QVariant list = prop.read(object); + QmlPrivate::ListInterface *li = + *(QmlPrivate::ListInterface **)list.constData(); + + int type = li->type(); + + if (QObject *obj = QmlMetaType::toQObject(value)) { + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *objMo = obj->metaObject(); + bool found = false; + while(!found && objMo) { + if (equal(objMo, mo)) + found = true; + else + objMo = objMo->superClass(); + } + + if (!found) + return false; + + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + void *d = (void *)&obj; + li->append(d); + } + } else { + Q_ASSERT(vt != t); + + QVariant v = value; + if (v.convert((QVariant::Type)t)) { + void *a[] = { (void *)v.constData(), 0, &status, &flags}; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } else if ((uint)t >= QVariant::UserType && vt == QVariant::String) { + QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); + if (!con) + return false; + + QVariant v = con(value.toString()); + if (v.userType() == t) { + void *a[] = { (void *)v.constData(), 0, &status, &flags}; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } + } else if (vt == QVariant::String) { + bool ok = false; + QVariant v = QmlStringConverters::variantFromString(value.toString(), t, &ok); + if (!ok) + return false; + + void *a[] = { (void *)v.constData(), 0, &status, &flags}; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } else { + return false; + } + } + + return true; +} + +/*! + Set the property value to \a value. +*/ +bool QmlMetaProperty::write(const QVariant &value) const +{ + return write(value, 0); +} + +/*! + Resets the property value. +*/ +bool QmlMetaProperty::reset() const +{ + if (isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args); + return true; + } else { + return false; + } +} + +bool QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const +{ + if (d->object && type() & Property && d->core.isValid() && isWritable()) + return d->writeValueProperty(value, flags); + else + return false; +} + +/*! + Returns true if the property has a change notifier signal, otherwise false. +*/ +bool QmlMetaProperty::hasChangedNotifier() const +{ + if (type() & Property && !(type() & Attached) && d->object) { + return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal(); + } + return false; +} + +/*! + Returns true if the property needs a change notifier signal for bindings + to remain upto date, false otherwise. + + Some properties, such as attached properties or those whose value never + changes, do not require a change notifier. +*/ +bool QmlMetaProperty::needsChangedNotifier() const +{ + return type() & Property && !(type() & Attached) && + !property().isConstant(); +} + +/*! + Connects the property's change notifier signal to the + specified \a method of the \a dest object and returns + true. Returns false if this metaproperty does not + represent a regular Qt property or if it has no + change notifier signal, or if the \a dest object does + not have the specified \a method. +*/ +bool QmlMetaProperty::connectNotifier(QObject *dest, int method) const +{ + if (!(type() & Property) || (type() & Attached) || !d->object) + return false; + + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + if (prop.hasNotifySignal()) { + return QMetaObject::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); + } else { + return false; + } +} + +/*! + Connects the property's change notifier signal to the + specified \a slot of the \a dest object and returns + true. Returns false if this metaproperty does not + represent a regular Qt property or if it has no + change notifier signal, or if the \a dest object does + not have the specified \a slot. +*/ +bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const +{ + if (!(type() & Property) || (type() & Attached) || !d->object) + return false; + + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + if (prop.hasNotifySignal()) { + QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); + return QObject::connect(d->object, signal.constData(), dest, slot); + } else { + return false; + } +} + +/*! + Return the Qt metaobject index of the property. +*/ +int QmlMetaProperty::coreIndex() const +{ + return d->core.coreIndex; +} + +/*! \internal */ +int QmlMetaProperty::valueTypeCoreIndex() const +{ + return d->valueType.valueTypeCoreIdx; +} + +Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes); + + +struct SerializedData { + QmlMetaProperty::Type type; + QmlPropertyCache::Data core; +}; + +struct ValueTypeSerializedData : public SerializedData { + QmlPropertyCache::ValueTypeData valueType; +}; + +QByteArray QmlMetaPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, + int subIndex, int subType) +{ + ValueTypeSerializedData sd; + sd.type = QmlMetaProperty::ValueTypeProperty; + sd.core.load(metaObject->property(index)); + sd.valueType.valueTypeCoreIdx = subIndex; + sd.valueType.valueTypePropType = subType; + + QByteArray rv((const char *)&sd, sizeof(sd)); + return rv; +} + +QByteArray QmlMetaPropertyPrivate::saveProperty(const QMetaObject *metaObject, int index) +{ + SerializedData sd; + sd.type = QmlMetaProperty::Property; + sd.core.load(metaObject->property(index)); + + QByteArray rv((const char *)&sd, sizeof(sd)); + return rv; +} + +QmlMetaProperty +QmlMetaPropertyPrivate::restore(const QByteArray &data, QObject *object, QmlContext *ctxt) +{ + QmlMetaProperty prop; + + if (data.isEmpty()) + return prop; + + prop.d->object = object; + prop.d->context = ctxt; + + const SerializedData *sd = (const SerializedData *)data.constData(); + if (sd->type == QmlMetaProperty::Property) { + prop.d->core = sd->core; + } else if(sd->type == QmlMetaProperty::ValueTypeProperty) { + const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd; + prop.d->core = vt->core; + prop.d->valueType = vt->valueType; + } + + return prop; +} + +/*! + \internal + + Creates a QmlMetaProperty for the property \a name of \a obj. Unlike + the QmlMetaProperty(QObject*, QString, QmlContext*) constructor, this static function + will correctly handle dot properties, including value types and attached properties. +*/ +QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, + const QString &name, + QmlContext *context) +{ + QmlTypeNameCache *typeNameCache = context?QmlContextPrivate::get(context)->imports:0; + + QStringList path = name.split(QLatin1Char('.')); + QObject *object = obj; + + for (int jj = 0; jj < path.count() - 1; ++jj) { + const QString &pathName = path.at(jj); + + if (QmlTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) { + if (data->type) { + QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) + return QmlMetaProperty(); + object = qmlAttachedPropertiesObjectById(data->type->index(), object); + if (!object) + return QmlMetaProperty(); + continue; + } else { + Q_ASSERT(data->typeNamespace); + ++jj; + data = data->typeNamespace->data(path.at(jj)); + if (!data || !data->type) + return QmlMetaProperty(); + QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) + return QmlMetaProperty(); + object = qmlAttachedPropertiesObjectById(data->type->index(), object); + if (!object) + return QmlMetaProperty(); + continue; + } + } + + QmlMetaProperty prop(object, pathName, context); + + if (jj == path.count() - 2 && prop.propertyType() < (int)QVariant::UserType && + qmlValueTypes()->valueTypes[prop.propertyType()]) { + // We're now at a value type property. We can use a global valuetypes array as we + // never actually use the objects, just look up their properties. + QObject *typeObject = + qmlValueTypes()->valueTypes[prop.propertyType()]; + int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData()); + if (idx == -1) + return QmlMetaProperty(); + QMetaProperty vtProp = typeObject->metaObject()->property(idx); + + QmlMetaProperty p = prop; + p.d->valueType.valueTypeCoreIdx = idx; + p.d->valueType.valueTypePropType = vtProp.userType(); + return p; + } + + QObject *objVal = QmlMetaType::toQObject(prop.read()); + if (!objVal) + return QmlMetaProperty(); + object = objVal; + } + + const QString &propName = path.last(); + QmlMetaProperty prop(object, propName, context); + if (!prop.isValid()) + return QmlMetaProperty(); + else + return prop; +} + +/*! + Returns true if lhs and rhs refer to the same metaobject data +*/ +bool QmlMetaPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs) +{ + return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata); +} + +/*! + Returns true if from inherits to. +*/ +bool QmlMetaPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to) +{ + if (from && to == &QObject::staticMetaObject) + return true; + + while (from) { + if (equal(from, to)) + return true; + from = from->superClass(); + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h new file mode 100644 index 0000000..240f5a2 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETAPROPERTY_H +#define QMLMETAPROPERTY_H + +#include <QtCore/qmetaobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlAbstractBinding; +class QmlExpression; +class QStringList; +class QVariant; +struct QMetaObject; +class QmlContext; +class QmlEngine; + +class QmlMetaPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlMetaProperty +{ +public: + enum PropertyCategory { + Unknown, + InvalidProperty, + Bindable, + List, + QmlList, //XXX + Object, + Normal + }; + QmlMetaProperty(); + QmlMetaProperty(QObject *); + QmlMetaProperty(QObject *, const QString &); + QmlMetaProperty(QObject *, QmlContext *); + QmlMetaProperty(QObject *, const QString &, QmlContext *); + QmlMetaProperty(const QmlMetaProperty &); + QmlMetaProperty &operator=(const QmlMetaProperty &); + ~QmlMetaProperty(); + + QString name() const; + + QVariant read() const; + bool write(const QVariant &) const; + enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02 }; + Q_DECLARE_FLAGS(WriteFlags, WriteFlag) + bool write(const QVariant &, QmlMetaProperty::WriteFlags) const; + bool reset() const; + + bool hasChangedNotifier() const; + bool needsChangedNotifier() const; + bool connectNotifier(QObject *dest, const char *slot) const; + bool connectNotifier(QObject *dest, int method) const; + + QMetaMethod method() const; + + enum Type { Invalid = 0x00, + Property = 0x01, + SignalProperty = 0x02, + Default = 0x08, + Attached = 0x10, + ValueTypeProperty = 0x20 }; + + Type type() const; + bool isProperty() const; + bool isDefault() const; + bool isWritable() const; + bool isDesignable() const; + bool isResettable() const; + bool isValid() const; + QObject *object() const; + + PropertyCategory propertyCategory() const; + + int propertyType() const; + const char *propertyTypeName() const; + + bool operator==(const QmlMetaProperty &) const; + + QMetaProperty property() const; + + QmlAbstractBinding *binding() const; + QmlAbstractBinding *setBinding(QmlAbstractBinding *, + QmlMetaProperty::WriteFlags flags = QmlMetaProperty::DontRemoveBinding) const; + + QmlExpression *signalExpression() const; + QmlExpression *setSignalExpression(QmlExpression *) const; + + static QmlMetaProperty createProperty(QObject *, const QString &, QmlContext *context=0); + + int coreIndex() const; + int valueTypeCoreIndex() const; +private: + friend class QmlEnginePrivate; + friend class QmlMetaPropertyPrivate; + QmlMetaPropertyPrivate *d; +}; +typedef QList<QmlMetaProperty> QmlMetaProperties; + Q_DECLARE_OPERATORS_FOR_FLAGS(QmlMetaProperty::WriteFlags) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLMETAPROPERTY_H diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h new file mode 100644 index 0000000..97b5208 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETAPROPERTY_P_H +#define QMLMETAPROPERTY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlmetaproperty.h" + +#include "qmlpropertycache_p.h" +#include "qmlguard_p.h" + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlMetaPropertyPrivate +{ +public: + QmlMetaPropertyPrivate() + : q(0), context(0), object(0), isDefaultProperty(false), isNameCached(false), + attachedFunc(-1) {} + + QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) + : q(0), context(other.context), object(other.object), + isDefaultProperty(other.isDefaultProperty), isNameCached(other.isNameCached), + core(other.core), nameCache(other.nameCache), + valueType(other.valueType), attachedFunc(other.attachedFunc) {} + + QmlMetaProperty *q; + QmlContext *context; + QmlGuard<QObject> object; + + bool isDefaultProperty:1; + bool isNameCached:1; + QmlPropertyCache::Data core; + QString nameCache; + + // Describes the "virtual" value-type sub-property. + QmlPropertyCache::ValueTypeData valueType; + + // The attached property accessor + int attachedFunc; + + void initProperty(QObject *obj, const QString &name); + void initDefault(QObject *obj); + + QObject *attachedObject() const; + QMetaMethod findSignal(QObject *, const QString &); + + int propertyType() const; + QmlMetaProperty::PropertyCategory propertyCategory() const; + + QVariant readValueProperty(); + bool writeValueProperty(const QVariant &, QmlMetaProperty::WriteFlags); + static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags); + static bool write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *, + QmlMetaProperty::WriteFlags flags = 0); + static QmlAbstractBinding *setBinding(QObject *, const QmlPropertyCache::Data &, QmlAbstractBinding *, + QmlMetaProperty::WriteFlags flags = QmlMetaProperty::DontRemoveBinding); + + static QByteArray saveValueType(const QMetaObject *, int, int, int); + static QByteArray saveProperty(const QMetaObject *, int); + static QmlMetaProperty restore(const QByteArray &, QObject *, QmlContext * = 0); + + static bool equal(const QMetaObject *, const QMetaObject *); + static bool canConvert(const QMetaObject *from, const QMetaObject *to); +}; + +QT_END_NAMESPACE + +#endif // QMLMETAPROPERTY_P_H diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp new file mode 100644 index 0000000..d9c007d --- /dev/null +++ b/src/declarative/qml/qmlmetatype.cpp @@ -0,0 +1,1369 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetatype.h" + +#include "qmlproxymetaobject_p.h" +#include "qmlcustomparser_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbitarray.h> +#include <QtCore/qreadwritelock.h> +#include <qmetatype.h> +#include <qobjectdefs.h> +#include <qdatetime.h> +#include <qbytearray.h> +#include <qreadwritelock.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvector.h> +#include <qlocale.h> +#include <QtCore/qcryptographichash.h> +#include <QtScript/qscriptvalue.h> + +#include <ctype.h> + +#ifdef QT_BOOTSTRAPPED +# ifndef QT_NO_GEOM_VARIANT +# define QT_NO_GEOM_VARIANT +# endif +#else +# include <qbitarray.h> +# include <qurl.h> +# include <qvariant.h> +#endif + +#ifndef QT_NO_GEOM_VARIANT +# include <qsize.h> +# include <qpoint.h> +# include <qrect.h> +# include <qline.h> +# include <qvector3d.h> +#endif +#define NS(x) QT_PREPEND_NAMESPACE(x) + +QT_BEGIN_NAMESPACE + +struct QmlMetaTypeData +{ + ~QmlMetaTypeData(); + QList<QmlType *> types; + typedef QHash<int, QmlType *> Ids; + Ids idToType; + typedef QHash<QByteArray, QmlType *> Names; + Names nameToType; + typedef QHash<const QMetaObject *, QmlType *> MetaObjects; + MetaObjects metaObjectToType; + typedef QHash<int, QmlMetaType::StringConverter> StringConverters; + StringConverters stringConverters; + + QBitArray objects; + QBitArray interfaces; + QBitArray qmllists; + QBitArray lists; +}; +Q_GLOBAL_STATIC(QmlMetaTypeData, metaTypeData) +Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) + +QmlMetaTypeData::~QmlMetaTypeData() +{ + for (int i = 0; i < types.count(); ++i) + delete types.at(i); +} + +class QmlTypePrivate +{ +public: + QmlTypePrivate(); + + void init() const; + + bool m_isInterface : 1; + const char *m_iid; + QByteArray m_name; + int m_version_maj; + int m_version_min; + int m_typeId; int m_listId; int m_qmlListId; + QmlPrivate::Func m_opFunc; + const QMetaObject *m_baseMetaObject; + QmlAttachedPropertiesFunc m_attachedPropertiesFunc; + const QMetaObject *m_attachedPropertiesType; + int m_parserStatusCast; + int m_propertyValueSourceCast; + int m_propertyValueInterceptorCast; + QmlPrivate::CreateFunc m_extFunc; + const QMetaObject *m_extMetaObject; + int m_index; + QmlCustomParser *m_customParser; + mutable volatile bool m_isSetup:1; + mutable QList<QmlProxyMetaObject::ProxyData> m_metaObjects; +}; + +QmlTypePrivate::QmlTypePrivate() +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_qmlListId(0), + m_opFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), + m_parserStatusCast(-1), m_propertyValueSourceCast(-1), m_propertyValueInterceptorCast(-1), + m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), m_isSetup(false) +{ +} + + +QmlType::QmlType(int type, int listType, int qmlListType, + QmlPrivate::Func opFunc, const char *iid, int index) +: d(new QmlTypePrivate) +{ + d->m_isInterface = true; + d->m_iid = iid; + d->m_typeId = type; + d->m_listId = listType; + d->m_qmlListId = qmlListType; + d->m_opFunc = opFunc; + d->m_index = index; + d->m_isSetup = true; + d->m_version_maj = 0; + d->m_version_min = 0; +} + +QmlType::QmlType(int type, int listType, int qmlListType, + QmlPrivate::Func opFunc, const char *qmlName, + int version_maj, int version_min, + const QMetaObject *metaObject, + QmlAttachedPropertiesFunc attachedPropertiesFunc, + const QMetaObject *attachedType, + int parserStatusCast, int propertyValueSourceCast, int propertyValueInterceptorCast, + QmlPrivate::CreateFunc extFunc, + const QMetaObject *extMetaObject, int index, + QmlCustomParser *customParser) +: d(new QmlTypePrivate) +{ + d->m_name = qmlName; + d->m_version_maj = version_maj; + d->m_version_min = version_min; + d->m_typeId = type; + d->m_listId = listType; + d->m_qmlListId = qmlListType; + d->m_opFunc = opFunc; + d->m_baseMetaObject = metaObject; + d->m_attachedPropertiesFunc = attachedPropertiesFunc; + d->m_attachedPropertiesType = attachedType; + d->m_parserStatusCast = parserStatusCast; + d->m_propertyValueSourceCast = propertyValueSourceCast; + d->m_propertyValueInterceptorCast = propertyValueInterceptorCast; + d->m_extFunc = extFunc; + d->m_index = index; + d->m_customParser = customParser; + + if (extMetaObject) + d->m_extMetaObject = extMetaObject; +} + +QmlType::~QmlType() +{ + delete d->m_customParser; + delete d; +} + +int QmlType::majorVersion() const +{ + return d->m_version_maj; +} + +int QmlType::minorVersion() const +{ + return d->m_version_min; +} + +bool QmlType::availableInVersion(int vmajor, int vminor) const +{ + return vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min); +} + +void QmlTypePrivate::init() const +{ + if (m_isSetup) return; + + QWriteLocker lock(metaTypeDataLock()); + if (m_isSetup) + return; + + // Setup extended meta object + // XXX - very inefficient + const QMetaObject *mo = m_baseMetaObject; + if (m_extFunc) { + QMetaObject *mmo = new QMetaObject; + *mmo = *m_extMetaObject; + mmo->d.superdata = mo; + QmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 }; + m_metaObjects << data; + } + + mo = mo->d.superdata; + while(mo) { + QmlType *t = metaTypeData()->metaObjectToType.value(mo); + if (t) { + if (t->d->m_extFunc) { + QMetaObject *mmo = new QMetaObject; + *mmo = *t->d->m_extMetaObject; + mmo->d.superdata = m_baseMetaObject; + if (!m_metaObjects.isEmpty()) + m_metaObjects.last().metaObject->d.superdata = mmo; + QmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 }; + m_metaObjects << data; + } + } + mo = mo->d.superdata; + } + + for (int ii = 0; ii < m_metaObjects.count(); ++ii) { + m_metaObjects[ii].propertyOffset = + m_metaObjects.at(ii).metaObject->propertyOffset(); + m_metaObjects[ii].methodOffset = + m_metaObjects.at(ii).metaObject->methodOffset(); + } + + m_isSetup = true; + lock.unlock(); +} + +QByteArray QmlType::typeName() const +{ + if (d->m_baseMetaObject) + return d->m_baseMetaObject->className(); + else + return QByteArray(); +} + +QByteArray QmlType::qmlTypeName() const +{ + return d->m_name; +} + +QObject *QmlType::create() const +{ + d->init(); + + QVariant v; + QObject *rv = 0; + d->m_opFunc(QmlPrivate::Create, 0, v, v, (void **)&rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QmlProxyMetaObject(rv, &d->m_metaObjects); + + return rv; +} + +QmlCustomParser *QmlType::customParser() const +{ + return d->m_customParser; +} + +bool QmlType::isInterface() const +{ + return d->m_isInterface; +} + +int QmlType::typeId() const +{ + return d->m_typeId; +} + +int QmlType::qListTypeId() const +{ + return d->m_listId; +} + +int QmlType::qmlListTypeId() const +{ + return d->m_qmlListId; +} + +void QmlType::listClear(const QVariant &list) +{ + Q_ASSERT(list.userType() == qListTypeId()); + QVariant arg; + d->m_opFunc(QmlPrivate::Clear, 0, list, arg, 0); +} + +void QmlType::listAppend(const QVariant &list, const QVariant &item) +{ + Q_ASSERT(list.userType() == qListTypeId()); + d->m_opFunc(QmlPrivate::Append, 0, list, item, 0); +} + +QVariant QmlType::listAt(const QVariant &list, int idx) +{ + Q_ASSERT(list.userType() == qListTypeId()); + QVariant rv; + void *ptr = (void *)&rv; + d->m_opFunc(QmlPrivate::Value, idx, list, QVariant(), &ptr); + return rv; +} + +int QmlType::listCount(const QVariant &list) +{ + Q_ASSERT(list.userType() == qListTypeId()); + return d->m_opFunc(QmlPrivate::Length, 0, list, QVariant(), 0); +} + +const QMetaObject *QmlType::metaObject() const +{ + d->init(); + + if (d->m_metaObjects.isEmpty()) + return d->m_baseMetaObject; + else + return d->m_metaObjects.first().metaObject; + +} + +const QMetaObject *QmlType::baseMetaObject() const +{ + return d->m_baseMetaObject; +} + +QmlAttachedPropertiesFunc QmlType::attachedPropertiesFunction() const +{ + return d->m_attachedPropertiesFunc; +} + +const QMetaObject *QmlType::attachedPropertiesType() const +{ + return d->m_attachedPropertiesType; +} + +int QmlType::parserStatusCast() const +{ + return d->m_parserStatusCast; +} + +int QmlType::propertyValueSourceCast() const +{ + return d->m_propertyValueSourceCast; +} + +int QmlType::propertyValueInterceptorCast() const +{ + return d->m_propertyValueInterceptorCast; +} + +QVariant QmlType::fromObject(QObject *obj) const +{ + QVariant rv; + QVariant *v_ptr = &rv; + QVariant vobj = QVariant::fromValue(obj); + d->m_opFunc(QmlPrivate::FromObject, 0, QVariant(), vobj, (void **)&v_ptr); + return rv; +} + +const char *QmlType::interfaceIId() const +{ + return d->m_iid; +} + +int QmlType::index() const +{ + return d->m_index; +} + +int QmlMetaType::registerInterface(const QmlPrivate::MetaTypeIds &id, + QmlPrivate::Func listFunction, + const char *iid) +{ + QWriteLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + int index = data->types.count(); + + QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, + listFunction, iid, index); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(type->qmlListTypeId(), type); + // XXX No insertMulti, so no multi-version interfaces? + if (!type->qmlTypeName().isEmpty()) + data->nameToType.insert(type->qmlTypeName(), type); + + if (data->interfaces.size() < id.typeId) + data->interfaces.resize(id.typeId + 16); + if (data->qmllists.size() < id.qmlListId) + data->qmllists.resize(id.qmlListId + 16); + if (data->lists.size() < id.listId) + data->lists.resize(id.listId + 16); + data->interfaces.setBit(id.typeId, true); + data->qmllists.setBit(id.qmlListId, true); + data->lists.setBit(id.listId, true); + + return index; +} + +int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Func func, + const char *uri, int version_maj, int version_min, const char *cname, + const QMetaObject *mo, QmlAttachedPropertiesFunc attach, const QMetaObject *attachMo, + int pStatus, int object, int valueSource, int valueInterceptor, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *parser) +{ + Q_UNUSED(object); + + if (cname) { + for (int ii = 0; cname[ii]; ++ii) { + if (!isalnum(cname[ii])) { + qWarning("QmlMetaType: Invalid QML name %s", cname); + return -1; + } + } + } + + QWriteLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + int index = data->types.count(); + + QByteArray name = uri; + if (uri) + name += '/'; + name += cname; + + QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, + func, name, version_maj, version_min, mo, attach, attachMo, pStatus, + valueSource, valueInterceptor, extFunc, extmo, index, parser); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(type->qmlListTypeId(), type); + + if (!type->qmlTypeName().isEmpty()) + data->nameToType.insertMulti(type->qmlTypeName(), type); + + data->metaObjectToType.insert(type->baseMetaObject(), type); + + if (data->objects.size() <= id.typeId) + data->objects.resize(id.typeId + 16); + if (data->qmllists.size() <= id.qmlListId) + data->qmllists.resize(id.qmlListId + 16); + if (data->lists.size() <= id.listId) + data->lists.resize(id.listId + 16); + data->objects.setBit(id.typeId, true); + data->qmllists.setBit(id.qmlListId, true); + data->lists.setBit(id.listId, true); + + return index; +} + +int QmlMetaType::qmlParserStatusCast(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type->parserStatusCast(); + else + return -1; +} + +int QmlMetaType::qmlPropertyValueSourceCast(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type->propertyValueSourceCast(); + else + return -1; +} + +int QmlMetaType::qmlPropertyValueInterceptorCast(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type->propertyValueInterceptorCast(); + else + return -1; +} + +QObject *QmlMetaType::toQObject(const QVariant &v) +{ + if (!isObject(v.userType())) + return 0; + + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *rv = *(QObject **)v.constData(); + return rv; +} + +/* + Returns the item type for a list of type \a id. + */ +int QmlMetaType::listType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + if (type && type->qListTypeId() == id) + return type->typeId(); + else + return 0; +} + +/* + Returns the item type for a qml list of type \a id. + */ +int QmlMetaType::qmlListType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + if (type && type->qmlListTypeId() == id) + return type->typeId(); + else + return 0; +} + +bool QmlMetaType::clear(const QVariant &list) +{ + int userType = list.userType(); + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if (type && type->qListTypeId() == userType) { + type->listClear(list); + return true; + } else { + return false; + } +} + +bool QmlMetaType::append(const QVariant &list, const QVariant &item) +{ + int userType = list.userType(); + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if (type && type->qListTypeId() == userType && + item.userType() == type->typeId()) { + type->listAppend(list, item); + return true; + } else { + return false; + } +} + +QVariant QmlMetaType::fromObject(QObject *obj, int typeId) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->idToType.value(typeId); + if (type && type->typeId() == typeId) + return type->fromObject(obj); + else + return QVariant(); +} + +const QMetaObject *QmlMetaType::rawMetaObjectForType(int id) +{ + if (id == QMetaType::QObjectStar) + return &QObject::staticMetaObject; + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->idToType.value(id); + if (type && type->typeId() == id) + return type->baseMetaObject(); + else + return 0; +} + +const QMetaObject *QmlMetaType::metaObjectForType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + lock.unlock(); + + if (type && type->typeId() == id) + return type->metaObject(); + else + return 0; +} + +int QmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->metaObjectToType.value(mo); + if (type && type->attachedPropertiesFunction()) + return type->index(); + else + return -1; +} + +QmlAttachedPropertiesFunc QmlMetaType::attachedPropertiesFuncById(int id) +{ + if (id < 0) + return 0; + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return data->types.at(id)->attachedPropertiesFunction(); +} + +QMetaProperty QmlMetaType::defaultProperty(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultProperty"); + if (-1 == idx) + return QMetaProperty(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaProperty(); + + idx = metaObject->indexOfProperty(info.value()); + if (-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +QMetaProperty QmlMetaType::defaultProperty(QObject *obj) +{ + if (!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultProperty(metaObject); +} + +QMetaMethod QmlMetaType::defaultMethod(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultMethod"); + if (-1 == idx) + return QMetaMethod(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaMethod(); + + idx = metaObject->indexOfMethod(info.value()); + if (-1 == idx) + return QMetaMethod(); + + return metaObject->method(idx); +} + +QMetaMethod QmlMetaType::defaultMethod(QObject *obj) +{ + if (!obj) + return QMetaMethod(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultMethod(metaObject); +} + +/*! + */ +QMetaProperty QmlMetaType::property(QObject *obj, const QByteArray &bname) +{ + return property(obj, bname.constData()); +} + +/*! + */ +QMetaProperty QmlMetaType::property(QObject *obj, const char *name) +{ + if (!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + + int idx = metaObject->indexOfProperty(name); + if (-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +QmlMetaType::TypeCategory QmlMetaType::typeCategory(int userType) +{ + if (userType < 0) + return Unknown; + if (userType == QMetaType::QObjectStar) + return Object; + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + if (userType < data->objects.size() && data->objects.testBit(userType)) + return Object; + else if (userType < data->qmllists.size() && data->qmllists.testBit(userType)) + return QmlList; + else if (userType < data->lists.size() && data->lists.testBit(userType)) + return List; + else + return Unknown; +} + +bool QmlMetaType::isObject(int userType) +{ + if (userType == QMetaType::QObjectStar) + return true; + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); +} + +bool QmlMetaType::isInterface(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); +} + +const char *QmlMetaType::interfaceIId(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if (type && type->isInterface() && type->typeId() == userType) + return type->interfaceIId(); + else + return 0; +} + +bool QmlMetaType::isQmlList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->qmllists.size() && data->qmllists.testBit(userType); +} + +bool QmlMetaType::isList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); +} + +bool QmlMetaType::isList(const QVariant &v) +{ + return (v.type() == QVariant::UserType && isList(v.userType())); +} + +int QmlMetaType::listCount(const QVariant &v) +{ + int userType = v.userType(); + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + + if (type && type->qListTypeId() == userType) + return type->listCount(v); + else + return 0; +} + +QVariant QmlMetaType::listAt(const QVariant &v, int idx) +{ + if (idx < 0) + return QVariant(); + + int userType = v.userType(); + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + + if (type && type->qListTypeId() == userType) + return type->listAt(v, idx); + else + return QVariant(); +} + +/*! + A custom string convertor allows you to specify a function pointer that + returns a variant of \a type. For example, if you have written your own icon + class that you want to support as an object property assignable in QML: + + \code + int type = qRegisterMetaType<SuperIcon>("SuperIcon"); + QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString); + \endcode + + The function pointer must be of the form: + \code + QVariant (*StringConverter)(const QString &); + \endcode + */ +void QmlMetaType::registerCustomStringConverter(int type, StringConverter converter) +{ + QWriteLocker lock(metaTypeDataLock()); + + QmlMetaTypeData *data = metaTypeData(); + if (data->stringConverters.contains(type)) + return; + data->stringConverters.insert(type, converter); +} + +/*! + Return the custom string converter for \a type, previously installed through + registerCustomStringConverter() + */ +QmlMetaType::StringConverter QmlMetaType::customStringConverter(int type) +{ + QReadLocker lock(metaTypeDataLock()); + + QmlMetaTypeData *data = metaTypeData(); + return data->stringConverters.value(type); +} + +/*! + Returns the type (if any) of URI-qualified named \a name in version specified + by \a version_major and \a version_minor. +*/ +QmlType *QmlMetaType::qmlType(const QByteArray &name, int version_major, int version_minor) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QList<QmlType*> types = data->nameToType.values(name); + foreach (QmlType *t, types) { + // XXX version_major<0 just a kludge for QmlMetaPropertyPrivate::initProperty + if (version_major<0 || t->availableInVersion(version_major,version_minor)) + return t; + } + return 0; +} + +QmlType *QmlMetaType::qmlType(const QMetaObject *metaObject) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->metaObjectToType.value(metaObject); +} + +QList<QByteArray> QmlMetaType::qmlTypeNames() +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.keys(); +} + +QList<QmlType*> QmlMetaType::qmlTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.values(); +} + +#include <QtGui/qfont.h> +#include <QtGui/qpixmap.h> +#include <QtGui/qbrush.h> +#include <QtGui/qcolor.h> +#include <QtGui/qpalette.h> +#include <QtGui/qicon.h> +#include <QtGui/qimage.h> +#include <QtGui/qpolygon.h> +#include <QtGui/qregion.h> +#include <QtGui/qbitmap.h> +#include <QtGui/qcursor.h> +#include <QtGui/qsizepolicy.h> +#include <QtGui/qkeysequence.h> +#include <QtGui/qpen.h> + +//#include <QtGui/qtextlength.h> +#include <QtGui/qtextformat.h> +#include <QtGui/qmatrix.h> +#include <QtGui/qtransform.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> + +Q_DECLARE_METATYPE(QScriptValue); + +/*! + Copies \a copy into \a data, assuming they both are of type \a type. If + \a copy is zero, a default type is copied. Returns true if the copy was + successful and false if not. + + \note This should move into QMetaType once complete + +*/ +bool QmlMetaType::copy(int type, void *data, const void *copy) +{ + if (copy) { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = *static_cast<void* const *>(copy); + return true; + case QMetaType::Long: + *static_cast<long *>(data) = *static_cast<const long*>(copy); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = *static_cast<const int*>(copy); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = *static_cast<const short*>(copy); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = *static_cast<const char*>(copy); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = *static_cast<const ulong*>(copy); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = *static_cast<const uint*>(copy); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = *static_cast<const qlonglong*>(copy); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = *static_cast<const qulonglong*>(copy); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = *static_cast<const ushort*>(copy); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = *static_cast<const uchar*>(copy); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = *static_cast<const bool*>(copy); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = *static_cast<const float*>(copy); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = *static_cast<const double*>(copy); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = *static_cast<const NS(QChar)*>(copy); + return true; + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = *static_cast<const NS(QVariantMap)*>(copy); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = *static_cast<const NS(QVariantHash)*>(copy); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = *static_cast<const NS(QVariantList)*>(copy); + return true; + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = *static_cast<const NS(QByteArray)*>(copy); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = *static_cast<const NS(QString)*>(copy); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = *static_cast<const NS(QStringList)*>(copy); + return true; + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = *static_cast<const NS(QBitArray)*>(copy); + return true; + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = *static_cast<const NS(QDate)*>(copy); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = *static_cast<const NS(QTime)*>(copy); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = *static_cast<const NS(QDateTime)*>(copy); + return true; + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = *static_cast<const NS(QUrl)*>(copy); + return true; + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = *static_cast<const NS(QLocale)*>(copy); + return true; + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = *static_cast<const NS(QRect)*>(copy); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = *static_cast<const NS(QRectF)*>(copy); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = *static_cast<const NS(QSize)*>(copy); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = *static_cast<const NS(QSizeF)*>(copy); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = *static_cast<const NS(QLine)*>(copy); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = *static_cast<const NS(QLineF)*>(copy); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = *static_cast<const NS(QPoint)*>(copy); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = *static_cast<const NS(QPointF)*>(copy); + return true; + case QMetaType::QVector3D: + *static_cast<NS(QVector3D) *>(data) = *static_cast<const NS(QVector3D)*>(copy); + return true; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = *static_cast<const NS(QRegExp)*>(copy); + return true; +#endif + case QMetaType::Void: + return true; + + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast<NS(QColorGroup) *>(data) = *static_cast<const NS(QColorGroup)*>(copy); + return true; +#endif + + case QMetaType::QFont: + *static_cast<NS(QFont) *>(data) = *static_cast<const NS(QFont)*>(copy); + return true; + case QMetaType::QPixmap: + *static_cast<NS(QPixmap) *>(data) = *static_cast<const NS(QPixmap)*>(copy); + return true; + case QMetaType::QBrush: + *static_cast<NS(QBrush) *>(data) = *static_cast<const NS(QBrush)*>(copy); + return true; + case QMetaType::QColor: + *static_cast<NS(QColor) *>(data) = *static_cast<const NS(QColor)*>(copy); + return true; + case QMetaType::QPalette: + *static_cast<NS(QPalette) *>(data) = *static_cast<const NS(QPalette)*>(copy); + return true; + case QMetaType::QIcon: + *static_cast<NS(QIcon) *>(data) = *static_cast<const NS(QIcon)*>(copy); + return true; + case QMetaType::QImage: + *static_cast<NS(QImage) *>(data) = *static_cast<const NS(QImage)*>(copy); + return true; + case QMetaType::QPolygon: + *static_cast<NS(QPolygon) *>(data) = *static_cast<const NS(QPolygon)*>(copy); + return true; + case QMetaType::QRegion: + *static_cast<NS(QRegion) *>(data) = *static_cast<const NS(QRegion)*>(copy); + return true; + case QMetaType::QBitmap: + *static_cast<NS(QBitmap) *>(data) = *static_cast<const NS(QBitmap)*>(copy); + return true; +#ifndef QT_NO_CURSOR + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = *static_cast<const NS(QCursor)*>(copy); + return true; +#endif + case QMetaType::QSizePolicy: + *static_cast<NS(QSizePolicy) *>(data) = *static_cast<const NS(QSizePolicy)*>(copy); + return true; + case QMetaType::QKeySequence: + *static_cast<NS(QKeySequence) *>(data) = *static_cast<const NS(QKeySequence)*>(copy); + return true; + case QMetaType::QPen: + *static_cast<NS(QPen) *>(data) = *static_cast<const NS(QPen)*>(copy); + return true; + case QMetaType::QTextLength: + *static_cast<NS(QTextLength) *>(data) = *static_cast<const NS(QTextLength)*>(copy); + return true; + case QMetaType::QTextFormat: + *static_cast<NS(QTextFormat) *>(data) = *static_cast<const NS(QTextFormat)*>(copy); + return true; + case QMetaType::QMatrix: + *static_cast<NS(QMatrix) *>(data) = *static_cast<const NS(QMatrix)*>(copy); + return true; + case QMetaType::QTransform: + *static_cast<NS(QTransform) *>(data) = *static_cast<const NS(QTransform)*>(copy); + return true; + case QMetaType::QMatrix4x4: + *static_cast<NS(QMatrix4x4) *>(data) = *static_cast<const NS(QMatrix4x4)*>(copy); + return true; + case QMetaType::QVector2D: + *static_cast<NS(QVector2D) *>(data) = *static_cast<const NS(QVector2D)*>(copy); + return true; + case QMetaType::QVector4D: + *static_cast<NS(QVector4D) *>(data) = *static_cast<const NS(QVector4D)*>(copy); + return true; + case QMetaType::QQuaternion: + *static_cast<NS(QQuaternion) *>(data) = *static_cast<const NS(QQuaternion)*>(copy); + return true; + + default: + if (type == qMetaTypeId<QVariant>()) { + *static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy); + return true; + } else if (type == qMetaTypeId<QScriptValue>()) { + *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast<void **>(data) = *static_cast<void* const *>(copy); + return true; + } + break; + } + } else { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = 0; + return true; + case QMetaType::Long: + *static_cast<long *>(data) = long(0); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = int(0); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = short(0); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = char(0); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = ulong(0); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = uint(0); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = qlonglong(0); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = qulonglong(0); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = ushort(0); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = uchar(0); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = bool(false); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = float(0); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = double(); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = NS(QChar)(); + return true; + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = NS(QVariantMap)(); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = NS(QVariantHash)(); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = NS(QVariantList)(); + return true; + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = NS(QByteArray)(); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = NS(QString)(); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = NS(QStringList)(); + return true; + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = NS(QBitArray)(); + return true; + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = NS(QDate)(); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = NS(QTime)(); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = NS(QDateTime)(); + return true; + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = NS(QUrl)(); + return true; + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = NS(QLocale)(); + return true; + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = NS(QRect)(); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = NS(QRectF)(); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = NS(QSize)(); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = NS(QSizeF)(); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = NS(QLine)(); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = NS(QLineF)(); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = NS(QPoint)(); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = NS(QPointF)(); + return true; + case QMetaType::QVector3D: + *static_cast<NS(QVector3D) *>(data) = NS(QVector3D)(); + return true; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = NS(QRegExp)(); + return true; +#endif + case QMetaType::Void: + return true; + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast<NS(QColorGroup) *>(data) = NS(QColorGroup)(); + return true; +#endif + + case QMetaType::QFont: + *static_cast<NS(QFont) *>(data) = NS(QFont)(); + return true; + case QMetaType::QPixmap: + *static_cast<NS(QPixmap) *>(data) = NS(QPixmap)(); + return true; + case QMetaType::QBrush: + *static_cast<NS(QBrush) *>(data) = NS(QBrush)(); + return true; + case QMetaType::QColor: + *static_cast<NS(QColor) *>(data) = NS(QColor)(); + return true; + case QMetaType::QPalette: + *static_cast<NS(QPalette) *>(data) = NS(QPalette)(); + return true; + case QMetaType::QIcon: + *static_cast<NS(QIcon) *>(data) = NS(QIcon)(); + return true; + case QMetaType::QImage: + *static_cast<NS(QImage) *>(data) = NS(QImage)(); + return true; + case QMetaType::QPolygon: + *static_cast<NS(QPolygon) *>(data) = NS(QPolygon)(); + return true; + case QMetaType::QRegion: + *static_cast<NS(QRegion) *>(data) = NS(QRegion)(); + return true; + case QMetaType::QBitmap: + *static_cast<NS(QBitmap) *>(data) = NS(QBitmap)(); + return true; +#ifndef QT_NO_CURSOR + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = NS(QCursor)(); + return true; +#endif + case QMetaType::QSizePolicy: + *static_cast<NS(QSizePolicy) *>(data) = NS(QSizePolicy)(); + return true; + case QMetaType::QKeySequence: + *static_cast<NS(QKeySequence) *>(data) = NS(QKeySequence)(); + return true; + case QMetaType::QPen: + *static_cast<NS(QPen) *>(data) = NS(QPen)(); + return true; + case QMetaType::QTextLength: + *static_cast<NS(QTextLength) *>(data) = NS(QTextLength)(); + return true; + case QMetaType::QTextFormat: + *static_cast<NS(QTextFormat) *>(data) = NS(QTextFormat)(); + return true; + case QMetaType::QMatrix: + *static_cast<NS(QMatrix) *>(data) = NS(QMatrix)(); + return true; + case QMetaType::QTransform: + *static_cast<NS(QTransform) *>(data) = NS(QTransform)(); + return true; + case QMetaType::QMatrix4x4: + *static_cast<NS(QMatrix4x4) *>(data) = NS(QMatrix4x4)(); + return true; + case QMetaType::QVector2D: + *static_cast<NS(QVector2D) *>(data) = NS(QVector2D)(); + return true; + case QMetaType::QVector4D: + *static_cast<NS(QVector4D) *>(data) = NS(QVector4D)(); + return true; + case QMetaType::QQuaternion: + *static_cast<NS(QQuaternion) *>(data) = NS(QQuaternion)(); + return true; + default: + if (type == qMetaTypeId<QVariant>()) { + *static_cast<NS(QVariant) *>(data) = NS(QVariant)(); + return true; + } else if (type == qMetaTypeId<QScriptValue>()) { + *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)(); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast<void **>(data) = 0; + return true; + } + break; + } + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h new file mode 100644 index 0000000..e0c65c5 --- /dev/null +++ b/src/declarative/qml/qmlmetatype.h @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETATYPE_H +#define QMLMETATYPE_H + +#include "qmlprivate.h" +#include "qmlparserstatus.h" +#include "qmlpropertyvaluesource.h" +#include "qmlpropertyvalueinterceptor.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <QtCore/qbitarray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlType; +class QmlCustomParser; +class Q_DECLARATIVE_EXPORT QmlMetaType +{ +public: + static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, int vmaj, int vmin, const char *qmlName, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int pStatus, int object, int valueSource, int valueInterceptor, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *); + static int registerInterface(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *); + + static bool copy(int type, void *data, const void *copy = 0); + + static QList<QByteArray> qmlTypeNames(); + static QList<QmlType*> qmlTypes(); + + static QmlType *qmlType(const QByteArray &, int, int); + static QmlType *qmlType(const QMetaObject *); + + static QMetaProperty defaultProperty(const QMetaObject *); + static QMetaProperty defaultProperty(QObject *); + static QMetaMethod defaultMethod(const QMetaObject *); + static QMetaMethod defaultMethod(QObject *); + static QMetaProperty property(QObject *, const QByteArray &); + static QMetaProperty property(QObject *, const char *); + static QObject *toQObject(const QVariant &); + static int qmlParserStatusCast(int); + static int qmlPropertyValueSourceCast(int); + static int qmlPropertyValueInterceptorCast(int); + static int listType(int); + static bool clear(const QVariant &); + static bool append(const QVariant &, const QVariant &); + static QVariant fromObject(QObject *, int type); + static const QMetaObject *rawMetaObjectForType(int); + static const QMetaObject *metaObjectForType(int); + static int attachedPropertiesFuncId(const QMetaObject *); + static QmlAttachedPropertiesFunc attachedPropertiesFuncById(int); + + enum TypeCategory { Unknown, Object, List, QmlList }; + static TypeCategory typeCategory(int); + + static bool isInterface(int); + static const char *interfaceIId(int); + static bool isObject(int); + static bool isList(int); + static bool isList(const QVariant &); + static bool isQmlList(int); + static int qmlListType(int); + static int listCount(const QVariant &); + static QVariant listAt(const QVariant &, int); + + typedef QVariant (*StringConverter)(const QString &); + static void registerCustomStringConverter(int, StringConverter); + static StringConverter customStringConverter(int); +}; + +class QmlTypePrivate; +class Q_DECLARATIVE_EXPORT QmlType +{ +public: + QByteArray typeName() const; + QByteArray qmlTypeName() const; + + int majorVersion() const; + int minorVersion() const; + bool availableInVersion(int vmajor, int vminor) const; + + QObject *create() const; + + QmlCustomParser *customParser() const; + + bool isInterface() const; + int typeId() const; + int qListTypeId() const; + int qmlListTypeId() const; + + void listClear(const QVariant &); + void listAppend(const QVariant &, const QVariant &); + QVariant listAt(const QVariant &, int); + int listCount(const QVariant &); + + const QMetaObject *metaObject() const; + const QMetaObject *baseMetaObject() const; + + QmlAttachedPropertiesFunc attachedPropertiesFunction() const; + const QMetaObject *attachedPropertiesType() const; + + int parserStatusCast() const; + QVariant fromObject(QObject *) const; + const char *interfaceIId() const; + int propertyValueSourceCast() const; + int propertyValueInterceptorCast() const; + + int index() const; +private: + friend class QmlMetaType; + friend class QmlTypePrivate; + friend struct QmlMetaTypeData; + QmlType(int, int, int, QmlPrivate::Func, const char *, int); + QmlType(int, int, int, QmlPrivate::Func, const char *, int, int, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int, int, int, QmlPrivate::CreateFunc, const QMetaObject *, int, QmlCustomParser *); + ~QmlType(); + + QmlTypePrivate *d; +}; + +template<typename T> +int qmlRegisterType(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op<T>, 0, 0, 0, 0, + &T::staticMetaObject, + QmlPrivate::attachedPropertiesFunc<T>(), + QmlPrivate::attachedPropertiesMetaObject<T>(), + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueInterceptor>::cast(), + 0, 0, 0); +} + +template<typename T> +int qmlRegisterType(const char *uri, int version_maj, int version_min, const char *qmlName, const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, + uri, version_maj, version_min, qmlName, + &T::staticMetaObject, + QmlPrivate::attachedPropertiesFunc<T>(), + QmlPrivate::attachedPropertiesMetaObject<T>(), + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueInterceptor>::cast(), + 0, 0, 0); +} + +template<typename T, typename E> +int qmlRegisterExtendedType(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + QmlAttachedPropertiesFunc attached = + QmlPrivate::attachedPropertiesFunc<E>(); + const QMetaObject * attachedMo = + QmlPrivate::attachedPropertiesMetaObject<E>(); + if (!attached) { + attached = QmlPrivate::attachedPropertiesFunc<T>(); + attachedMo = QmlPrivate::attachedPropertiesMetaObject<T>(); + } + + return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op<T>, 0, 0, 0, 0, + &T::staticMetaObject, attached, attachedMo, + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueInterceptor>::cast(), + &QmlPrivate::CreateParent<E>::create, &E::staticMetaObject, 0); +} + +template<typename T, typename E> +int qmlRegisterExtendedType(const char *uri, int version_maj, int version_min, const char *qmlName, const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + QmlAttachedPropertiesFunc attached = + QmlPrivate::attachedPropertiesFunc<E>(); + const QMetaObject * attachedMo = + QmlPrivate::attachedPropertiesMetaObject<E>(); + if (!attached) { + attached = QmlPrivate::attachedPropertiesFunc<T>(); + attachedMo = QmlPrivate::attachedPropertiesMetaObject<T>(); + } + + return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, + uri, version_maj, version_min, qmlName, + &T::staticMetaObject, + attached, attachedMo, + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueInterceptor>::cast(), + &QmlPrivate::CreateParent<E>::create, + &E::staticMetaObject, 0); +} + +template<typename T> +int qmlRegisterInterface(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerInterface(ids, + QmlPrivate::list_interface_op<T>, + qobject_interface_iid<T *>()); +} + +template<typename T> +int qmlRegisterCustomType(const char *uri, int version_maj, int version_min, const char *qmlName, const char *typeName, QmlCustomParser *parser) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + '*').constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, + uri, version_maj, version_min, qmlName, + &T::staticMetaObject, + QmlPrivate::attachedPropertiesFunc<T>(), + QmlPrivate::attachedPropertiesMetaObject<T>(), + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueSource>::cast(), + QmlPrivate::StaticCastSelector<T,QmlPropertyValueInterceptor>::cast(), + 0, 0, parser); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLMETATYPE_H + diff --git a/src/declarative/qml/qmlmoduleplugin.cpp b/src/declarative/qml/qmlmoduleplugin.cpp new file mode 100644 index 0000000..2f2cb25 --- /dev/null +++ b/src/declarative/qml/qmlmoduleplugin.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmoduleplugin.h" +#include "qstringlist.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlModulePlugin + \brief The QmlModulePlugin class provides an abstract base for custom QML module plugins. + \reentrant + \ingroup plugins + + The QML module plugin is a simple plugin interface that makes it + easy to add custom QML modules that can be loaded dynamically + into applications. + + Writing a QML module plugin is achieved by subclassing this base + class, reimplementing the pure virtual function keys(), and + exporting the class with the Q_EXPORT_PLUGIN2() macro. See \l{How + to Create Qt Plugins} for details. + + The strings returned by keys() should be the list of URIs of modules + that the plugin registers. + + The plugin should register QML types with qmlRegisterType() when the + defineModule() method is called. + + \sa examples/declarative/plugins +*/ + +/*! + Constructs a QML module plugin with the given \a parent. This is + invoked automatically by the Q_EXPORT_PLUGIN2() macro. +*/ +QmlModulePlugin::QmlModulePlugin(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the QML module plugin. + + You never have to call this explicitly. Qt destroys a plugin + automatically when it is no longer used. +*/ +QmlModulePlugin::~QmlModulePlugin() +{ +} + +/*! + \fn void QmlModulePlugin::defineModule(const QString& uri) + + Subclasses must override this function to register types + of the module \a uri, which will be one of the strings returned by keys(). + + The plugin registers QML types with qmlRegisterType(): + + \code + qmlRegisterType<MyClass>("com.nokia.MyModule", 1, 0, "MyType", "MyClass"); + \endcode +*/ + +void QmlModulePlugin::defineModuleOnce(const QString& uri) +{ + if (!defined.contains(uri)) { + defined += uri; + defineModule(uri); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmoduleplugin.h b/src/declarative/qml/qmlmoduleplugin.h new file mode 100644 index 0000000..384e05e --- /dev/null +++ b/src/declarative/qml/qmlmoduleplugin.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMODULEPLUGIN_H +#define QMLMODULEPLUGIN_H + +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <QtCore/qlist.h> +#include <QtCore/qset.h> +#include <QtCore/qbytearray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +struct Q_DECLARATIVE_EXPORT QmlModuleFactoryInterface : public QFactoryInterface +{ + virtual void defineModuleOnce(const QString& uri) = 0; +}; + +#define QmlModuleFactoryInterface_iid "com.nokia.Qt.QmlModuleFactoryInterface" + +Q_DECLARE_INTERFACE(QmlModuleFactoryInterface, QmlModuleFactoryInterface_iid) + + +class Q_DECLARATIVE_EXPORT QmlModulePlugin : public QObject, public QmlModuleFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QmlModuleFactoryInterface:QFactoryInterface) +public: + explicit QmlModulePlugin(QObject *parent = 0); + ~QmlModulePlugin(); + + virtual void defineModule(const QString& uri) = 0; + +private: + void defineModuleOnce(const QString& uri); + QSet<QString> defined; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLMODULEPLUGIN_H diff --git a/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp b/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp new file mode 100644 index 0000000..76f20d8 --- /dev/null +++ b/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlnetworkaccessmanagerfactory.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlNetworkAccessManagerFactory + \brief The QmlNetworkAccessManagerFactory class provides a factory for QNetworkAccessManager + + QNetworkAccessManager is used for all network access by QML. + By implementing a factory it is possible to create custom + QNetworkAccessManager with specialized caching, proxy and + cookie support. + + To implement a factory, subclass QmlNetworkAccessManagerFactory and implement + the create() method. + + If the created QNetworkAccessManager becomes invalid, due to a + change in proxy settings, for example, call the invalidate() method. + This will cause all QNetworkAccessManagers to be recreated. + + Note: the create() method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ +QmlNetworkAccessManagerFactory::~QmlNetworkAccessManagerFactory() +{ +} + +/*! + \fn QNetworkAccessManager *QmlNetworkAccessManagerFactory::create(QObject *parent) + + Implement this method to create a QNetworkAccessManager with \a parent. + This allows proxies, caching and cookie support to be setup appropriately. + + Note: this method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlnetworkaccessmanagerfactory.h b/src/declarative/qml/qmlnetworkaccessmanagerfactory.h new file mode 100644 index 0000000..ce9860f --- /dev/null +++ b/src/declarative/qml/qmlnetworkaccessmanagerfactory.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLNETWORKACCESSMANAGERFACTORY_H +#define QMLNETWORKACCESSMANAGERFACTORY_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QNetworkAccessManager; +class Q_DECLARATIVE_EXPORT QmlNetworkAccessManagerFactory +{ +public: + virtual ~QmlNetworkAccessManagerFactory(); + virtual QNetworkAccessManager *create(QObject *parent) = 0; + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLNETWORKACCESSMANAGERFACTORY_H diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp new file mode 100644 index 0000000..7bbb7df --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -0,0 +1,673 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlobjectscriptclass_p.h" + +#include "qmlengine_p.h" +#include "qmlcontext_p.h" +#include "qmldeclarativedata_p.h" +#include "qmltypenamescriptclass_p.h" +#include "qmllistscriptclass_p.h" +#include "qmlbinding.h" +#include "qmlguard_p.h" +#include "qmlvmemetaobject_p.h" + +#include <QtCore/qtimer.h> +#include <QtCore/qvarlengtharray.h> + +Q_DECLARE_METATYPE(QScriptValue); + +QT_BEGIN_NAMESPACE + +struct ObjectData : public QScriptDeclarativeClass::Object { + ObjectData(QObject *o, int t) : object(o), type(t) {} + QmlGuard<QObject> object; + int type; +}; + +/* + The QmlObjectScriptClass handles property access for QObjects + via QtScript. It is also used to provide a more useful API in + QtScript for QML. + */ +QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) +: QmlScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), +#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) + methods(bindEngine), +#endif + lastData(0), engine(bindEngine) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + m_destroy = scriptEngine->newFunction(destroy); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_toString = scriptEngine->newFunction(tostring); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); +} + +QmlObjectScriptClass::~QmlObjectScriptClass() +{ +} + +QScriptValue QmlObjectScriptClass::newQObject(QObject *object, int type) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (!object) + return newObject(scriptEngine, this, new ObjectData(object, type)); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true); + + if (!ddata->scriptValue.isValid()) { + ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object, type)); + return ddata->scriptValue; + } else if (ddata->scriptValue.engine() == QmlEnginePrivate::getScriptEngine(engine)) { + return ddata->scriptValue; + } else { + return newObject(scriptEngine, this, new ObjectData(object, type)); + } +} + +QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const +{ + return value.toQObject(); +} + +int QmlObjectScriptClass::objectType(const QScriptValue &value) const +{ + if (scriptClass(value) != this) + return QVariant::Invalid; + + Object *o = object(value); + return ((ObjectData*)(o))->type; +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + return queryProperty(toQObject(object), name, flags, 0); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, + QScriptClass::QueryFlags flags, QmlContext *evalContext, + QueryHints hints) +{ + Q_UNUSED(flags); + lastData = 0; + lastTNData = 0; + + if (name == m_destroyId.identifier || + name == m_toStringId.identifier) + return QScriptClass::HandlesReadAccess; + + if (!obj) + return 0; + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + lastData = QmlPropertyCache::property(engine, obj, name, local); + + if (lastData) + return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + + if (!(hints & SkipAttachedProperties)) { + if (!evalContext && context()) { + // Global object, QScriptContext activation object, QmlContext object + QScriptValue scopeNode = scopeChainValue(context(), -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); + + evalContext = enginePrivate->contextClass->contextFromValue(scopeNode); + } + + if (evalContext) { + QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); + + if (cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } + } + } + } + + if (!(hints & ImplicitObject)) { + local.coreIndex = -1; + lastData = &local; + return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + } + + return 0; +} + +QmlObjectScriptClass::ScriptValue +QmlObjectScriptClass::property(Object *object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QmlObjectScriptClass::ScriptValue +QmlObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (name == m_destroyId.identifier) + return Value(scriptEngine, m_destroy); + else if (name == m_toStringId.identifier) + return Value(scriptEngine, m_toString); + + if (lastData && !lastData->isValid()) + return Value(); + + Q_ASSERT(obj); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (lastTNData) { + + if (lastTNData->type) + return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type)); + else + return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace)); + + } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + if (lastData->flags & QmlPropertyCache::Data::IsVMEFunction) { + return Value(scriptEngine, ((QmlVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex)); + } else { +#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) + // Uncomment to use QtScript method call logic + // QScriptValue sobj = scriptEngine->newQObject(obj); + // return Value(scriptEngine, sobj.property(toString(name))); + return Value(scriptEngine, methods.newMethod(obj, lastData)); +#else + QScriptValue sobj = scriptEngine->newQObject(obj); + return Value(scriptEngine, sobj.property(toString(name))); +#endif + } + } else { + if (enginePriv->captureProperties && !(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } + + if ((uint)lastData->propType < QVariant::UserType) { + QmlValueType *valueType = enginePriv->valueTypes[lastData->propType]; + if (valueType) + return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType)); + } + + if (lastData->flags & QmlPropertyCache::Data::IsQList) { + return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QListPtr, lastData->propType)); + } else if (lastData->flags & QmlPropertyCache::Data::IsQmlList) { + return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QmlListPtr, lastData->propType)); + } else if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, newQObject(rv, lastData->propType)); + } else if (lastData->flags & QmlPropertyCache::Data::IsQScriptValue) { + QScriptValue rv = scriptEngine->nullValue(); + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::QReal) { + qreal rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Int) { + int rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Bool) { + bool rv = false; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::QString) { + QString rv; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::UInt) { + uint rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Float) { + float rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Double) { + double rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + return Value(scriptEngine, enginePriv->scriptValueFromVariant(var)); + } + + } +} + +void QmlObjectScriptClass::setProperty(Object *object, + const Identifier &name, + const QScriptValue &value) +{ + return setProperty(toQObject(object), name, value); +} + +void QmlObjectScriptClass::setProperty(QObject *obj, + const Identifier &name, + const QScriptValue &value, + QmlContext *evalContext) +{ + Q_UNUSED(name); + + Q_ASSERT(obj); + Q_ASSERT(lastData); + + if (!lastData->isValid()) { + QString error = QLatin1String("Cannot assign to non-existant property \"") + + toString(name) + QLatin1Char('\"'); + if (context()) + context()->throwError(error); + return; + } + + if (!(lastData->flags & QmlPropertyCache::Data::IsWritable)) { + QString error = QLatin1String("Cannot assign to read-only property \"") + + toString(name) + QLatin1Char('\"'); + if (context()) + context()->throwError(error); + return; + } + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!evalContext && context()) { + // Global object, QScriptContext activation object, QmlContext object + QScriptValue scopeNode = scopeChainValue(context(), -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass); + + evalContext = enginePriv->contextClass->contextFromValue(scopeNode); + } + + QmlAbstractBinding *delBinding = QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0); + if (delBinding) + delBinding->destroy(); + + if (value.isUndefined() && lastData->flags & QmlPropertyCache::Data::IsResettable) { + void *a[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); + } else { + // ### Can well known types be optimized? + QVariant v = QmlScriptClass::toVariant(engine, value); + QmlMetaPropertyPrivate::write(obj, *lastData, v, evalContext); + } +} + +bool QmlObjectScriptClass::isQObject() const +{ + return true; +} + +QObject *QmlObjectScriptClass::toQObject(Object *object, bool *ok) +{ + if (ok) *ok = true; + + ObjectData *data = (ObjectData*)object; + return data->object.data(); +} + +QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *) +{ + QObject* obj = context->thisObject().toQObject(); + + QString ret; + if(obj){ + QString objectName = obj->objectName(); + + ret += QString::fromUtf8(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + + if (!objectName.isEmpty()) { + ret += QLatin1String(", \""); + ret += objectName; + ret += QLatin1Char('\"'); + } + + ret += QLatin1Char(')'); + }else{ + ret += QLatin1String("null"); + } + return QScriptValue(ret); +} + +QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + if (delay > 0) + QTimer::singleShot(delay, obj, SLOT(deleteLater())); + else + obj->deleteLater(); + } + return engine->nullValue(); +} + +QStringList QmlObjectScriptClass::propertyNames(Object *object) +{ + QObject *obj = toQObject(object); + if (!obj) + return QStringList(); + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache && ddata) { cache->addref(); ddata->propertyCache = cache; } + } + + if (!cache) + return QStringList(); + + return cache->propertyNames(); +} + +#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) + +struct MethodData : public QScriptDeclarativeClass::Object { + MethodData(QObject *o, const QmlPropertyCache::Data &d) : object(o), data(d) {} + + QmlGuard<QObject> object; + QmlPropertyCache::Data data; +}; + +QmlObjectMethodScriptClass::QmlObjectMethodScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), + engine(bindEngine) +{ + setSupportsCall(true); +} + +QmlObjectMethodScriptClass::~QmlObjectMethodScriptClass() +{ +} + +QScriptValue QmlObjectMethodScriptClass::newMethod(QObject *object, const QmlPropertyCache::Data *method) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new MethodData(object, *method)); +} + +namespace { +struct MetaCallArgument { + inline MetaCallArgument(); + inline ~MetaCallArgument(); + inline void *dataPtr(); + + inline void initAsType(int type, QmlEngine *); + void fromScriptValue(int type, QmlEngine *, const QScriptValue &); + inline QScriptDeclarativeClass::Value toValue(QmlEngine *); + +private: + MetaCallArgument(const MetaCallArgument &); + + inline void cleanup(); + + char *data[16]; + int type; +}; +} + +MetaCallArgument::MetaCallArgument() +: type(QVariant::Invalid) +{ +} + +MetaCallArgument::~MetaCallArgument() +{ + cleanup(); +} + +void MetaCallArgument::cleanup() +{ + if (type == QMetaType::QString) { + ((QString *)data)->~QString(); + } else if (type == -1 || type == qMetaTypeId<QVariant>()) { + ((QVariant *)data)->~QVariant(); + } else if (type == qMetaTypeId<QScriptValue>()) { + ((QScriptValue *)data)->~QScriptValue(); + } +} + +void *MetaCallArgument::dataPtr() +{ + if (type == -1) + return ((QVariant *)data)->data(); + else + return (void *)data; +} + +void MetaCallArgument::initAsType(int callType, QmlEngine *e) +{ + if (type != 0) { cleanup(); type = 0; } + if (callType == 0) return; + + QScriptEngine *engine = QmlEnginePrivate::getScriptEngine(e); + + if (callType == qMetaTypeId<QScriptValue>()) { + new (data) QScriptValue(engine->undefinedValue()); + type = callType; + } else if (callType == QMetaType::Int || + callType == QMetaType::UInt || + callType == QMetaType::Bool || + callType == QMetaType::Double || + callType == QMetaType::Float) { + type = callType; + } else if (callType == QMetaType::QObjectStar) { + *((QObject **)data) = 0; + type = callType; + } else if (callType == QMetaType::QString) { + new (data) QString(); + type = callType; + } else if (callType == qMetaTypeId<QVariant>()) { + type = qMetaTypeId<QVariant>(); + new (data) QVariant(); + } else { + type = -1; + new (data) QVariant(callType, (void *)0); + } +} + +void MetaCallArgument::fromScriptValue(int callType, QmlEngine *engine, const QScriptValue &value) +{ + if (type != 0) { cleanup(); type = 0; } + + if (callType == qMetaTypeId<QScriptValue>()) { + new (data) QScriptValue(value); + type = qMetaTypeId<QScriptValue>(); + } else if (callType == QMetaType::Int) { + *((int *)data) = int(value.toInt32()); + type = callType; + } else if (callType == QMetaType::UInt) { + *((uint *)data) = uint(value.toUInt32()); + type = callType; + } else if (callType == QMetaType::Bool) { + *((bool *)data) = value.toBool(); + type = callType; + } else if (callType == QMetaType::Double) { + *((double *)data) = double(value.toNumber()); + type = callType; + } else if (callType == QMetaType::Float) { + *((float *)data) = float(value.toNumber()); + type = callType; + } else if (callType == QMetaType::QString) { + if (value.isNull() || value.isUndefined()) + new (data) QString(); + else + new (data) QString(value.toString()); + type = callType; + } else if (callType == QMetaType::QObjectStar) { + *((QObject **)data) = value.toQObject(); + type = callType; + } else if (callType == qMetaTypeId<QVariant>()) { + new (data) QVariant(QmlScriptClass::toVariant(engine, value)); + type = callType; + } else { + new (data) QVariant(); + type = -1; + + QVariant v = QmlScriptClass::toVariant(engine, value); + if (v.userType() == callType) { + *((QVariant *)data) = v; + } else if (v.canConvert((QVariant::Type)callType)) { + *((QVariant *)data) = v; + ((QVariant *)data)->convert((QVariant::Type)callType); + } else { + *((QVariant *)data) = QVariant(callType, (void *)0); + } + } +} + +QScriptDeclarativeClass::Value MetaCallArgument::toValue(QmlEngine *e) +{ + QScriptEngine *engine = QmlEnginePrivate::getScriptEngine(e); + + if (type == qMetaTypeId<QScriptValue>()) { + return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)data)); + } else if (type == QMetaType::Int) { + return QScriptDeclarativeClass::Value(engine, *((int *)data)); + } else if (type == QMetaType::UInt) { + return QScriptDeclarativeClass::Value(engine, *((uint *)data)); + } else if (type == QMetaType::Bool) { + return QScriptDeclarativeClass::Value(engine, *((bool *)data)); + } else if (type == QMetaType::Double) { + return QScriptDeclarativeClass::Value(engine, *((double *)data)); + } else if (type == QMetaType::Float) { + return QScriptDeclarativeClass::Value(engine, *((float *)data)); + } else if (type == QMetaType::QString) { + return QScriptDeclarativeClass::Value(engine, *((QString *)data)); + } else if (type == QMetaType::QObjectStar) { + return QScriptDeclarativeClass::Value(engine, QmlEnginePrivate::get(e)->objectClass->newQObject(*((QObject **)data))); + } else if (type == -1 || type == qMetaTypeId<QVariant>()) { + return QScriptDeclarativeClass::Value(engine, QmlEnginePrivate::get(e)->scriptValueFromVariant(*((QVariant *)data))); + } else { + return QScriptDeclarativeClass::Value(); + } +} + +QmlObjectMethodScriptClass::Value QmlObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt) +{ + MethodData *method = static_cast<MethodData *>(o); + + if (method->data.flags & QmlPropertyCache::Data::HasArguments) { + + QMetaMethod m = method->object->metaObject()->method(method->data.coreIndex); + QList<QByteArray> argTypeNames = m.parameterTypes(); + QVarLengthArray<int, 9> argTypes(argTypeNames.count()); + + // ### Cache + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + argTypes[ii] = QMetaType::type(argTypeNames.at(ii)); + if (argTypes[ii] == QVariant::Invalid) + return Value(ctxt, ctxt->throwError(QString(QLatin1String("Unknown method parameter type: %1")).arg(QLatin1String(argTypeNames.at(ii))))); + } + + if (argTypes.count() > ctxt->argumentCount()) + return Value(ctxt, ctxt->throwError("Insufficient arguments")); + + QVarLengthArray<MetaCallArgument, 9> args(argTypes.count() + 1); + args[0].initAsType(method->data.propType, engine); + + for (int ii = 0; ii < argTypes.count(); ++ii) + args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii)); + + QVarLengthArray<void *, 9> argData(args.count()); + for (int ii = 0; ii < args.count(); ++ii) + argData[ii] = args[ii].dataPtr(); + + QMetaObject::metacall(method->object, QMetaObject::InvokeMetaMethod, method->data.coreIndex, argData.data()); + + return args[0].toValue(engine); + + } else if (method->data.propType != 0) { + + MetaCallArgument arg; + arg.initAsType(method->data.propType, engine); + + void *args[] = { arg.dataPtr() }; + + QMetaObject::metacall(method->object, QMetaObject::InvokeMetaMethod, method->data.coreIndex, args); + + return arg.toValue(engine); + + } else { + + void *args[] = { 0 }; + QMetaObject::metacall(method->object, QMetaObject::InvokeMetaMethod, method->data.coreIndex, args); + return Value(); + + } + return Value(); +} + +#endif + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h new file mode 100644 index 0000000..470c555 --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLOBJECTSCRIPTCLASS_P_H +#define QMLOBJECTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlpropertycache_p.h" +#include "qmltypenamecache_p.h" + +#include <private/qmlscriptclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QScriptContext; +class QScriptEngine; +class QmlContext; + +#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) +class Q_AUTOTEST_EXPORT QmlObjectMethodScriptClass : public QScriptDeclarativeClass +{ +public: + QmlObjectMethodScriptClass(QmlEngine *); + ~QmlObjectMethodScriptClass(); + + QScriptValue newMethod(QObject *, const QmlPropertyCache::Data *); +protected: + virtual Value call(Object *, QScriptContext *); + +private: + QmlEngine *engine; +}; +#endif + +class Q_AUTOTEST_EXPORT QmlObjectScriptClass : public QmlScriptClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar); + QObject *toQObject(const QScriptValue &) const; + int objectType(const QScriptValue &) const; + + enum QueryHint { + ImplicitObject = 0x01, + SkipAttachedProperties = 0x02 + }; + Q_DECLARE_FLAGS(QueryHints, QueryHint) + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags, + QmlContext *evalContext, + QueryHints hints = 0); + + ScriptValue property(QObject *, const Identifier &); + + void setProperty(QObject *, const Identifier &name, const QScriptValue &, + QmlContext *evalContext = 0); + virtual QStringList propertyNames(Object *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual ScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + virtual bool isQObject() const; + virtual QObject *toQObject(Object *, bool *ok = 0); + +private: +#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) + QmlObjectMethodScriptClass methods; +#endif + + QmlTypeNameCache::Data *lastTNData; + QmlPropertyCache::Data *lastData; + QmlPropertyCache::Data local; + + PersistentIdentifier m_destroyId; + PersistentIdentifier m_toStringId; + QScriptValue m_destroy; + QScriptValue m_toString; + + static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine); + static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine); + + QmlEngine *engine; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlObjectScriptClass::QueryHints); + +QT_END_NAMESPACE + +#endif // QMLOBJECTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp new file mode 100644 index 0000000..02a9e70 --- /dev/null +++ b/src/declarative/qml/qmlparser.cpp @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlparser_p.h" + +#include "qmlpropertyvaluesource.h" +#include "qmlvme_p.h" +#include "qml.h" +#include "qmlcomponent_p.h" +#include "qmlcomponent.h" +#include "qmetaobjectbuilder_p.h" +#include "qmlvmemetaobject_p.h" +#include "qmlcompiler_p.h" +#include "parser/qmljsast_p.h" +#include "parser/qmljsengine_p.h" + +#include <qfxperf_p_p.h> + +#include <QStack> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +using namespace QmlJS; +using namespace QmlParser; + +QmlParser::Object::Object() +: type(-1), majorVersion(-1), minorVersion(-1), idIndex(-1), metatype(0), defaultProperty(0), parserStatusCast(-1) +{ +} + +QmlParser::Object::~Object() +{ + if (defaultProperty) defaultProperty->release(); + foreach(Property *prop, properties) + prop->release(); + foreach(Property *prop, valueProperties) + prop->release(); + foreach(Property *prop, signalProperties) + prop->release(); + foreach(Property *prop, attachedProperties) + prop->release(); + foreach(Property *prop, groupedProperties) + prop->release(); + foreach(Property *prop, valueTypeProperties) + prop->release(); + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, scriptStringProperties) + prop.first->release(); + foreach(const DynamicProperty &prop, dynamicProperties) + if (prop.defaultValue) prop.defaultValue->release(); + foreach(Object *obj, scriptBlockObjects) + obj->release(); +} + +void Object::setBindingBit(int b) +{ + while (bindingBitmask.size() < 4 * (1 + b / 32)) + bindingBitmask.append(char(0)); + + quint32 *bits = (quint32 *)bindingBitmask.data(); + bits[b / 32] |= (1 << (b % 32)); +} + +const QMetaObject *Object::metaObject() const +{ + if (!metadata.isEmpty() && metatype) + return &extObject; + else + return metatype; +} + +QmlParser::Property *Object::getDefaultProperty() +{ + if (!defaultProperty) { + defaultProperty = new Property; + defaultProperty->parent = this; + } + return defaultProperty; +} + +void QmlParser::Object::addValueProperty(Property *p) +{ + p->addref(); + valueProperties << p; +} + +void QmlParser::Object::addSignalProperty(Property *p) +{ + p->addref(); + signalProperties << p; +} + +void QmlParser::Object::addAttachedProperty(Property *p) +{ + p->addref(); + attachedProperties << p; +} + +void QmlParser::Object::addGroupedProperty(Property *p) +{ + p->addref(); + groupedProperties << p; +} + +void QmlParser::Object::addValueTypeProperty(Property *p) +{ + p->addref(); + valueTypeProperties << p; +} + +void QmlParser::Object::addScriptStringProperty(Property *p, int stack) +{ + p->addref(); + scriptStringProperties << qMakePair(p, stack); +} + + +Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) +{ + if (!properties.contains(name)) { + if (create) { + Property *property = new Property(name); + property->parent = this; + properties.insert(name, property); + } else { + return 0; + } + } + return properties[name]; +} + +QmlParser::Object::DynamicProperty::DynamicProperty() +: isDefaultProperty(false), type(Variant), defaultValue(0) +{ +} + +QmlParser::Object::DynamicProperty::DynamicProperty(const DynamicProperty &o) +: isDefaultProperty(o.isDefaultProperty), + type(o.type), + customType(o.customType), + name(o.name), + defaultValue(o.defaultValue), + location(o.location) +{ +} + +QmlParser::Object::DynamicSignal::DynamicSignal() +{ +} + +QmlParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) +: name(o.name), parameterTypes(o.parameterTypes), + parameterNames(o.parameterNames) +{ +} + +QmlParser::Object::DynamicSlot::DynamicSlot() +{ +} + +QmlParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) +: name(o.name), body(o.body), parameterNames(o.parameterNames) +{ +} + +QmlParser::Property::Property() +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false) +{ +} + +QmlParser::Property::Property(const QByteArray &n) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false), + isDeferred(false) +{ +} + +QmlParser::Property::~Property() +{ + foreach(Value *value, values) + value->release(); + if (value) value->release(); +} + +Object *QmlParser::Property::getValue() +{ + if (!value) value = new Object; + return value; +} + +void QmlParser::Property::addValue(Value *v) +{ + values << v; +} + +bool QmlParser::Property::isEmpty() const +{ + return !value && values.isEmpty(); +} + +QmlParser::Value::Value() +: type(Unknown), object(0) +{ +} + +QmlParser::Value::~Value() +{ + if (object) object->release(); +} + +QmlParser::Variant::Variant() +: t(Invalid) {} + +QmlParser::Variant::Variant(const Variant &o) +: t(o.t), d(o.d), s(o.s) +{ +} + +QmlParser::Variant::Variant(bool v) +: t(Boolean), b(v) +{ +} + +QmlParser::Variant::Variant(double v, const QString &asWritten) +: t(Number), d(v), s(asWritten) +{ +} + +QmlParser::Variant::Variant(const QString &v) +: t(String), s(v) +{ +} + +QmlParser::Variant::Variant(const QString &v, QmlJS::AST::Node *n) +: t(Script), n(n), s(v) +{ +} + +QmlParser::Variant &QmlParser::Variant::operator=(const Variant &o) +{ + t = o.t; + d = o.d; + s = o.s; + return *this; +} + +QmlParser::Variant::Type QmlParser::Variant::type() const +{ + return t; +} + +bool QmlParser::Variant::asBoolean() const +{ + return b; +} + +QString QmlParser::Variant::asString() const +{ + return s; +} + +double QmlParser::Variant::asNumber() const +{ + return d; +} + +QString QmlParser::Variant::asScript() const +{ + switch(type()) { + default: + case Invalid: + return QString(); + case Boolean: + return b?QLatin1String("true"):QLatin1String("false"); + case Number: + if (s.isEmpty()) + return QString::number(d); + else + return s; + case String: + case Script: + return s; + } +} + +QmlJS::AST::Node *QmlParser::Variant::asAST() const +{ + if (type() == Script) + return n; + else + return 0; +} + +bool QmlParser::Variant::isStringList() const +{ + if (isString()) + return true; + + if (type() != Script || !n) + return false; + + AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n); + if (!array) + return false; + + AST::ElementList *elements = array->elements; + + while (elements) { + + if (!AST::cast<AST::StringLiteral *>(elements->expression)) + return false; + + elements = elements->next; + } + + return true; +} + +QStringList QmlParser::Variant::asStringList() const +{ + QStringList rv; + if (isString()) { + rv << asString(); + return rv; + } + + AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n); + if (!array) + return rv; + + AST::ElementList *elements = array->elements; + while (elements) { + + AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression); + if (!string) + return QStringList(); + rv.append(string->value->asString()); + + elements = elements->next; + } + + return rv; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h new file mode 100644 index 0000000..aa7a762 --- /dev/null +++ b/src/declarative/qml/qmlparser_p.h @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPARSER_P_H +#define QMLPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qml.h" +#include "qmlrefcount_p.h" + +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/qstring.h> + +#include <private/qobject_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +namespace QmlJS { namespace AST { class Node; } } + +/* + XXX + + These types are created (and owned) by the QmlXmlParser and consumed by the + QmlCompiler. During the compilation phase the compiler will update some of + the fields for both its own use and for the use of the upcoming QmlDom API. + + The types are part of the generic sounding "QmlParser" namespace for legacy + reasons (there used to be more in this namespace) and will be cleaned up and + migrated into a more appropriate location shortly. +*/ +namespace QmlParser +{ + struct Location + { + Location() : line(-1), column(-1) {} + int line; + int column; + }; + + struct LocationRange + { + LocationRange() : offset(0), length(0) {} + quint32 offset; + quint32 length; + }; + + struct LocationSpan + { + Location start; + Location end; + LocationRange range; + }; + + class Property; + class Object : public QmlRefCount + { + public: + Object(); + virtual ~Object(); + + // Type of the object. The integer is an index into the + // QmlCompiledData::types array, or -1 if the object is a property + // group. + int type; + // The url of this object if it is an external type. Used by the DOM + QUrl url; + + // version information if type is defined in library or C++ + int majorVersion; + int minorVersion; + + // The fully-qualified name of this type + QByteArray typeName; + // The class name + QByteArray className; + // The id assigned to the object (if any). Set by the QmlCompiler + QString id; + // The id index assigned to the object (if any). Set by the QmlCompiler + int idIndex; + // Custom parsed data + QByteArray custom; + // Bit mask of the properties assigned bindings + QByteArray bindingBitmask; + void setBindingBit(int); + // Returns the metaobject for this type, or 0 if not available. + // Internally selectd between the metatype and extObject variables + const QMetaObject *metaObject() const; + + // The compile time metaobject for this type + const QMetaObject *metatype; + // The synthesized metaobject, if QML added signals or properties to + // this type. Otherwise null + QAbstractDynamicMetaObject extObject; + QByteArray metadata; // Generated by compiler + QByteArray synthdata; // Generated by compiler + + Property *getDefaultProperty(); + Property *getProperty(const QByteArray &name, bool create=true); + + Property *defaultProperty; + QHash<QByteArray, Property *> properties; + + QList<Object *> scriptBlockObjects; + + // Output of the compilation phase (these properties continue to exist + // in either the defaultProperty or properties members too) + void addValueProperty(Property *); + void addSignalProperty(Property *); + void addAttachedProperty(Property *); + void addGroupedProperty(Property *); + void addValueTypeProperty(Property *); + void addScriptStringProperty(Property *, int = 0); + QList<Property *> valueProperties; + QList<Property *> signalProperties; + QList<Property *> attachedProperties; + QList<Property *> groupedProperties; + QList<Property *> valueTypeProperties; + QList<QPair<Property *, int> > scriptStringProperties; + + // Script blocks that were nested under this object + struct ScriptBlock { + QStringList codes; + QStringList files; + QList<int> lineNumbers; + }; + QList<ScriptBlock> scripts; + + // The bytes to cast instances by to get to the QmlParserStatus + // interface. -1 indicates the type doesn't support this interface. + // Set by the QmlCompiler. + int parserStatusCast; + + LocationSpan location; + + struct DynamicProperty { + DynamicProperty(); + DynamicProperty(const DynamicProperty &); + + enum Type { Variant, Int, Bool, Real, String, Url, Color, Date, Alias, Custom, CustomList }; + + bool isDefaultProperty; + Type type; + QByteArray customType; + QByteArray name; + QmlParser::Property *defaultValue; + LocationSpan location; + }; + struct DynamicSignal { + DynamicSignal(); + DynamicSignal(const DynamicSignal &); + + QByteArray name; + QList<QByteArray> parameterTypes; + QList<QByteArray> parameterNames; + }; + struct DynamicSlot { + DynamicSlot(); + DynamicSlot(const DynamicSlot &); + + QByteArray name; + QString body; + QList<QByteArray> parameterNames; + }; + + // The list of dynamic properties + QList<DynamicProperty> dynamicProperties; + // The list of dynamic signals + QList<DynamicSignal> dynamicSignals; + // The list of dynamic slots + QList<DynamicSlot> dynamicSlots; + }; + + class Variant + { + public: + enum Type { + Invalid, + Boolean, + Number, + String, + Script + }; + + Variant(); + Variant(const Variant &); + Variant(bool); + Variant(double, const QString &asWritten=QString()); + Variant(const QString &); + Variant(const QString &, QmlJS::AST::Node *); + Variant &operator=(const Variant &); + + Type type() const; + + bool isBoolean() const { return type() == Boolean; } + bool isNumber() const { return type() == Number; } + bool isString() const { return type() == String; } + bool isScript() const { return type() == Script; } + bool isStringList() const; + + bool asBoolean() const; + QString asString() const; + double asNumber() const; + QString asScript() const; + QmlJS::AST::Node *asAST() const; + QStringList asStringList() const; + + private: + Type t; + union { + bool b; + double d; + QmlJS::AST::Node *n; + }; + QString s; + }; + + class Value : public QmlRefCount + { + public: + Value(); + virtual ~Value(); + + enum Type { + // The type of this value assignment is not yet known + Unknown, + // This is used as a literal property assignment + Literal, + // This is used as a property binding assignment + PropertyBinding, + // This is used as a QmlPropertyValueSource assignment + ValueSource, + // This is used as a QmlPropertyValueInterceptor assignment + ValueInterceptor, + // This is used as a property QObject assignment + CreatedObject, + // This is used as a signal object assignment + SignalObject, + // This is used as a signal expression assignment + SignalExpression, + // This is used as an id assignment only + Id + }; + Type type; + + // ### Temporary + QString primitive() const { return value.asScript(); } + + // Primitive value + Variant value; + // Object value + Object *object; + + LocationSpan location; + }; + + class Property : public QmlRefCount + { + public: + Property(); + Property(const QByteArray &n); + virtual ~Property(); + + // The Object to which this property is attached + Object *parent; + + Object *getValue(); + void addValue(Value *v); + + // The QVariant::Type of the property, or 0 (QVariant::Invalid) if + // unknown. + int type; + // The metaobject index of this property, or -1 if unknown. + int index; + + // Returns true if this is an empty property - both value and values + // are unset. + bool isEmpty() const; + // The list of values assigned to this property. Content in values + // and value are mutually exclusive + QList<Value *> values; + // The accessed property. This is used to represent dot properties. + // Content in value and values are mutually exclusive. + Object *value; + // The property name + QByteArray name; + // True if this property was accessed as the default property. + bool isDefault; + // True if the setting of this property will be deferred. Set by the + // QmlCompiler + bool isDeferred; + + LocationSpan location; + LocationRange listValueRange; + QList<int> listCommaPositions; + }; +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QmlParser::Variant) + +QT_END_HEADER + +#endif // QMLPARSER_P_H diff --git a/src/declarative/qml/qmlparserstatus.cpp b/src/declarative/qml/qmlparserstatus.cpp new file mode 100644 index 0000000..69ccfda --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlparserstatus.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlParserStatus + \brief The QmlParserStatus class provides updates on the parser state. +*/ + +/*! \internal */ +QmlParserStatus::QmlParserStatus() +: d(0) +{ +} + +/*! \internal */ +QmlParserStatus::~QmlParserStatus() +{ + if(d) + (*d) = 0; +} + +/*! + Invoked after class creation, but before any properties have been set. +*/ +void QmlParserStatus::classBegin() +{ +} + +/*! + Invoked after the root component that caused this instantiation has + completed construction. At this point all static values and binding values + have been assigned to the class. +*/ +void QmlParserStatus::componentComplete() +{ +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlparserstatus.h b/src/declarative/qml/qmlparserstatus.h new file mode 100644 index 0000000..e12c7b5 --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPARSERSTATUS_H +#define QMLPARSERSTATUS_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlParserStatus +{ +public: + QmlParserStatus(); + virtual ~QmlParserStatus(); + + virtual void classBegin(); + virtual void componentComplete(); + +private: + friend class QmlVME; + friend class QmlComponent; + friend class QmlComponentPrivate; + friend class QmlEnginePrivate; + QmlParserStatus **d; +}; +Q_DECLARE_INTERFACE(QmlParserStatus, "com.trolltech.qml.QmlParserStatus") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPARSERSTATUS_H diff --git a/src/declarative/qml/qmlprivate.cpp b/src/declarative/qml/qmlprivate.cpp new file mode 100644 index 0000000..01353cc --- /dev/null +++ b/src/declarative/qml/qmlprivate.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlprivate.h" + +QT_BEGIN_NAMESPACE + +QmlPrivate::InstanceType::InstanceType(int) {} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlprivate.h b/src/declarative/qml/qmlprivate.h new file mode 100644 index 0000000..dd98110 --- /dev/null +++ b/src/declarative/qml/qmlprivate.h @@ -0,0 +1,386 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPRIVATE_H +#define QMLPRIVATE_H + +#include <QtCore/qglobal.h> + +#ifndef Q_OS_WIN +#include <stdint.h> +#endif +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +typedef QObject *(*QmlAttachedPropertiesFunc)(QObject *); + +//template<typename T> +//struct qml_hasAttached { static bool const value = false; }; + +template <typename TYPE> +class QmlTypeInfo +{ +public: + enum { + hasAttachedProperties = 0 + }; +}; + + +namespace QmlPrivate +{ + class ListInterface + { + public: + virtual ~ListInterface() {} + virtual int type() const = 0; + virtual void append(void *) = 0; + virtual void insert(int, void *) = 0; + virtual void removeAt(int) = 0; + virtual void at(int, void *) const = 0; + virtual int count() const = 0; + virtual void clear() = 0; + }; + + enum ListOp { Append, Set, Insert, Prepend, Length, FromObject, + Object, Create, Value, Clear }; + + template<typename T> + int list_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<typename T> + int list_nocreate_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<typename T> + int list_interface_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<class From, class To, int N> + struct StaticCastSelectorClass + { + static inline int cast() { return -1; } + }; + + template<class From, class To> + struct StaticCastSelectorClass<From, To, sizeof(int)> + { + static inline int cast() { return (int)((intptr_t)static_cast<To *>((From *)0x10000000)) - 0x10000000; } + }; + + template<class From, class To> + struct StaticCastSelector + { + typedef int yes_type; + typedef char no_type; + + static yes_type check(To *); + static no_type check(...); + + static inline int cast() + { + return StaticCastSelectorClass<From, To, sizeof(check((From *)0))>::cast(); + } + }; + + template <typename T> + struct has_attachedPropertiesMember + { + static bool const value = QmlTypeInfo<T>::hasAttachedProperties; + }; + + template <typename T, bool hasMember> + class has_attachedPropertiesMethod + { + typedef int yes_type; + typedef char no_type; + + template<typename ReturnType> + static yes_type check(ReturnType *(*)(QObject *)); + static no_type check(...); + + public: + static bool const value = sizeof(check(&T::qmlAttachedProperties)) == sizeof(yes_type); + }; + + template <typename T> + class has_attachedPropertiesMethod<T, false> + { + public: + static bool const value = false; + }; + + template<typename T, int N> + class AttachedPropertySelector + { + public: + static inline QmlAttachedPropertiesFunc func() { return 0; } + static inline const QMetaObject *metaObject() { return 0; } + }; + template<typename T> + class AttachedPropertySelector<T, 1> + { + static inline QObject *attachedProperties(QObject *obj) { + return T::qmlAttachedProperties(obj); + } + template<typename ReturnType> + static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) { + return &ReturnType::staticMetaObject; + } + public: + static inline QmlAttachedPropertiesFunc func() { + return &attachedProperties; + } + static inline const QMetaObject *metaObject() { + return attachedPropertiesMetaObject(&T::qmlAttachedProperties); + } + }; + + template<typename T> + inline QmlAttachedPropertiesFunc attachedPropertiesFunc() + { + return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func(); + } + + template<typename T> + inline const QMetaObject *attachedPropertiesMetaObject() + { + return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject(); + } + + struct MetaTypeIds { + int typeId; + int listId; + int qmlListId; + }; + typedef int (*Func)(QmlPrivate::ListOp, int, const QVariant &, const QVariant &, void **); + typedef QObject *(*CreateFunc)(QObject *); + + template<typename T> + struct CreateParent { + static QObject *create(QObject *other) { + return new T(other); + } + }; + + template<typename T> + struct CreateNoParent { + static QObject *create() { + return new T; + } + }; + + struct Q_DECLARATIVE_EXPORT InstanceType { + InstanceType(int); + }; + + template<typename T, int VMAJ, int VMIN> + struct Define { + static InstanceType instance; + }; + + template<typename T> + struct ExtCreate { + static QObject *create(QObject *other) { + return new T(other); + } + }; +} + +template<typename T> +int QmlPrivate::list_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + if (op == QmlPrivate::Create) { + QObject *obj = static_cast<QObject *>(new T); + *((QObject **)out) = obj; + return 0; + } + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + *out = static_cast<QObject *>(value.value<T *>()); + break; + case QmlPrivate::FromObject: + { + QObject *fromObj = value.value<QObject *>(); + T *me = qobject_cast<T *>(fromObj); + if (me) { + *((QVariant *)*out) = QVariant::fromValue(me); + } + } + break; + case QmlPrivate::Value: + if (list->count() <= val) *((QVariant *)*out) = QVariant(); + else *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + +template<typename T> +int QmlPrivate::list_nocreate_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + *out = static_cast<QObject *>(value.value<T *>()); + break; + case QmlPrivate::FromObject: + { + QObject *fromObj = value.value<QObject *>(); + T *me = qobject_cast<T *>(fromObj); + if (me) { + *((QVariant *)*out) = QVariant::fromValue(me); + } + } + break; + case QmlPrivate::Value: + *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + +template<typename T> +int QmlPrivate::list_interface_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + break; + case QmlPrivate::FromObject: + break; + case QmlPrivate::Value: + *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPRIVATE_H diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp new file mode 100644 index 0000000..04cffe1 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertycache_p.h" + +#include "qmlengine_p.h" +#include "qmlbinding.h" +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_METATYPE(QScriptValue); + +void QmlPropertyCache::Data::load(const QMetaProperty &p, QmlEngine *engine) +{ + propType = p.userType(); + if (QVariant::Type(propType) == QVariant::LastType) + propType = qMetaTypeId<QVariant>(); + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + + if (p.isConstant()) + flags |= Data::IsConstant; + if (p.isWritable()) + flags |= Data::IsWritable; + if (p.isResettable()) + flags |= Data::IsResettable; + + if (propType == qMetaTypeId<QmlBinding *>()) { + flags |= Data::IsQmlBinding; + } else if (propType == qMetaTypeId<QScriptValue>()) { + flags |= Data::IsQScriptValue; + } else if (p.isEnumType()) { + flags |= Data::IsEnumType; + } else { + QmlMetaType::TypeCategory cat = engine ? QmlEnginePrivate::get(engine)->typeCategory(propType) + : QmlMetaType::typeCategory(propType); + if (cat == QmlMetaType::Object) + flags |= Data::IsQObjectDerived; + else if (cat == QmlMetaType::List) + flags |= Data::IsQList; + else if (cat == QmlMetaType::QmlList) + flags |= Data::IsQmlList; + } +} + +void QmlPropertyCache::Data::load(const QMetaMethod &m) +{ + coreIndex = m.methodIndex(); + flags |= Data::IsFunction; + propType = QVariant::Invalid; + + const char *returnType = m.typeName(); + if (returnType) + propType = QMetaType::type(returnType); + + QList<QByteArray> params = m.parameterTypes(); + if (!params.isEmpty()) + flags |= Data::HasArguments; +} + + +QmlPropertyCache::QmlPropertyCache(QmlEngine *e) +: QmlCleanup(e), engine(e) +{ +} + +QmlPropertyCache::~QmlPropertyCache() +{ + clear(); +} + +void QmlPropertyCache::clear() +{ + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->release(); + + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) + (*iter)->release(); + + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); + iter != identifierCache.end(); ++iter) + (*iter)->release(); + + indexCache.clear(); + stringCache.clear(); + identifierCache.clear(); +} + +QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, + const QString &property) +{ + Q_ASSERT(metaObject); + + QmlPropertyCache::Data rv; + int idx = metaObject->indexOfProperty(property.toUtf8()); + if (idx != -1) { + rv.load(metaObject->property(idx)); + return rv; + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (methodName == property) { + rv.load(m); + return rv; + } + } + + return rv; +} + +QmlPropertyCache *QmlPropertyCache::copy() const +{ + QmlPropertyCache *cache = new QmlPropertyCache(engine); + cache->indexCache = indexCache; + cache->stringCache = stringCache; + cache->identifierCache = identifierCache; + + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->addref(); + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + (*iter)->addref(); + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter) + (*iter)->addref(); + + return cache; +} + +void QmlPropertyCache::append(QmlEngine *engine, const QMetaObject *metaObject, + Data::Flag propertyFlags, Data::Flag methodFlags) +{ + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + int propCount = metaObject->propertyCount(); + int propOffset = metaObject->propertyOffset(); + + indexCache.resize(propCount); + for (int ii = propOffset; ii < propCount; ++ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QString::fromUtf8(p.name()); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); + + data->load(p, engine); + data->flags |= propertyFlags; + + indexCache[ii] = data; + + if (stringCache.contains(propName)) { + stringCache[propName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + stringCache.insert(propName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + int methodOffset = metaObject->methodOffset(); + for (int ii = methodOffset; ii < methodCount; ++ii) { + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); + + if (stringCache.contains(methodName)) { + stringCache[methodName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + data->load(m); + if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method) + data->flags |= methodFlags; + + stringCache.insert(methodName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + } +} + +// ### Optimize - check engine for the parent meta object etc. +QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + QmlPropertyCache *cache = new QmlPropertyCache(engine); + cache->update(engine, metaObject); + return cache; +} + +void QmlPropertyCache::update(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + clear(); + + // ### The properties/methods should probably be spliced on a per-metaobject basis + int propCount = metaObject->propertyCount(); + + indexCache.resize(propCount); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QString::fromUtf8(p.name()); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); + + data->load(p, engine); + + indexCache[ii] = data; + + if (stringCache.contains(propName)) + continue; + + stringCache.insert(propName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (stringCache.contains(methodName)) + continue; + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); + + data->load(m); + + stringCache.insert(methodName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + } +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(int index) const +{ + if (index < 0 || index >= indexCache.count()) + return 0; + + return indexCache.at(index); +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QString &str) const +{ + return stringCache.value(str); +} + +QString QmlPropertyCache::Data::name(QObject *object) +{ + if (!object) + return QString(); + + return name(object->metaObject()); +} + +QString QmlPropertyCache::Data::name(const QMetaObject *metaObject) +{ + if (!metaObject || coreIndex == -1) + return QString(); + + if (flags & IsFunction) { + QMetaMethod m = metaObject->method(coreIndex); + + QString name = QString::fromUtf8(m.signature()); + int parenIdx = name.indexOf(QLatin1Char('(')); + if (parenIdx != -1) + name = name.left(parenIdx); + return name; + } else { + QMetaProperty p = metaObject->property(coreIndex); + return QString::fromUtf8(p.name()); + } +} + +QStringList QmlPropertyCache::propertyNames() const +{ + return stringCache.keys(); +} + +QmlPropertyCache::Data *QmlPropertyCache::property(QmlEngine *engine, QObject *obj, + const QScriptDeclarativeClass::Identifier &name, Data &local) +{ + QmlPropertyCache::Data *rv = 0; + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + rv = cache->property(name); + } else { + local = QmlPropertyCache::create(obj->metaObject(), enginePrivate->objectClass->toString(name)); + if (local.isValid()) + rv = &local; + } + + return rv; +} + +QmlPropertyCache::Data *QmlPropertyCache::property(QmlEngine *engine, QObject *obj, + const QString &name, Data &local) +{ + QmlPropertyCache::Data *rv = 0; + + if (!engine) { + local = QmlPropertyCache::create(obj->metaObject(), name); + if (local.isValid()) + rv = &local; + } else { + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + rv = cache->property(name); + } else { + local = QmlPropertyCache::create(obj->metaObject(), name); + if (local.isValid()) + rv = &local; + } + } + + return rv; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h new file mode 100644 index 0000000..efc4643 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYCACHE_P_H +#define QMLPROPERTYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlrefcount_p.h" +#include "qmlcleanup_p.h" + +#include <QtCore/qvector.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QMetaProperty; +class QmlPropertyCache : public QmlRefCount, public QmlCleanup +{ +public: + QmlPropertyCache(QmlEngine *); + virtual ~QmlPropertyCache(); + + struct Data { + inline Data(); + inline bool operator==(const Data &); + + enum Flag { + NoFlags = 0x00000000, + + // Can apply to all properties, except IsFunction + IsConstant = 0x00000001, + IsWritable = 0x00000002, + IsResettable = 0x00000004, + + // These are mutualy exclusive + IsFunction = 0x00000008, + IsQObjectDerived = 0x00000010, + IsEnumType = 0x00000020, + IsQmlList = 0x00000040, + IsQList = 0x00000080, + IsQmlBinding = 0x00000100, + IsQScriptValue = 0x00000200, + + // Apply only to IsFunctions + IsVMEFunction = 0x00000400, + HasArguments = 0x00000800 + + }; + Q_DECLARE_FLAGS(Flags, Flag) + + bool isValid() const { return coreIndex != -1; } + + Flags flags; + int propType; + int coreIndex; + int notifyIndex; + + void load(const QMetaProperty &, QmlEngine *engine = 0); + void load(const QMetaMethod &); + QString name(QObject *); + QString name(const QMetaObject *); + }; + + struct ValueTypeData { + inline ValueTypeData(); + inline bool operator==(const ValueTypeData &); + int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper + int valueTypePropType; // The QVariant::Type of access property on the value type wrapper + }; + + void update(QmlEngine *, const QMetaObject *); + + QmlPropertyCache *copy() const; + void append(QmlEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, + Data::Flag methodFlags = Data::NoFlags); + + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + static Data create(const QMetaObject *, const QString &); + + inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; + Data *property(const QString &) const; + Data *property(int) const; + QStringList propertyNames() const; + + inline QmlEngine *qmlEngine() const; + static Data *property(QmlEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &); + static Data *property(QmlEngine *, QObject *, const QString &, Data &); +protected: + virtual void clear(); + +private: + struct RData : public Data, public QmlRefCount { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; + + typedef QVector<RData *> IndexCache; + typedef QHash<QString, RData *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + + QmlEngine *engine; + IndexCache indexCache; + StringCache stringCache; + IdentifierCache identifierCache; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlPropertyCache::Data::Flags); + +QmlPropertyCache::Data::Data() +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1) +{ +} + +bool QmlPropertyCache::Data::operator==(const QmlPropertyCache::Data &other) +{ + return flags == other.flags && + propType == other.propType && + coreIndex == other.coreIndex && + notifyIndex == other.notifyIndex; +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +QmlPropertyCache::ValueTypeData::ValueTypeData() +: valueTypeCoreIdx(-1), valueTypePropType(0) +{ +} + +bool QmlPropertyCache::ValueTypeData::operator==(const ValueTypeData &o) +{ + return valueTypeCoreIdx == o.valueTypeCoreIdx && + valueTypePropType == o.valueTypePropType; +} + +QmlEngine *QmlPropertyCache::qmlEngine() const +{ + return engine; +} + +QT_END_NAMESPACE + +#endif // QMLPROPERTYCACHE_P_H diff --git a/src/declarative/qml/qmlpropertyvalueinterceptor.cpp b/src/declarative/qml/qmlpropertyvalueinterceptor.cpp new file mode 100644 index 0000000..9d0d7f6 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvalueinterceptor.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertyvalueinterceptor.h" + +#include "qml.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlPropertyValueInterceptor + \brief The QmlPropertyValueInterceptor class is inherited by property interceptors such as Behavior. + \internal + + This class intercepts property writes, allowing for custom handling. For example, Behavior uses this + interception to provide a default animation for all changes to a property's value. + */ + +/*! + Constructs a QmlPropertyValueInterceptor. +*/ +QmlPropertyValueInterceptor::QmlPropertyValueInterceptor() +{ +} + +QmlPropertyValueInterceptor::~QmlPropertyValueInterceptor() +{ +} + +/*! + \fn void QmlPropertyValueInterceptor::setTarget(const QmlMetaProperty &property) + Set the target \a property for the value interceptor. This method will + be called by the QML engine when assigning a value interceptor. +*/ + +/*! + \fn void QmlPropertyValueInterceptor::write(const QVariant &value) + This method will be called when a new \a value is assigned to the property being intercepted. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertyvalueinterceptor.h b/src/declarative/qml/qmlpropertyvalueinterceptor.h new file mode 100644 index 0000000..71cc6c5 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvalueinterceptor.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYVALUEINTERCEPTOR_H +#define QMLPROPERTYVALUEINTERCEPTOR_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlMetaProperty; +class Q_DECLARATIVE_EXPORT QmlPropertyValueInterceptor +{ +public: + QmlPropertyValueInterceptor(); + virtual ~QmlPropertyValueInterceptor(); + virtual void setTarget(const QmlMetaProperty &property) = 0; + virtual void write(const QVariant &value) = 0; +}; +Q_DECLARE_INTERFACE(QmlPropertyValueInterceptor, "com.trolltech.qml.QmlPropertyValueInterceptor") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPROPERTYVALUEINTERCEPTOR_H diff --git a/src/declarative/qml/qmlpropertyvaluesource.cpp b/src/declarative/qml/qmlpropertyvaluesource.cpp new file mode 100644 index 0000000..50f2f8c --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertyvaluesource.h" + +#include "qml.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlPropertyValueSource + \brief The QmlPropertyValueSource class is inherited by property value sources such as animations and bindings. + \internal + */ + +/*! + Constructs a QmlPropertyValueSource. +*/ +QmlPropertyValueSource::QmlPropertyValueSource() +{ +} + +QmlPropertyValueSource::~QmlPropertyValueSource() +{ +} + +/*! + \fn void QmlPropertyValueSource::setTarget(const QmlMetaProperty &property) + Set the target \a property for the value source. This method will + be called by the QML engine when assigning a value source. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertyvaluesource.h b/src/declarative/qml/qmlpropertyvaluesource.h new file mode 100644 index 0000000..2017fb2 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYVALUESOURCE_H +#define QMLPROPERTYVALUESOURCE_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlMetaProperty; +class Q_DECLARATIVE_EXPORT QmlPropertyValueSource +{ +public: + QmlPropertyValueSource(); + virtual ~QmlPropertyValueSource(); + virtual void setTarget(const QmlMetaProperty &) = 0; +}; +Q_DECLARE_INTERFACE(QmlPropertyValueSource, "com.trolltech.qml.QmlPropertyValueSource") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPROPERTYVALUESOURCE_H diff --git a/src/declarative/qml/qmlproxymetaobject.cpp b/src/declarative/qml/qmlproxymetaobject.cpp new file mode 100644 index 0000000..983c350 --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlproxymetaobject_p.h" + +#include <QDebug> + +QT_BEGIN_NAMESPACE + +QmlProxyMetaObject::QmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList) +: metaObjects(mList), proxies(0), parent(0), object(obj) +{ +#ifdef QMLPROXYMETAOBJECT_DEBUG + qWarning() << "QmlProxyMetaObject" << obj->metaObject()->className(); +#endif + + *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject; + + QObjectPrivate *op = QObjectPrivate::get(obj); + if (op->metaObject) + parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + + op->metaObject = this; + +#ifdef QMLPROXYMETAOBJECT_DEBUG + const QMetaObject *mo = obj->metaObject(); + while(mo) { + qWarning() << " " << mo->className(); + mo = mo->superClass(); + } +#endif +} + +QmlProxyMetaObject::~QmlProxyMetaObject() +{ + if (parent) + delete parent; + parent = 0; + + if (proxies) + delete [] proxies; + proxies = 0; +} + +int QmlProxyMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if ((c == QMetaObject::ReadProperty || + c == QMetaObject::WriteProperty) && + id >= metaObjects->last().propertyOffset) { + + for (int ii = 0; ii < metaObjects->count(); ++ii) { + const ProxyData &data = metaObjects->at(ii); + if (id >= data.propertyOffset) { + if (!proxies) { + proxies = new QObject*[metaObjects->count()]; + ::memset(proxies, 0, + sizeof(QObject *) * metaObjects->count()); + } + + if (!proxies[ii]) { + QObject *proxy = data.createFunc(object); + const QMetaObject *metaObject = proxy->metaObject(); + proxies[ii] = proxy; + + int localOffset = data.metaObject->methodOffset(); + int methodOffset = metaObject->methodOffset(); + int methods = metaObject->methodCount() - methodOffset; + + // ### - Can this be done more optimally? + for (int jj = 0; jj < methods; ++jj) { + QMetaMethod method = + metaObject->method(jj + methodOffset); + if (method.methodType() == QMetaMethod::Signal) + QMetaObject::connect(proxy, methodOffset + jj, + object, localOffset + jj); + } + } + + int proxyOffset = proxies[ii]->metaObject()->propertyOffset(); + int proxyId = id - data.propertyOffset + proxyOffset; + + return proxies[ii]->qt_metacall(c, proxyId, a); + } + } + } else if (c == QMetaObject::InvokeMetaMethod && + id >= metaObjects->last().methodOffset) { + QMetaMethod m = object->metaObject()->method(id); + if (m.methodType() == QMetaMethod::Signal) { + QMetaObject::activate(object, id, a); + return -1; + } + } + + if (parent) + return parent->metaCall(c, id, a); + else + return object->qt_metacall(c, id, a); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlproxymetaobject_p.h b/src/declarative/qml/qmlproxymetaobject_p.h new file mode 100644 index 0000000..f983030 --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROXYMETAOBJECT_P_H +#define QMLPROXYMETAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmetaobjectbuilder_p.h" +#include "qml.h" + +#include <QtCore/QMetaObject> +#include <QtCore/QObject> + +#include <private/qobject_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlProxyMetaObject : public QAbstractDynamicMetaObject +{ +public: + struct ProxyData { + typedef QObject *(*CreateFunc)(QObject *); + QMetaObject *metaObject; + CreateFunc createFunc; + int propertyOffset; + int methodOffset; + }; + + QmlProxyMetaObject(QObject *, QList<ProxyData> *); + virtual ~QmlProxyMetaObject(); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QList<ProxyData> *metaObjects; + QObject **proxies; + + QAbstractDynamicMetaObject *parent; + QObject *object; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPROXYMETAOBJECT_P_H + diff --git a/src/declarative/qml/qmlrefcount.cpp b/src/declarative/qml/qmlrefcount.cpp new file mode 100644 index 0000000..9422625 --- /dev/null +++ b/src/declarative/qml/qmlrefcount.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlrefcount_p.h" + +QT_BEGIN_NAMESPACE + +QmlRefCount::QmlRefCount() +: refCount(1) +{ +} + +QmlRefCount::~QmlRefCount() +{ +} + +void QmlRefCount::addref() +{ + Q_ASSERT(refCount > 0); + ++refCount; +} + +void QmlRefCount::release() +{ + Q_ASSERT(refCount > 0); + --refCount; + if (refCount == 0) + delete this; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlrefcount_p.h b/src/declarative/qml/qmlrefcount_p.h new file mode 100644 index 0000000..7448042 --- /dev/null +++ b/src/declarative/qml/qmlrefcount_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLREFCOUNT_P_H +#define QMLREFCOUNT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_AUTOTEST_EXPORT QmlRefCount +{ +public: + QmlRefCount(); + virtual ~QmlRefCount(); + void addref(); + void release(); + +private: + int refCount; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLREFCOUNT_P_H diff --git a/src/declarative/qml/qmlrewrite.cpp b/src/declarative/qml/qmlrewrite.cpp new file mode 100644 index 0000000..34bd198 --- /dev/null +++ b/src/declarative/qml/qmlrewrite.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlrewrite_p.h" + +#include "qmlglobal_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP); + +namespace QmlRewrite { + +bool SharedBindingTester::isSharable(const QString &code) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) + return false; + + _sharable = true; + AST::Node::acceptChild(parser.statement(), this); + return _sharable; +} + +QString RewriteBinding::operator()(const QString &code, bool *ok) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) { + if (ok) *ok = false; + return QString(); + } else { + if (ok) *ok = true; + } + return rewrite(code, 0, parser.statement()); +} + +void RewriteBinding::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +QString RewriteBinding::rewrite(QString code, unsigned position, + AST::Statement *node) +{ + TextWriter w; + _writer = &w; + _position = position; + _inLoop = 0; + + accept(node); + + unsigned startOfStatement = node->firstSourceLocation().begin() - _position; + unsigned endOfStatement = node->lastSourceLocation().end() - _position; + + _writer->replace(startOfStatement, 0, QLatin1String("(function() { ")); + _writer->replace(endOfStatement, 0, QLatin1String(" })")); + + if (rewriteDump()) { + qWarning() << "============================================================="; + qWarning() << "Rewrote:"; + qWarning() << qPrintable(code); + } + + w.write(&code); + + if (rewriteDump()) { + qWarning() << "To:"; + qWarning() << qPrintable(code); + qWarning() << "============================================================="; + } + + return code; +} + +bool RewriteBinding::visit(AST::Block *ast) +{ + for (AST::StatementList *it = ast->statements; it; it = it->next) { + if (! it->next) { + // we need to rewrite only the last statement of a block. + accept(it->statement); + } + } + + return false; +} + +bool RewriteBinding::visit(AST::ExpressionStatement *ast) +{ + if (! _inLoop) { + unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; + _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); + } + + return false; +} + +bool RewriteBinding::visit(AST::DoWhileStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::DoWhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::WhileStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::WhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::LocalForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForEachStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForEachStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForEachStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::LocalForEachStatement *) +{ + --_inLoop; +} + +} // namespace QmlRewrite + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlrewrite_p.h b/src/declarative/qml/qmlrewrite_p.h new file mode 100644 index 0000000..a04a0db --- /dev/null +++ b/src/declarative/qml/qmlrewrite_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLREWRITE_P_H +#define QMLREWRITE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "rewriter/textwriter_p.h" +#include "parser/qmljslexer_p.h" +#include "parser/qmljsparser_p.h" +#include "parser/qmljsnodepool_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlRewrite { +using namespace QmlJS; + +class SharedBindingTester : protected AST::Visitor +{ + bool _sharable; +public: + bool isSharable(const QString &code); + + virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; } + virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; } + virtual bool visit(AST::CallExpression *) { _sharable = false; return false; } +}; + +class RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(const QString &code, bool *ok = 0); + +protected: + using AST::Visitor::visit; + + void accept(AST::Node *node); + QString rewrite(QString code, unsigned position, AST::Statement *node); + + virtual bool visit(AST::Block *ast); + virtual bool visit(AST::ExpressionStatement *ast); + + virtual bool visit(AST::DoWhileStatement *ast); + virtual void endVisit(AST::DoWhileStatement *ast); + + virtual bool visit(AST::WhileStatement *ast); + virtual void endVisit(AST::WhileStatement *ast); + + virtual bool visit(AST::ForStatement *ast); + virtual void endVisit(AST::ForStatement *ast); + + virtual bool visit(AST::LocalForStatement *ast); + virtual void endVisit(AST::LocalForStatement *ast); + + virtual bool visit(AST::ForEachStatement *ast); + virtual void endVisit(AST::ForEachStatement *ast); + + virtual bool visit(AST::LocalForEachStatement *ast); + virtual void endVisit(AST::LocalForEachStatement *ast); + +private: + int _inLoop; +}; + +} // namespace QmlRewrite + +QT_END_NAMESPACE + +#endif // QMLREWRITE_P_H + diff --git a/src/declarative/qml/qmlscript.cpp b/src/declarative/qml/qmlscript.cpp new file mode 100644 index 0000000..10fc9a6 --- /dev/null +++ b/src/declarative/qml/qmlscript.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is just a dummy file to include the documentation + +/*! + \qmlclass Script QmlScript + \brief The Script element provides a way to add JavaScript code snippets in QML. + \ingroup group_utility + + The Script element is used to add convenient JavaScript "glue" methods to + your Qt Declarative application or component. + + An example: + + \qml + Script { + function debugMyComponent() { + console.log(text.text); + console.log(otherinterestingitem.property); + } + } + MouseRegion { onClicked: debugMyComponent() } + \endqml + + \note While it is possible to use any JavaScript code within a Script element, + it is recommended that the code be limited to defining functions. The Script + element executes JavaScript as soon as it is specified, so + when defining a component, this may be done before the execution context is + fully specified. As a result, some properties or items may not be + accessible. You can avoid this problem by limiting your JavaScript to + defining functions that are only executed later once the context is fully + defined. + + \sa {JavaScript Blocks} +*/ + +/*! + \qmlproperty string Script::script + \default + The JavaScript code to be executed. +*/ + +/*! + \qmlproperty url Script::source + + Specifies a source file containing JavaScript code. This can be used instead + of providing inline JavaScript code in the Script element. +*/ diff --git a/src/declarative/qml/qmlscriptclass_p.h b/src/declarative/qml/qmlscriptclass_p.h new file mode 100644 index 0000000..847ee66 --- /dev/null +++ b/src/declarative/qml/qmlscriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSCRIPTCLASS_P_H +#define QMLSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptclass.h> +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlScriptClass : public QScriptDeclarativeClass +{ +public: + QmlScriptClass(QScriptEngine *); + + static QVariant toVariant(QmlEngine *, const QScriptValue &); + +#if (QT_VERSION <= QT_VERSION_CHECK(4, 6, 2)) && !defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE) + struct Value : public QScriptValue { + Value() : QScriptValue() {} + Value(QScriptEngine *engine, int v) : QScriptValue(engine, v) {} + Value(QScriptEngine *engine, uint v) : QScriptValue(engine, v) {} + Value(QScriptEngine *engine, bool v) : QScriptValue(engine, v) {} + Value(QScriptEngine *engine, double v) : QScriptValue(engine, v) {} + Value(QScriptEngine *engine, float v) : QScriptValue(engine, v) {} + Value(QScriptEngine *engine, const QString &v) : QScriptValue(engine, v) {} + Value(QScriptEngine *, const QScriptValue &v) : QScriptValue(v) {} + }; + + typedef QScriptValue ScriptValue; +#else + typedef Value ScriptValue; +#endif +}; + +QT_END_NAMESPACE + +#endif // QMLSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp new file mode 100644 index 0000000..a24ef51 --- /dev/null +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -0,0 +1,952 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlscriptparser_p.h" + +#include "qmlparser_p.h" +#include "parser/qmljsengine_p.h" +#include "parser/qmljsparser_p.h" +#include "parser/qmljslexer_p.h" +#include "parser/qmljsnodepool_p.h" +#include "parser/qmljsastvisitor_p.h" +#include "parser/qmljsast_p.h" +#include "qmlrewrite_p.h" + +#include <qfxperf_p_p.h> + +#include <QStack> +#include <QCoreApplication> +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +using namespace QmlJS; +using namespace QmlParser; + +namespace { + +class ProcessAST: protected AST::Visitor +{ + struct State { + State() : object(0), property(0) {} + State(Object *o) : object(o), property(0) {} + State(Object *o, Property *p) : object(o), property(p) {} + + Object *object; + Property *property; + }; + + struct StateStack : public QStack<State> + { + void pushObject(Object *obj) + { + push(State(obj)); + } + + void pushProperty(const QString &name, const LocationSpan &location) + { + const State &state = top(); + if (state.property) { + State s(state.property->getValue(), + state.property->getValue()->getProperty(name.toUtf8())); + s.property->location = location; + push(s); + } else { + State s(state.object, + state.object->getProperty(name.toUtf8())); + + s.property->location = location; + push(s); + } + } + }; + +public: + ProcessAST(QmlScriptParser *parser); + virtual ~ProcessAST(); + + void operator()(const QString &code, AST::Node *node); + +protected: + Object *defineObjectBinding(AST::UiQualifiedId *propertyName, + AST::UiQualifiedId *objectTypeName, + LocationSpan location, + AST::UiObjectInitializer *initializer = 0); + + Object *defineObjectBinding_helper(AST::UiQualifiedId *propertyName, + const QString &objectType, + AST::SourceLocation typeLocation, + LocationSpan location, + AST::UiObjectInitializer *initializer = 0); + + QmlParser::Variant getVariant(AST::ExpressionNode *expr); + + LocationSpan location(AST::SourceLocation start, AST::SourceLocation end); + LocationSpan location(AST::UiQualifiedId *); + + using AST::Visitor::visit; + using AST::Visitor::endVisit; + + virtual bool visit(AST::UiProgram *node); + virtual bool visit(AST::UiImport *node); + virtual bool visit(AST::UiObjectDefinition *node); + virtual bool visit(AST::UiPublicMember *node); + virtual bool visit(AST::UiObjectBinding *node); + + virtual bool visit(AST::UiScriptBinding *node); + virtual bool visit(AST::UiArrayBinding *node); + virtual bool visit(AST::UiSourceElement *node); + + void accept(AST::Node *node); + + QString asString(AST::UiQualifiedId *node) const; + + const State state() const; + Object *currentObject() const; + Property *currentProperty() const; + + QString qualifiedNameId() const; + + QString textAt(const AST::SourceLocation &loc) const + { return _contents.mid(loc.offset, loc.length); } + + + QString textAt(const AST::SourceLocation &first, + const AST::SourceLocation &last) const + { return _contents.mid(first.offset, last.offset + last.length - first.offset); } + + QString asString(AST::ExpressionNode *expr) + { + if (! expr) + return QString(); + + return textAt(expr->firstSourceLocation(), expr->lastSourceLocation()); + } + + QString asString(AST::Statement *stmt) + { + if (! stmt) + return QString(); + + QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation()); + s += QLatin1Char('\n'); + return s; + } + +private: + QmlScriptParser *_parser; + StateStack _stateStack; + QStringList _scope; + QString _contents; + + inline bool isSignalProperty(const QByteArray &propertyName) const { + return (propertyName.length() >= 3 && propertyName.startsWith("on") && + ('A' <= propertyName.at(2) && 'Z' >= propertyName.at(2))); + } + +}; + +ProcessAST::ProcessAST(QmlScriptParser *parser) + : _parser(parser) +{ +} + +ProcessAST::~ProcessAST() +{ +} + +void ProcessAST::operator()(const QString &code, AST::Node *node) +{ + _contents = code; + accept(node); +} + +void ProcessAST::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +const ProcessAST::State ProcessAST::state() const +{ + if (_stateStack.isEmpty()) + return State(); + + return _stateStack.back(); +} + +Object *ProcessAST::currentObject() const +{ + return state().object; +} + +Property *ProcessAST::currentProperty() const +{ + return state().property; +} + +QString ProcessAST::qualifiedNameId() const +{ + return _scope.join(QLatin1String("/")); +} + +QString ProcessAST::asString(AST::UiQualifiedId *node) const +{ + QString s; + + for (AST::UiQualifiedId *it = node; it; it = it->next) { + s.append(it->name->asString()); + + if (it->next) + s.append(QLatin1Char('.')); + } + + return s; +} + +Object * +ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName, + const QString &objectType, + AST::SourceLocation typeLocation, + LocationSpan location, + AST::UiObjectInitializer *initializer) +{ + int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.')); + bool isType = !objectType.isEmpty() && + (objectType.at(0).isUpper() || + (lastTypeDot >= 0 && objectType.at(lastTypeDot+1).isUpper())); + + int propertyCount = 0; + for (; propertyName; propertyName = propertyName->next){ + ++propertyCount; + _stateStack.pushProperty(propertyName->name->asString(), + this->location(propertyName)); + } + + if (!isType) { + + if(propertyCount || !currentObject()) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Expected type name")); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; + return 0; + } + + LocationSpan loc = ProcessAST::location(typeLocation, typeLocation); + if (propertyName) + loc = ProcessAST::location(propertyName); + + _stateStack.pushProperty(objectType, loc); + accept(initializer); + _stateStack.pop(); + + return 0; + + } else { + // Class + + QString resolvableObjectType = objectType; + if (lastTypeDot >= 0) + resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/')); + + bool isScript = resolvableObjectType == QLatin1String("Script"); + + if (isScript) { + if (_stateStack.isEmpty() || _stateStack.top().property) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Invalid use of Script block")); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; + return 0; + } + } + + Object *obj = new Object; + + if (!isScript) { + QmlScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType); + obj->type = typeRef->id; + + typeRef->refObjects.append(obj); + } + + // XXX this doesn't do anything (_scope never builds up) + _scope.append(resolvableObjectType); + obj->typeName = qualifiedNameId().toUtf8(); + _scope.removeLast(); + + obj->location = location; + + if (isScript) { + + _stateStack.top().object->scriptBlockObjects.append(obj); + + } else if (propertyCount) { + + Property *prop = currentProperty(); + Value *v = new Value; + v->object = obj; + v->location = obj->location; + prop->addValue(v); + + while (propertyCount--) + _stateStack.pop(); + + } else { + + if (! _parser->tree()) { + _parser->setTree(obj); + } else { + const State state = _stateStack.top(); + Value *v = new Value; + v->object = obj; + v->location = obj->location; + if (state.property) { + state.property->addValue(v); + } else { + Property *defaultProp = state.object->getDefaultProperty(); + if (defaultProp->location.start.line == -1) { + defaultProp->location = v->location; + defaultProp->location.end = defaultProp->location.start; + defaultProp->location.range.length = 0; + } + defaultProp->addValue(v); + } + } + } + + _stateStack.pushObject(obj); + accept(initializer); + _stateStack.pop(); + + return obj; + } +} + +Object *ProcessAST::defineObjectBinding(AST::UiQualifiedId *qualifiedId, + AST::UiQualifiedId *objectTypeName, + LocationSpan location, + AST::UiObjectInitializer *initializer) +{ + const QString objectType = asString(objectTypeName); + const AST::SourceLocation typeLocation = objectTypeName->identifierToken; + + if (objectType == QLatin1String("Script")) { + + AST::UiObjectMemberList *it = initializer->members; + for (; it; it = it->next) { + AST::UiScriptBinding *scriptBinding = AST::cast<AST::UiScriptBinding *>(it->member); + if (! scriptBinding) + continue; + + QString propertyName = asString(scriptBinding->qualifiedId); + if (propertyName == QLatin1String("source")) { + if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(scriptBinding->statement)) { + QmlParser::Variant string = getVariant(stmt->expression); + if (string.isStringList()) { + QStringList urls = string.asStringList(); + // We need to add this as a resource + for (int ii = 0; ii < urls.count(); ++ii) + _parser->_refUrls << QUrl(urls.at(ii)); + } + } + } + } + + } + + return defineObjectBinding_helper(qualifiedId, objectType, typeLocation, location, initializer); +} + +LocationSpan ProcessAST::location(AST::UiQualifiedId *id) +{ + return location(id->identifierToken, id->identifierToken); +} + +LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end) +{ + LocationSpan rv; + rv.start.line = start.startLine; + rv.start.column = start.startColumn; + rv.end.line = end.startLine; + rv.end.column = end.startColumn + end.length - 1; + rv.range.offset = start.offset; + rv.range.length = end.offset + end.length - start.offset; + return rv; +} + +// UiProgram: UiImportListOpt UiObjectMemberList ; +bool ProcessAST::visit(AST::UiProgram *node) +{ + accept(node->imports); + accept(node->members->member); + return false; +} + +// UiImport: T_IMPORT T_STRING_LITERAL ; +bool ProcessAST::visit(AST::UiImport *node) +{ + QString uri; + QmlScriptParser::Import import; + + if (node->fileName) { + import.type = QmlScriptParser::Import::File; + uri = node->fileName->asString(); + } else { + import.type = QmlScriptParser::Import::Library; + uri = asString(node->importUri); + } + + AST::SourceLocation startLoc = node->importToken; + AST::SourceLocation endLoc = node->semicolonToken; + + if (node->importId) { + import.qualifier = node->importId->asString(); + if (!import.qualifier.at(0).isUpper()) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Invalid import qualifier ID")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + } + if (node->versionToken.isValid()) + import.version = textAt(node->versionToken); + else if (import.type == QmlScriptParser::Import::Library) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Library import requires a version")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + + import.location = location(startLoc, endLoc); + import.uri = uri; + + _parser->_imports << import; + + return false; +} + +bool ProcessAST::visit(AST::UiPublicMember *node) +{ + const struct TypeNameToType { + const char *name; + Object::DynamicProperty::Type type; + const char *qtName; + } propTypeNameToTypes[] = { + { "int", Object::DynamicProperty::Int, "int" }, + { "bool", Object::DynamicProperty::Bool, "bool" }, + { "double", Object::DynamicProperty::Real, "double" }, + { "real", Object::DynamicProperty::Real, "qreal" }, + { "string", Object::DynamicProperty::String, "QString" }, + { "url", Object::DynamicProperty::Url, "QUrl" }, + { "color", Object::DynamicProperty::Color, "QColor" }, + { "date", Object::DynamicProperty::Date, "QDate" }, + { "var", Object::DynamicProperty::Variant, "QVariant" }, + { "variant", Object::DynamicProperty::Variant, "QVariant" } + }; + const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / + sizeof(propTypeNameToTypes[0]); + + if(node->type == AST::UiPublicMember::Signal) { + const QString name = node->name->asString(); + + Object::DynamicSignal signal; + signal.name = name.toUtf8(); + + AST::UiParameterList *p = node->parameters; + while (p) { + const QString memberType = p->type->asString(); + const char *qtType = 0; + for(int ii = 0; !qtType && ii < propTypeNameToTypesCount; ++ii) { + if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) + qtType = propTypeNameToTypes[ii].qtName; + } + + if (!qtType) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Expected parameter type")); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + + signal.parameterTypes << qtType; + signal.parameterNames << p->name->asString().toUtf8(); + p = p->finish(); + } + + _stateStack.top().object->dynamicSignals << signal; + } else { + const QString memberType = node->memberType->asString(); + const QString name = node->name->asString(); + + bool typeFound = false; + Object::DynamicProperty::Type type; + + if (memberType == QLatin1String("alias")) { + type = Object::DynamicProperty::Alias; + typeFound = true; + } + + for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { + if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) { + type = propTypeNameToTypes[ii].type; + typeFound = true; + } + } + + if (!typeFound && memberType.at(0).isUpper()) { + QString typemodifier; + if(node->typeModifier) + typemodifier = node->typeModifier->asString(); + if (typemodifier == QString()) { + type = Object::DynamicProperty::Custom; + } else if(typemodifier == QLatin1String("list")) { + type = Object::DynamicProperty::CustomList; + } else { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Invalid property type modifier")); + error.setLine(node->typeModifierToken.startLine); + error.setColumn(node->typeModifierToken.startColumn); + _parser->_errors << error; + return false; + } + typeFound = true; + } else if (node->typeModifier) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Unexpected property type modifier")); + error.setLine(node->typeModifierToken.startLine); + error.setColumn(node->typeModifierToken.startColumn); + _parser->_errors << error; + return false; + } + + if(!typeFound) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Expected property type")); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + + if (node->isReadonlyMember) { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","Readonly not yet supported")); + error.setLine(node->readonlyToken.startLine); + error.setColumn(node->readonlyToken.startColumn); + _parser->_errors << error; + return false; + + } + Object::DynamicProperty property; + property.isDefaultProperty = node->isDefaultMember; + property.type = type; + if (type >= Object::DynamicProperty::Custom) { + QmlScriptParser::TypeReference *typeRef = + _parser->findOrCreateType(memberType); + typeRef->refObjects.append(_stateStack.top().object); + } + property.customType = memberType.toUtf8(); + property.name = name.toUtf8(); + property.location = location(node->firstSourceLocation(), + node->lastSourceLocation()); + + if (node->expression) { // default value + property.defaultValue = new Property; + property.defaultValue->parent = _stateStack.top().object; + property.defaultValue->location = + location(node->expression->firstSourceLocation(), + node->expression->lastSourceLocation()); + Value *value = new Value; + value->location = location(node->expression->firstSourceLocation(), + node->expression->lastSourceLocation()); + value->value = getVariant(node->expression); + property.defaultValue->values << value; + } + + _stateStack.top().object->dynamicProperties << property; + } + + return true; +} + + +// UiObjectMember: UiQualifiedId UiObjectInitializer ; +bool ProcessAST::visit(AST::UiObjectDefinition *node) +{ + LocationSpan l = location(node->firstSourceLocation(), + node->lastSourceLocation()); + + defineObjectBinding(/*propertyName = */ 0, + node->qualifiedTypeNameId, + l, + node->initializer); + + return false; +} + + +// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; +bool ProcessAST::visit(AST::UiObjectBinding *node) +{ + LocationSpan l = location(node->qualifiedTypeNameId->identifierToken, + node->initializer->rbraceToken); + + defineObjectBinding(node->qualifiedId, + node->qualifiedTypeNameId, + l, + node->initializer); + + return false; +} + +QmlParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) +{ + if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) { + return QmlParser::Variant(lit->value->asString()); + } else if (expr->kind == AST::Node::Kind_TrueLiteral) { + return QmlParser::Variant(true); + } else if (expr->kind == AST::Node::Kind_FalseLiteral) { + return QmlParser::Variant(false); + } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) { + return QmlParser::Variant(lit->value, asString(expr)); + } else { + + if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) { + if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) { + return QmlParser::Variant(-lit->value, asString(expr)); + } + } + + return QmlParser::Variant(asString(expr), expr); + } +} + + +// UiObjectMember: UiQualifiedId T_COLON Statement ; +bool ProcessAST::visit(AST::UiScriptBinding *node) +{ + int propertyCount = 0; + AST::UiQualifiedId *propertyName = node->qualifiedId; + for (; propertyName; propertyName = propertyName->next){ + ++propertyCount; + _stateStack.pushProperty(propertyName->name->asString(), + location(propertyName)); + } + + Property *prop = currentProperty(); + + QmlParser::Variant primitive; + + if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) { + primitive = getVariant(stmt->expression); + } else { // do binding + primitive = QmlParser::Variant(asString(node->statement), + node->statement); + } + + prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset; + prop->location.range.offset = node->qualifiedId->identifierToken.offset; + Value *v = new Value; + v->value = primitive; + v->location = location(node->statement->firstSourceLocation(), + node->statement->lastSourceLocation()); + + prop->addValue(v); + + while (propertyCount--) + _stateStack.pop(); + + return true; +} + +static QList<int> collectCommas(AST::UiArrayMemberList *members) +{ + QList<int> commas; + + if (members) { + for (AST::UiArrayMemberList *it = members->next; it; it = it->next) { + commas.append(it->commaToken.offset); + } + } + + return commas; +} + +// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; +bool ProcessAST::visit(AST::UiArrayBinding *node) +{ + int propertyCount = 0; + AST::UiQualifiedId *propertyName = node->qualifiedId; + for (; propertyName; propertyName = propertyName->next){ + ++propertyCount; + _stateStack.pushProperty(propertyName->name->asString(), + location(propertyName)); + } + + accept(node->members); + + // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range: + Property* prop = currentProperty(); + prop->listValueRange.offset = node->lbracketToken.offset; + prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset; + + // Store the positions of the comma token too, again for the DOM to be able to retreive it. + prop->listCommaPositions = collectCommas(node->members); + + while (propertyCount--) + _stateStack.pop(); + + return false; +} + +bool ProcessAST::visit(AST::UiSourceElement *node) +{ + QmlParser::Object *obj = currentObject(); + + bool isScript = (obj && obj->typeName == "Script"); + + if (!isScript) { + + if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) { + + Object::DynamicSlot slot; + + AST::FormalParameterList *f = funDecl->formals; + while (f) { + slot.parameterNames << f->name->asString().toUtf8(); + f = f->finish(); + } + + QString body = textAt(funDecl->lbraceToken, funDecl->rbraceToken); + slot.name = funDecl->name->asString().toUtf8(); + slot.body = body; + obj->dynamicSlots << slot; + + } else { + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser","QmlJS declaration outside Script element")); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; + } + return false; + + } else { + QString source; + + int line = 0; + if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) { + line = funDecl->functionToken.startLine; + source = asString(funDecl); + } else if (AST::VariableStatement *varStmt = AST::cast<AST::VariableStatement *>(node->sourceElement)) { + // ignore variable declarations + line = varStmt->declarationKindToken.startLine; + + QmlError error; + error.setDescription(QCoreApplication::translate("QmlParser", "Variable declarations not allow in inline Script blocks")); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; + return false; + } + + Value *value = new Value; + value->location = location(node->firstSourceLocation(), + node->lastSourceLocation()); + value->value = QmlParser::Variant(source); + + obj->getDefaultProperty()->addValue(value); + } + + return false; +} + +} // end of anonymous namespace + + +QmlScriptParser::QmlScriptParser() +: root(0), data(0) +{ + +} + +QmlScriptParser::~QmlScriptParser() +{ + clear(); +} + +class QmlScriptParserJsASTData +{ +public: + QmlScriptParserJsASTData(const QString &filename) + : nodePool(filename, &engine) {} + + Engine engine; + NodePool nodePool; +}; + +bool QmlScriptParser::parse(const QByteArray &qmldata, const QUrl &url) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QmlPerfTimer<QmlPerf::QmlParsing> pt; +#endif + clear(); + + const QString fileName = url.toString(); + + QTextStream stream(qmldata, QIODevice::ReadOnly); + stream.setCodec("UTF-8"); + const QString code = stream.readAll(); + + data = new QmlScriptParserJsASTData(fileName); + + Lexer lexer(&data->engine); + lexer.setCode(code, /*line = */ 1); + + Parser parser(&data->engine); + + if (! parser.parse() || !_errors.isEmpty()) { + + // Extract errors from the parser + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + + if (m.isWarning()) + continue; + + QmlError error; + error.setUrl(url); + error.setDescription(m.message); + error.setLine(m.loc.startLine); + error.setColumn(m.loc.startColumn); + _errors << error; + + } + } + + if (_errors.isEmpty()) { + ProcessAST process(this); + process(code, parser.ast()); + + // Set the url for process errors + for(int ii = 0; ii < _errors.count(); ++ii) + _errors[ii].setUrl(url); + } + + return _errors.isEmpty(); +} + +QList<QmlScriptParser::TypeReference*> QmlScriptParser::referencedTypes() const +{ + return _refTypes; +} + +QList<QUrl> QmlScriptParser::referencedResources() const +{ + return _refUrls; +} + +Object *QmlScriptParser::tree() const +{ + return root; +} + +QList<QmlScriptParser::Import> QmlScriptParser::imports() const +{ + return _imports; +} + +QList<QmlError> QmlScriptParser::errors() const +{ + return _errors; +} + +void QmlScriptParser::clear() +{ + if (root) { + root->release(); + root = 0; + } + _imports.clear(); + qDeleteAll(_refTypes); + _refTypes.clear(); + _errors.clear(); + + if (data) { + delete data; + data = 0; + } +} + +QmlScriptParser::TypeReference *QmlScriptParser::findOrCreateType(const QString &name) +{ + TypeReference *type = 0; + int i = 0; + for (; i < _refTypes.size(); ++i) { + if (_refTypes.at(i)->name == name) { + type = _refTypes.at(i); + break; + } + } + if (!type) { + type = new TypeReference(i, name); + _refTypes.append(type); + } + + return type; +} + +void QmlScriptParser::setTree(Object *tree) +{ + Q_ASSERT(! root); + + root = tree; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h new file mode 100644 index 0000000..16888aa --- /dev/null +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QMLSCRIPTPARSER_P_H +#define QMLSCRIPTPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlerror.h" +#include "qmlparser_p.h" + +#include <QtCore/QList> +#include <QtCore/QUrl> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QByteArray; + +class QmlScriptParserJsASTData; +class QmlScriptParser +{ +public: + class Import + { + public: + Import() : type(Library) {} + + enum Type { Library, File }; + Type type; + + QString uri; + QString qualifier; + QString version; + + QmlParser::LocationSpan location; + }; + + class TypeReference + { + public: + TypeReference(int typeId, const QString &typeName) : id(typeId), name(typeName) {} + + int id; + // type as it has been referenced in Qml + QString name; + // objects in parse tree referencing the type + QList<QmlParser::Object*> refObjects; + }; + + QmlScriptParser(); + ~QmlScriptParser(); + + bool parse(const QByteArray &data, const QUrl &url = QUrl()); + + QList<TypeReference*> referencedTypes() const; + QList<QUrl> referencedResources() const; + + QmlParser::Object *tree() const; + QList<Import> imports() const; + + void clear(); + + QList<QmlError> errors() const; + +// ### private: + TypeReference *findOrCreateType(const QString &name); + void setTree(QmlParser::Object *tree); + + void setScriptFile(const QString &filename) {_scriptFile = filename; } + QString scriptFile() const { return _scriptFile; } + +// ### private: + QList<QmlError> _errors; + + QmlParser::Object *root; + QList<Import> _imports; + QList<TypeReference*> _refTypes; + QList<QUrl> _refUrls; + QString _scriptFile; + QmlScriptParserJsASTData *data; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLSCRIPTPARSER_P_H diff --git a/src/declarative/qml/qmlscriptstring.cpp b/src/declarative/qml/qmlscriptstring.cpp new file mode 100644 index 0000000..1ccad53 --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlscriptstring.h" + +QT_BEGIN_NAMESPACE + +class QmlScriptStringPrivate : public QSharedData +{ +public: + QmlScriptStringPrivate() : context(0), scope(0) {} + + QmlContext *context; + QObject *scope; + QString script; +}; + +/*! +\class QmlScriptString +\brief The QmlScriptString class encapsulates a script and its context. + +The QmlScriptString is used by properties that want to accept a script "assignment" from QML. + +Normally, the following code would result in a binding being established for the \c script +property. If the property had a type of QmlScriptString, the script - \e {console.log(1921)} - itself +would be passed to the property and it could choose how to handle it. + +\code +MyType { + script: console.log(1921) +} +\endcode +*/ + +/*! +Construct an empty instance. +*/ +QmlScriptString::QmlScriptString() +: d(new QmlScriptStringPrivate) +{ +} + +/*! +Copy \a other. +*/ +QmlScriptString::QmlScriptString(const QmlScriptString &other) +: d(other.d) +{ +} + +/*! +\internal +*/ +QmlScriptString::~QmlScriptString() +{ +} + +/*! +Assign \a other to this. +*/ +QmlScriptString &QmlScriptString::operator=(const QmlScriptString &other) +{ + d = other.d; + return *this; +} + +/*! +Return the context for the script. +*/ +QmlContext *QmlScriptString::context() const +{ + return d->context; +} + +/*! +Sets the \a context for the script. +*/ +void QmlScriptString::setContext(QmlContext *context) +{ + d->context = context; +} + +/*! +Returns the scope object for the script. +*/ +QObject *QmlScriptString::scopeObject() const +{ + return d->scope; +} + +/*! +Sets the scope \a object for the script. +*/ +void QmlScriptString::setScopeObject(QObject *object) +{ + d->scope = object; +} + +/*! +Returns the script text. +*/ +QString QmlScriptString::script() const +{ + return d->script; +} + +/*! +Sets the \a script text. +*/ +void QmlScriptString::setScript(const QString &script) +{ + d->script = script; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlscriptstring.h b/src/declarative/qml/qmlscriptstring.h new file mode 100644 index 0000000..73a473f --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSCRIPTSTRING_H +#define QMLSCRIPTSTRING_H + +#include <QtCore/qstring.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlContext; +class QmlScriptStringPrivate; +class Q_DECLARATIVE_EXPORT QmlScriptString +{ +public: + QmlScriptString(); + QmlScriptString(const QmlScriptString &); + ~QmlScriptString(); + + QmlScriptString &operator=(const QmlScriptString &); + + QmlContext *context() const; + void setContext(QmlContext *); + + QObject *scopeObject() const; + void setScopeObject(QObject *); + + QString script() const; + void setScript(const QString &); + +private: + QSharedDataPointer<QmlScriptStringPrivate> d; +}; + +Q_DECLARE_METATYPE(QmlScriptString); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLSCRIPTSTRING_H + diff --git a/src/declarative/qml/qmlsqldatabase.cpp b/src/declarative/qml/qmlsqldatabase.cpp new file mode 100644 index 0000000..684caa2 --- /dev/null +++ b/src/declarative/qml/qmlsqldatabase.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlsqldatabase_p.h" + +#include "qmlengine.h" +#include "qmlengine_p.h" +#include "qmlrefcount_p.h" +#include "qmlengine_p.h" + +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptvalueiterator.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptengine.h> +#include <QtScript/qscriptclasspropertyiterator.h> +#include <QtSql/qsqldatabase.h> +#include <QtSql/qsqlquery.h> +#include <QtSql/qsqlerror.h> +#include <QtSql/qsqlrecord.h> +#include <QtCore/qstack.h> +#include <QtCore/qcryptographichash.h> +#include <QtCore/qsettings.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QSqlDatabase) +Q_DECLARE_METATYPE(QSqlQuery) + +class QmlSqlQueryScriptClass: public QScriptClass { +public: + QmlSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine) + { + str_length = engine->toStringHandle(QLatin1String("length")); + str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization) + } + + QueryFlags queryProperty(const QScriptValue &, + const QScriptString &name, + QueryFlags flags, uint *) + { + if (flags & HandlesReadAccess) { + if (name == str_length) { + return HandlesReadAccess; + } else if (name == str_forwardOnly) { + return flags; + } + } + if (flags & HandlesWriteAccess) + if (name == str_forwardOnly) + return flags; + return 0; + } + + QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint) + { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + if (name == str_length) { + int s = query.size(); + if (s<0) { + // Inefficient. + if (query.last()) { + return query.at()+1; + } else { + return 0; + } + } else { + return s; + } + } else if (name == str_forwardOnly) { + return query.isForwardOnly(); + } + return engine()->undefinedValue(); + } + + void setProperty(QScriptValue &object, + const QScriptString &name, uint, const QScriptValue & value) + { + if (name == str_forwardOnly) { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + query.setForwardOnly(value.toBool()); + } + } + + QScriptValue::PropertyFlags propertyFlags(const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/) + { + if (name == str_length) { + return QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration; + } + return QScriptValue::Undeletable; + } + +private: + QScriptString str_length; + QScriptString str_forwardOnly; +}; + +// If the spec changes to allow iteration, check git history... +// class QmlSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator + + + +enum SqlException { + UNKNOWN_ERR, + DATABASE_ERR, + VERSION_ERR, + TOO_LARGE_ERR, + QUOTA_ERR, + SYNTAX_ERR, + CONSTRAINT_ERR, + TIMEOUT_ERR +}; + +static const char* sqlerror[] = { + "UNKNOWN_ERR", + "DATABASE_ERR", + "VERSION_ERR", + "TOO_LARGE_ERR", + "QUOTA_ERR", + "SYNTAX_ERR", + "CONSTRAINT_ERR", + "TIMEOUT_ERR", + 0 +}; + +#define THROW_SQL(error, desc) \ +{ \ + QScriptValue errorValue = context->throwError(desc); \ + errorValue.setProperty(QLatin1String("code"), error); \ + return errorValue; \ +} + + +static QString databaseFile(const QString& connectionName, QScriptEngine *engine) +{ + QmlScriptEngine *qmlengine = static_cast<QmlScriptEngine*>(engine); + QString basename = qmlengine->offlineStoragePath + + QDir::separator() + QLatin1String("Databases") + QDir::separator(); + basename += connectionName; + return basename; +} + + + +static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine) +{ + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(context->thisObject().data()); + int i = context->argument(0).toNumber(); + if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at()) + QSqlRecord r = query.record(); + QScriptValue row = engine->newObject(); + for (int j=0; j<r.count(); ++j) { + row.setProperty(r.fieldName(j), QScriptValue(engine,r.value(j).toString())); + } + return row; + } + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/) +{ + THROW_SQL(DATABASE_ERR,QmlEngine::tr("executeSql called outside transaction()")); +} + +static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QString sql = context->argument(0).toString(); + QSqlQuery query(db); + bool err = false; + + QScriptValue result; + + if (query.prepare(sql)) { + if (context->argumentCount() > 1) { + QScriptValue values = context->argument(1); + if (values.isObject()) { + for (QScriptValueIterator it(values); it.hasNext();) { + it.next(); + query.bindValue(it.name(),it.value().toVariant()); + } + } else { + query.bindValue(0,values.toVariant()); + } + } + if (query.exec()) { + result = engine->newObject(); + QmlScriptEngine *qmlengine = static_cast<QmlScriptEngine*>(engine); + if (!qmlengine->sqlQueryClass) + qmlengine->sqlQueryClass = new QmlSqlQueryScriptClass(engine); + QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass); + rows.setData(engine->newVariant(qVariantFromValue(query))); + rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration); + result.setProperty(QLatin1String("rows"),rows); + result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected()); + result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString()); + } else { + err = true; + } + } else { + err = true; + } + if (err) + THROW_SQL(DATABASE_ERR,query.lastError().text()); + return result; +} + +static QScriptValue qmlsqldatabase_executeSql_readonly(QScriptContext *context, QScriptEngine *engine) +{ + QString sql = context->argument(0).toString(); + if (sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) { + return qmlsqldatabase_executeSql(context,engine); + } else { + THROW_SQL(SYNTAX_ERR,QmlEngine::tr("Read-only Transaction")) + } +} + +static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine) +{ + if (context->argumentCount() < 2) + return engine->undefinedValue(); + + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QString from_version = context->argument(0).toString(); + QString to_version = context->argument(1).toString(); + QScriptValue callback = context->argument(2); + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1)); + QScriptValue tx = engine->newVariant(instance,qVariantFromValue(db)); + + QString foundvers = context->thisObject().property(QLatin1String("version")).toString(); + if (from_version!=foundvers) { + THROW_SQL(2,QmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers)); + return engine->undefinedValue(); + } + + bool ok = true; + if (callback.isFunction()) { + ok = false; + db.transaction(); + callback.call(QScriptValue(), QScriptValueList() << tx); + if (engine->hasUncaughtException()) { + db.rollback(); + } else { + if (!db.commit()) { + db.rollback(); + THROW_SQL(0,QmlEngine::tr("SQL transaction failed")); + } else { + ok = true; + } + } + } + + if (ok) { + context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly); + QSettings ini(databaseFile(db.connectionName(),engine)+QLatin1String(".ini"),QSettings::IniFormat); + ini.setValue(QLatin1String("Version"), to_version); + } + + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QScriptValue callback = context->argument(0); + if (!callback.isFunction()) + THROW_SQL(UNKNOWN_ERR,QmlEngine::tr("transaction: missing callback")); + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("executeSql"), + engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1)); + QScriptValue tx = engine->newVariant(instance,qVariantFromValue(db)); + + db.transaction(); + callback.call(QScriptValue(), QScriptValueList() << tx); + instance.setProperty(QLatin1String("executeSql"), + engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction)); + if (engine->hasUncaughtException()) { + db.rollback(); + } else { + if (!db.commit()) + db.rollback(); + } + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine) +{ + return qmlsqldatabase_transaction_shared(context,engine,false); +} +static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QScriptEngine *engine) +{ + return qmlsqldatabase_transaction_shared(context,engine,true); +} + +/* + Currently documented in doc/src/declarastive/globalobject.qdoc +*/ +static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine) +{ + QSqlDatabase database; + + QString dbname = context->argument(0).toString(); + QString dbversion = context->argument(1).toString(); + QString dbdescription = context->argument(2).toString(); + int dbestimatedsize = context->argument(3).toNumber(); + QScriptValue dbcreationCallback = context->argument(4); + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(dbname.toUtf8()); + QString dbid(QLatin1String(md5.result().toHex())); + + QString basename = databaseFile(dbid,engine); + bool created = false; + QString version = dbversion; + + { + QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); + + if (QSqlDatabase::connectionNames().contains(dbid)) { + database = QSqlDatabase::database(dbid); + version = ini.value(QLatin1String("Version")).toString(); + if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty()) + THROW_SQL(VERSION_ERR,QmlEngine::tr("SQL: database version mismatch")); + } else { + created = !QFile::exists(basename+QLatin1String(".sqlite")); + database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); + QDir().mkpath(basename); + if (created) { + ini.setValue(QLatin1String("Name"), dbname); + if (dbcreationCallback.isFunction()) + version = QString(); + ini.setValue(QLatin1String("Version"), version); + ini.setValue(QLatin1String("Description"), dbdescription); + ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize); + ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE")); + } else { + if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { + // Incompatible + THROW_SQL(VERSION_ERR,QmlEngine::tr("SQL: database version mismatch")); + } + version = ini.value(QLatin1String("Version")).toString(); + } + database.setDatabaseName(basename+QLatin1String(".sqlite")); + } + if (!database.isOpen()) + database.open(); + } + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1)); + instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1)); + instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly); + instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3)); + + QScriptValue result = engine->newVariant(instance,qVariantFromValue(database)); + + if (created && dbcreationCallback.isFunction()) { + dbcreationCallback.call(QScriptValue(), QScriptValueList() << result); + } + + return result; +} + +void qt_add_qmlsqldatabase(QScriptEngine *engine) +{ + QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open_sync, 4); + engine->globalObject().setProperty(QLatin1String("openDatabaseSync"), openDatabase); + + QScriptValue sqlExceptionPrototype = engine->newObject(); + for (int i=0; sqlerror[i]; ++i) + sqlExceptionPrototype.setProperty(QLatin1String(sqlerror[i]), + i,QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + engine->globalObject().setProperty(QLatin1String("SQLException"), sqlExceptionPrototype); +} + +/* +HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator). +We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward +through the data. +*/ + diff --git a/src/declarative/qml/qmlsqldatabase_p.h b/src/declarative/qml/qmlsqldatabase_p.h new file mode 100644 index 0000000..5a38bf0 --- /dev/null +++ b/src/declarative/qml/qmlsqldatabase_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSQLDATABASE_P_H +#define QMLSQLDATABASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +class QScriptEngine; +void qt_add_qmlsqldatabase(QScriptEngine *engine); + +#endif // QMLSQLDATABASE_P_H + diff --git a/src/declarative/qml/qmlstringconverters.cpp b/src/declarative/qml/qmlstringconverters.cpp new file mode 100644 index 0000000..2963ab5 --- /dev/null +++ b/src/declarative/qml/qmlstringconverters.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlstringconverters_p.h" + +#include <QtGui/qcolor.h> +#include <QtGui/qvector3d.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qsize.h> +#include <QtCore/qvariant.h> +#include <QtCore/qdatetime.h> + +QT_BEGIN_NAMESPACE + +static uchar fromHex(const uchar c, const uchar c2) +{ + uchar rv = 0; + if (c >= '0' && c <= '9') + rv += (c - '0') * 16; + else if (c >= 'A' && c <= 'F') + rv += (c - 'A' + 10) * 16; + else if (c >= 'a' && c <= 'f') + rv += (c - 'a' + 10) * 16; + + if (c2 >= '0' && c2 <= '9') + rv += (c2 - '0'); + else if (c2 >= 'A' && c2 <= 'F') + rv += (c2 - 'A' + 10); + else if (c2 >= 'a' && c2 <= 'f') + rv += (c2 - 'a' + 10); + + return rv; +} + +static uchar fromHex(const QString &s, int idx) +{ + uchar c = s.at(idx).toAscii(); + uchar c2 = s.at(idx + 1).toAscii(); + return fromHex(c, c2); +} + +QVariant QmlStringConverters::variantFromString(const QString &s) +{ + if (s.isEmpty()) + return QVariant(s); + if (s.startsWith(QLatin1Char('\'')) && s.endsWith(QLatin1Char('\''))) { + QString data = s.mid(1, s.length() - 2); + return QVariant(data); + } + bool ok = false; + QRectF r = rectFFromString(s, &ok); + if (ok) return QVariant(r); + QColor c = colorFromString(s, &ok); + if (ok) return QVariant(c); + QPointF p = pointFFromString(s, &ok); + if (ok) return QVariant(p); + QSizeF sz = sizeFFromString(s, &ok); + if (ok) return QVariant(sz); + QVector3D v = vector3DFromString(s, &ok); + if (ok) return qVariantFromValue(v); + + return QVariant(s); +} + +QVariant QmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok) +{ + switch (preferredType) { + case QMetaType::QColor: + return QVariant::fromValue(colorFromString(s, ok)); + case QMetaType::QDate: + return QVariant::fromValue(dateFromString(s, ok)); + case QMetaType::QTime: + return QVariant::fromValue(timeFromString(s, ok)); + case QMetaType::QDateTime: + return QVariant::fromValue(dateTimeFromString(s, ok)); + case QMetaType::QPointF: + return QVariant::fromValue(pointFFromString(s, ok)); + case QMetaType::QPoint: + return QVariant::fromValue(pointFFromString(s, ok).toPoint()); + case QMetaType::QSizeF: + return QVariant::fromValue(sizeFFromString(s, ok)); + case QMetaType::QSize: + return QVariant::fromValue(sizeFFromString(s, ok).toSize()); + case QMetaType::QRectF: + return QVariant::fromValue(rectFFromString(s, ok)); + case QMetaType::QRect: + return QVariant::fromValue(rectFFromString(s, ok).toRect()); + case QMetaType::QVector3D: + return QVariant::fromValue(vector3DFromString(s, ok)); + default: + if (ok) *ok = false; + return QVariant(); + } +} + +QColor QmlStringConverters::colorFromString(const QString &s, bool *ok) +{ + if (s.startsWith(QLatin1Char('#')) && s.length() == 9) { + uchar a = fromHex(s, 1); + uchar r = fromHex(s, 3); + uchar g = fromHex(s, 5); + uchar b = fromHex(s, 7); + if (ok) *ok = true; + return QColor(r, g, b, a); + } else { + QColor rv; + if (s.startsWith(QLatin1Char('#')) || QColor::colorNames().contains(s.toLower())) + rv = QColor(s); + if (ok) *ok = rv.isValid(); + return rv; + } +} + +QDate QmlStringConverters::dateFromString(const QString &s, bool *ok) +{ + QDate d = QDate::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} + +QTime QmlStringConverters::timeFromString(const QString &s, bool *ok) +{ + QTime t = QTime::fromString(s, Qt::ISODate); + if (ok) *ok = t.isValid(); + return t; +} + +QDateTime QmlStringConverters::dateTimeFromString(const QString &s, bool *ok) +{ + QDateTime d = QDateTime::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} + +//expects input of "x,y" +QPointF QmlStringConverters::pointFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 1) { + if (ok) + *ok = false; + return QPointF(); + } + + bool xGood, yGood; + int index = s.indexOf(QLatin1Char(',')); + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1).toDouble(&yGood); + if (!xGood || !yGood) { + if (ok) + *ok = false; + return QPointF(); + } + + if (ok) + *ok = true; + return QPointF(xCoord, yCoord); +} + +//expects input of "widthxheight" +QSizeF QmlStringConverters::sizeFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QSizeF(); + } + + bool wGood, hGood; + int index = s.indexOf(QLatin1Char('x')); + qreal width = s.left(index).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!wGood || !hGood) { + if (ok) + *ok = false; + return QSizeF(); + } + + if (ok) + *ok = true; + return QSizeF(width, height); +} + +//expects input of "x,y,widthxheight" //### use space instead of second comma? +QRectF QmlStringConverters::rectFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QRectF(); + } + + bool xGood, yGood, wGood, hGood; + int index = s.indexOf(QLatin1Char(',')); + qreal x = s.left(index).toDouble(&xGood); + int index2 = s.indexOf(QLatin1Char(','), index+1); + qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood); + index = s.indexOf(QLatin1Char('x'), index2+1); + qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!xGood || !yGood || !wGood || !hGood) { + if (ok) + *ok = false; + return QRectF(); + } + + if (ok) + *ok = true; + return QRectF(x, y, width, height); +} + +//expects input of "x,y,z" +QVector3D QmlStringConverters::vector3DFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 2) { + if (ok) + *ok = false; + return QVector3D(); + } + + bool xGood, yGood, zGood; + int index = s.indexOf(QLatin1Char(',')); + int index2 = s.indexOf(QLatin1Char(','), index+1); + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood); + qreal zCoord = s.mid(index2+1).toDouble(&zGood); + if (!xGood || !yGood || !zGood) { + if (ok) + *ok = false; + return QVector3D(); + } + + if (ok) + *ok = true; + return QVector3D(xCoord, yCoord, zCoord); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlstringconverters_p.h b/src/declarative/qml/qmlstringconverters_p.h new file mode 100644 index 0000000..dfc59ce --- /dev/null +++ b/src/declarative/qml/qmlstringconverters_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSTRINGCONVERTERS_P_H +#define QMLSTRINGCONVERTERS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> + +class QColor; +class QPointF; +class QSizeF; +class QRectF; +class QString; +class QByteArray; +class QVector3D; + +QT_BEGIN_NAMESPACE + +// XXX - Bauhaus currently uses these methods which is why they're exported +namespace QmlStringConverters +{ + QVariant Q_DECLARATIVE_EXPORT variantFromString(const QString &); + QVariant Q_DECLARATIVE_EXPORT variantFromString(const QString &, int preferredType, bool *ok = 0); + + QColor Q_DECLARATIVE_EXPORT colorFromString(const QString &, bool *ok = 0); + QDate Q_DECLARATIVE_EXPORT dateFromString(const QString &, bool *ok = 0); + QTime Q_DECLARATIVE_EXPORT timeFromString(const QString &, bool *ok = 0); + QDateTime Q_DECLARATIVE_EXPORT dateTimeFromString(const QString &, bool *ok = 0); + QPointF Q_DECLARATIVE_EXPORT pointFFromString(const QString &, bool *ok = 0); + QSizeF Q_DECLARATIVE_EXPORT sizeFFromString(const QString &, bool *ok = 0); + QRectF Q_DECLARATIVE_EXPORT rectFFromString(const QString &, bool *ok = 0); + QVector3D Q_DECLARATIVE_EXPORT vector3DFromString(const QString &, bool *ok = 0); +}; + +QT_END_NAMESPACE + +#endif // QMLSTRINGCONVERTERS_P_H diff --git a/src/declarative/qml/qmltypenamecache.cpp b/src/declarative/qml/qmltypenamecache.cpp new file mode 100644 index 0000000..7e68492 --- /dev/null +++ b/src/declarative/qml/qmltypenamecache.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmltypenamecache_p.h" + +#include "qmlengine_p.h" + +QT_BEGIN_NAMESPACE + +QmlTypeNameCache::QmlTypeNameCache(QmlEngine *e) +: QmlCleanup(e), engine(e) +{ +} + +QmlTypeNameCache::~QmlTypeNameCache() +{ + clear(); +} + +void QmlTypeNameCache::clear() +{ + qDeleteAll(stringCache); + stringCache.clear(); + identifierCache.clear(); + engine = 0; +} + +void QmlTypeNameCache::add(const QString &name, QmlType *type) +{ + if (stringCache.contains(name)) + return; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->type = type; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); +} + +void QmlTypeNameCache::add(const QString &name, QmlTypeNameCache *typeNamespace) +{ + if (stringCache.contains(name)) + return; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->typeNamespace = typeNamespace; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); + typeNamespace->addref(); +} + +QmlTypeNameCache::Data *QmlTypeNameCache::data(const QString &id) const +{ + return stringCache.value(id); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmltypenamecache_p.h b/src/declarative/qml/qmltypenamecache_p.h new file mode 100644 index 0000000..754399f --- /dev/null +++ b/src/declarative/qml/qmltypenamecache_p.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLTYPENAMECACHE_P_H +#define QMLTYPENAMECACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlrefcount_p.h" +#include "qmlcleanup_p.h" + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlTypeNameCache : public QmlRefCount, public QmlCleanup +{ +public: + QmlTypeNameCache(QmlEngine *); + virtual ~QmlTypeNameCache(); + + struct Data { + inline Data(); + inline ~Data(); + QmlType *type; + QmlTypeNameCache *typeNamespace; + }; + + void add(const QString &, QmlType *); + void add(const QString &, QmlTypeNameCache *); + + Data *data(const QString &) const; + inline Data *data(const QScriptDeclarativeClass::Identifier &id) const; + +protected: + virtual void clear(); + +private: + struct RData : public Data { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; + typedef QHash<QString, RData *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +QmlTypeNameCache::Data::Data() +: type(0), typeNamespace(0) +{ +} + +QmlTypeNameCache::Data::~Data() +{ + if (typeNamespace) typeNamespace->release(); +} + +QmlTypeNameCache::Data *QmlTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +QT_END_NAMESPACE + +#endif // QMLTYPENAMECACHE_P_H + diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp new file mode 100644 index 0000000..14c8652 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmltypenamescriptclass_p.h" + +#include "qmlengine_p.h" +#include "qmltypenamecache_p.h" + +QT_BEGIN_NAMESPACE + +struct TypeNameData : public QScriptDeclarativeClass::Object { + TypeNameData(QObject *o, QmlType *t, QmlTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {} + TypeNameData(QObject *o, QmlTypeNameCache *n, QmlTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) { + if (typeNamespace) typeNamespace->addref(); + } + ~TypeNameData() { + if (typeNamespace) typeNamespace->release(); + } + + QObject *object; + QmlType *type; + QmlTypeNameCache *typeNamespace; + QmlTypeNameScriptClass::TypeNameMode mode; +}; + +QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *bindEngine) +: QmlScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), + engine(bindEngine), object(0), type(0) +{ +} + +QmlTypeNameScriptClass::~QmlTypeNameScriptClass() +{ +} + +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlType *type, TypeNameMode mode) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode)); +} + +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlTypeNameCache *ns, TypeNameMode mode) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode)); +} + +QScriptClass::QueryFlags +QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + + TypeNameData *data = (TypeNameData *)obj; + + object = 0; + type = 0; + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + if (data->typeNamespace) { + + QmlTypeNameCache::Data *d = data->typeNamespace->data(name); + if (d && d->type) { + type = d->type; + return QScriptClass::HandlesReadAccess; + } else { + return 0; + } + + } else { + Q_ASSERT(data->type); + + QString strName = toString(name); + + if (strName.at(0).isUpper()) { + // Must be an enum + if (data->mode == IncludeEnums) { + // ### Optimize + QByteArray enumName = strName.toUtf8(); + const QMetaObject *metaObject = data->type->baseMetaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + int value = e.keyToValue(enumName.constData()); + if (value != -1) { + enumValue = value; + return QScriptClass::HandlesReadAccess; + } + } + } + return 0; + } else if (data->object) { + // Must be an attached property + object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); + if (!object) return 0; + return ep->objectClass->queryProperty(object, name, flags, 0); + } + } + + return 0; +} + +QmlTypeNameScriptClass::ScriptValue +QmlTypeNameScriptClass::property(Object *obj, const Identifier &name) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + if (type) { + return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode)); + } else if (object) { + return ep->objectClass->property(object, name); + } else { + return Value(scriptEngine, enumValue); + } +} + +void QmlTypeNameScriptClass::setProperty(Object *o, const Identifier &n, const QScriptValue &v) +{ + Q_ASSERT(object); + Q_ASSERT(!type); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + ep->objectClass->setProperty(((TypeNameData *)o)->object, n, v); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmltypenamescriptclass_p.h b/src/declarative/qml/qmltypenamescriptclass_p.h new file mode 100644 index 0000000..cf8c621 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLTYPENAMESCRIPTCLASS_P_H +#define QMLTYPENAMESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include "qmlengine_p.h" + +#include <QtScript/qscriptclass.h> + +#include <private/qmlscriptclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlType; +class QmlTypeNameCache; +class QmlTypeNameScriptClass : public QmlScriptClass +{ +public: + QmlTypeNameScriptClass(QmlEngine *); + ~QmlTypeNameScriptClass(); + + enum TypeNameMode { IncludeEnums, ExcludeEnums }; + QScriptValue newObject(QObject *, QmlType *, TypeNameMode = IncludeEnums); + QScriptValue newObject(QObject *, QmlTypeNameCache *, TypeNameMode = IncludeEnums); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual ScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + +private: + QmlEngine *engine; + QObject *object; + QmlType *type; + quint32 enumValue; +}; + +QT_END_NAMESPACE + +#endif // QMLTYPENAMESCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlvaluetype.cpp b/src/declarative/qml/qmlvaluetype.cpp new file mode 100644 index 0000000..058fd6e --- /dev/null +++ b/src/declarative/qml/qmlvaluetype.cpp @@ -0,0 +1,636 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvaluetype_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QmlValueTypeFactory::QmlValueTypeFactory() +{ + // ### Optimize + for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii) + valueTypes[ii] = valueType(ii); +} + +QmlValueTypeFactory::~QmlValueTypeFactory() +{ + for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii) + delete valueTypes[ii]; +} + +QmlValueType *QmlValueTypeFactory::valueType(int t) +{ + switch (t) { + case QVariant::Point: + return new QmlPointValueType; + case QVariant::PointF: + return new QmlPointFValueType; + case QVariant::Size: + return new QmlSizeValueType; + case QVariant::SizeF: + return new QmlSizeFValueType; + case QVariant::Rect: + return new QmlRectValueType; + case QVariant::RectF: + return new QmlRectFValueType; + case QVariant::Vector3D: + return new QmlVector3DValueType; + case QVariant::Font: + return new QmlFontValueType; + default: + return 0; + } +} + +QmlValueType::QmlValueType(QObject *parent) +: QObject(parent) +{ +} + +QmlPointFValueType::QmlPointFValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlPointFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &point, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlPointFValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &point, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlPointFValueType::value() +{ + return QVariant(point); +} + +void QmlPointFValueType::setValue(QVariant value) +{ + point = qvariant_cast<QPointF>(value); +} + +qreal QmlPointFValueType::x() const +{ + return point.x(); +} + +qreal QmlPointFValueType::y() const +{ + return point.y(); +} + +void QmlPointFValueType::setX(qreal x) +{ + point.setX(x); +} + +void QmlPointFValueType::setY(qreal y) +{ + point.setY(y); +} + +QmlPointValueType::QmlPointValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlPointValueType::read(QObject *obj, int idx) +{ + void *a[] = { &point, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlPointValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &point, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlPointValueType::value() +{ + return QVariant(point); +} + +void QmlPointValueType::setValue(QVariant value) +{ + point = qvariant_cast<QPoint>(value); +} + +int QmlPointValueType::x() const +{ + return point.x(); +} + +int QmlPointValueType::y() const +{ + return point.y(); +} + +void QmlPointValueType::setX(int x) +{ + point.setX(x); +} + +void QmlPointValueType::setY(int y) +{ + point.setY(y); +} + +QmlSizeFValueType::QmlSizeFValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlSizeFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &size, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlSizeFValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &size, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlSizeFValueType::value() +{ + return QVariant(size); +} + +void QmlSizeFValueType::setValue(QVariant value) +{ + size = qvariant_cast<QSizeF>(value); +} + +qreal QmlSizeFValueType::width() const +{ + return size.width(); +} + +qreal QmlSizeFValueType::height() const +{ + return size.height(); +} + +void QmlSizeFValueType::setWidth(qreal w) +{ + size.setWidth(w); +} + +void QmlSizeFValueType::setHeight(qreal h) +{ + size.setHeight(h); +} + +QmlSizeValueType::QmlSizeValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlSizeValueType::read(QObject *obj, int idx) +{ + void *a[] = { &size, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlSizeValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &size, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlSizeValueType::value() +{ + return QVariant(size); +} + +void QmlSizeValueType::setValue(QVariant value) +{ + size = qvariant_cast<QSize>(value); +} + +int QmlSizeValueType::width() const +{ + return size.width(); +} + +int QmlSizeValueType::height() const +{ + return size.height(); +} + +void QmlSizeValueType::setWidth(int w) +{ + size.setWidth(w); +} + +void QmlSizeValueType::setHeight(int h) +{ + size.setHeight(h); +} + +QmlRectFValueType::QmlRectFValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlRectFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &rect, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlRectFValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &rect, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlRectFValueType::value() +{ + return QVariant(rect); +} + +void QmlRectFValueType::setValue(QVariant value) +{ + rect = qvariant_cast<QRectF>(value); +} + +qreal QmlRectFValueType::x() const +{ + return rect.x(); +} + +qreal QmlRectFValueType::y() const +{ + return rect.y(); +} + +void QmlRectFValueType::setX(qreal x) +{ + rect.moveLeft(x); +} + +void QmlRectFValueType::setY(qreal y) +{ + rect.moveTop(y); +} + +qreal QmlRectFValueType::width() const +{ + return rect.width(); +} + +qreal QmlRectFValueType::height() const +{ + return rect.height(); +} + +void QmlRectFValueType::setWidth(qreal w) +{ + rect.setWidth(w); +} + +void QmlRectFValueType::setHeight(qreal h) +{ + rect.setHeight(h); +} + +QmlRectValueType::QmlRectValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlRectValueType::read(QObject *obj, int idx) +{ + void *a[] = { &rect, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlRectValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &rect, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlRectValueType::value() +{ + return QVariant(rect); +} + +void QmlRectValueType::setValue(QVariant value) +{ + rect = qvariant_cast<QRect>(value); +} + +int QmlRectValueType::x() const +{ + return rect.x(); +} + +int QmlRectValueType::y() const +{ + return rect.y(); +} + +void QmlRectValueType::setX(int x) +{ + rect.moveLeft(x); +} + +void QmlRectValueType::setY(int y) +{ + rect.moveTop(y); +} + +int QmlRectValueType::width() const +{ + return rect.width(); +} + +int QmlRectValueType::height() const +{ + return rect.height(); +} + +void QmlRectValueType::setWidth(int w) +{ + rect.setWidth(w); +} + +void QmlRectValueType::setHeight(int h) +{ + rect.setHeight(h); +} + +QmlVector3DValueType::QmlVector3DValueType(QObject *parent) +: QmlValueType(parent) +{ +} + +void QmlVector3DValueType::read(QObject *obj, int idx) +{ + void *a[] = { &vector, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlVector3DValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &vector, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlVector3DValueType::value() +{ + return QVariant(vector); +} + +void QmlVector3DValueType::setValue(QVariant value) +{ + vector = qvariant_cast<QVector3D>(value); +} + +qreal QmlVector3DValueType::x() const +{ + return vector.x(); +} + +qreal QmlVector3DValueType::y() const +{ + return vector.y(); +} + +qreal QmlVector3DValueType::z() const +{ + return vector.z(); +} + +void QmlVector3DValueType::setX(qreal x) +{ + vector.setX(x); +} + +void QmlVector3DValueType::setY(qreal y) +{ + vector.setY(y); +} + +void QmlVector3DValueType::setZ(qreal z) +{ + vector.setZ(z); +} + +QmlFontValueType::QmlFontValueType(QObject *parent) +: QmlValueType(parent), hasPixelSize(false) +{ +} + +void QmlFontValueType::read(QObject *obj, int idx) +{ + void *a[] = { &font, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QmlFontValueType::write(QObject *obj, int idx, QmlMetaProperty::WriteFlags flags) +{ + int status = -1; + void *a[] = { &font, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QmlFontValueType::value() +{ + return QVariant(font); +} + +void QmlFontValueType::setValue(QVariant value) +{ + font = qvariant_cast<QFont>(value); +} + + +QString QmlFontValueType::family() const +{ + return font.family(); +} + +void QmlFontValueType::setFamily(const QString &family) +{ + font.setFamily(family); +} + +bool QmlFontValueType::bold() const +{ + return font.bold(); +} + +void QmlFontValueType::setBold(bool b) +{ + font.setBold(b); +} + +QmlFontValueType::FontWeight QmlFontValueType::weight() const +{ + return (QmlFontValueType::FontWeight)font.weight(); +} + +void QmlFontValueType::setWeight(QmlFontValueType::FontWeight w) +{ + font.setWeight((QFont::Weight)w); +} + +bool QmlFontValueType::italic() const +{ + return font.italic(); +} + +void QmlFontValueType::setItalic(bool b) +{ + font.setItalic(b); +} + +bool QmlFontValueType::underline() const +{ + return font.underline(); +} + +void QmlFontValueType::setUnderline(bool b) +{ + font.setUnderline(b); +} + +bool QmlFontValueType::overline() const +{ + return font.overline(); +} + +void QmlFontValueType::setOverline(bool b) +{ + font.setOverline(b); +} + +bool QmlFontValueType::strikeout() const +{ + return font.strikeOut(); +} + +void QmlFontValueType::setStrikeout(bool b) +{ + font.setStrikeOut(b); +} + +qreal QmlFontValueType::pointSize() const +{ + return font.pointSizeF(); +} + +void QmlFontValueType::setPointSize(qreal size) +{ + if (hasPixelSize) { + qWarning() << "Both point size and pixel size set. Using pixel size."; + return; + } + + if (size >= 0.0) + font.setPointSizeF(size); +} + +int QmlFontValueType::pixelSize() const +{ + return font.pixelSize(); +} + +void QmlFontValueType::setPixelSize(int size) +{ + if (size >=0) { + font.setPixelSize(size); + hasPixelSize = true; + } else { + hasPixelSize = false; + } +} + +QmlFontValueType::Capitalization QmlFontValueType::capitalization() const +{ + return (QmlFontValueType::Capitalization)font.capitalization(); +} + +void QmlFontValueType::setCapitalization(QmlFontValueType::Capitalization c) +{ + font.setCapitalization((QFont::Capitalization)c); +} + +qreal QmlFontValueType::letterSpacing() const +{ + return font.letterSpacing(); +} + +void QmlFontValueType::setLetterSpacing(qreal size) +{ + font.setLetterSpacing(QFont::PercentageSpacing, size); +} + +qreal QmlFontValueType::wordSpacing() const +{ + return font.wordSpacing(); +} + +void QmlFontValueType::setWordSpacing(qreal size) +{ + font.setWordSpacing(size); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvaluetype_p.h b/src/declarative/qml/qmlvaluetype_p.h new file mode 100644 index 0000000..800edee --- /dev/null +++ b/src/declarative/qml/qmlvaluetype_p.h @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVALUETYPE_P_H +#define QMLVALUETYPE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlmetaproperty.h" + +#include <QtCore/qobject.h> +#include <QtCore/qrect.h> +#include <QtCore/qvariant.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qfont.h> + +QT_BEGIN_NAMESPACE + +class Q_DECLARATIVE_EXPORT QmlValueType : public QObject +{ + Q_OBJECT +public: + QmlValueType(QObject *parent = 0); + virtual void read(QObject *, int) = 0; + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags flags) = 0; + virtual QVariant value() = 0; + virtual void setValue(QVariant) = 0; +}; + +class Q_DECLARATIVE_EXPORT QmlValueTypeFactory +{ +public: + QmlValueTypeFactory(); + ~QmlValueTypeFactory(); + static QmlValueType *valueType(int); + + QmlValueType *valueTypes[QVariant::UserType - 1]; + QmlValueType *operator[](int idx) const { return valueTypes[idx]; } +}; + +class Q_AUTOTEST_EXPORT QmlPointFValueType : public QmlValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_OBJECT +public: + QmlPointFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + void setX(qreal); + void setY(qreal); + +private: + QPointF point; +}; + +class Q_AUTOTEST_EXPORT QmlPointValueType : public QmlValueType +{ + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_OBJECT +public: + QmlPointValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int x() const; + int y() const; + void setX(int); + void setY(int); + +private: + QPoint point; +}; + +class Q_AUTOTEST_EXPORT QmlSizeFValueType : public QmlValueType +{ + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_OBJECT +public: + QmlSizeFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal width() const; + qreal height() const; + void setWidth(qreal); + void setHeight(qreal); + +private: + QSizeF size; +}; + +class Q_AUTOTEST_EXPORT QmlSizeValueType : public QmlValueType +{ + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(int height READ height WRITE setHeight) + Q_OBJECT +public: + QmlSizeValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int width() const; + int height() const; + void setWidth(int); + void setHeight(int); + +private: + QSize size; +}; + +class Q_AUTOTEST_EXPORT QmlRectFValueType : public QmlValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_OBJECT +public: + QmlRectFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + void setX(qreal); + void setY(qreal); + + qreal width() const; + qreal height() const; + void setWidth(qreal); + void setHeight(qreal); + +private: + QRectF rect; +}; + +class Q_AUTOTEST_EXPORT QmlRectValueType : public QmlValueType +{ + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(int height READ height WRITE setHeight) + Q_OBJECT +public: + QmlRectValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int x() const; + int y() const; + void setX(int); + void setY(int); + + int width() const; + int height() const; + void setWidth(int); + void setHeight(int); + +private: + QRect rect; +}; + +class Q_AUTOTEST_EXPORT QmlVector3DValueType : public QmlValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal z READ z WRITE setZ) + Q_OBJECT +public: + QmlVector3DValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + qreal z() const; + void setX(qreal); + void setY(qreal); + void setZ(qreal); + +private: + QVector3D vector; +}; + +class Q_AUTOTEST_EXPORT QmlFontValueType : public QmlValueType +{ + Q_OBJECT + Q_ENUMS(FontWeight) + Q_ENUMS(Capitalization) + + Q_PROPERTY(QString family READ family WRITE setFamily) + Q_PROPERTY(bool bold READ bold WRITE setBold) + Q_PROPERTY(FontWeight weight READ weight WRITE setWeight) + Q_PROPERTY(bool italic READ italic WRITE setItalic) + Q_PROPERTY(bool underline READ underline WRITE setUnderline) + Q_PROPERTY(bool overline READ overline WRITE setOverline) + Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout) + Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize) + Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize) + Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization) + Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing) + Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing) + +public: + enum FontWeight { Light = QFont::Light, + Normal = QFont::Normal, + DemiBold = QFont::DemiBold, + Bold = QFont::Bold, + Black = QFont::Black }; + enum Capitalization { MixedCase = QFont::MixedCase, + AllUppercase = QFont::AllUppercase, + AllLowercase = QFont::AllLowercase, + SmallCaps = QFont::SmallCaps, + Capitalize = QFont::Capitalize }; + + QmlFontValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QmlMetaProperty::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + QString family() const; + void setFamily(const QString &); + + bool bold() const; + void setBold(bool b); + + FontWeight weight() const; + void setWeight(FontWeight); + + bool italic() const; + void setItalic(bool b); + + bool underline() const; + void setUnderline(bool b); + + bool overline() const; + void setOverline(bool b); + + bool strikeout() const; + void setStrikeout(bool b); + + qreal pointSize() const; + void setPointSize(qreal size); + + int pixelSize() const; + void setPixelSize(int size); + + Capitalization capitalization() const; + void setCapitalization(Capitalization); + + qreal letterSpacing() const; + void setLetterSpacing(qreal spacing); + + qreal wordSpacing() const; + void setWordSpacing(qreal spacing); + +private: + QFont font; + bool hasPixelSize; +}; + +QT_END_NAMESPACE + +#endif // QMLVALUETYPE_P_H diff --git a/src/declarative/qml/qmlvaluetypescriptclass.cpp b/src/declarative/qml/qmlvaluetypescriptclass.cpp new file mode 100644 index 0000000..5e222a1 --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvaluetypescriptclass_p.h" + +#include "qmlengine_p.h" +#include "qmlguard_p.h" + +QT_BEGIN_NAMESPACE + +struct QmlValueTypeReference : public QScriptDeclarativeClass::Object { + QmlValueType *type; + QmlGuard<QObject> object; + int property; +}; + +QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine) +: QmlScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) +{ +} + +QmlValueTypeScriptClass::~QmlValueTypeScriptClass() +{ +} + +QScriptValue QmlValueTypeScriptClass::newObject(QObject *object, int coreIndex, QmlValueType *type) +{ + QmlValueTypeReference *ref = new QmlValueTypeReference; + ref->type = type; + ref->object = object; + ref->property = coreIndex; + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + return QScriptDeclarativeClass::newObject(scriptEngine, this, ref); +} + +QScriptClass::QueryFlags +QmlValueTypeScriptClass::queryProperty(Object *obj, const Identifier &name, + QScriptClass::QueryFlags) +{ + QmlValueTypeReference *ref = static_cast<QmlValueTypeReference *>(obj); + + m_lastIndex = -1; + + if (!ref->object) + return 0; + + QByteArray propName = toString(name).toUtf8(); + + m_lastIndex = ref->type->metaObject()->indexOfProperty(propName.constData()); + if (m_lastIndex == -1) + return 0; + + QMetaProperty prop = ref->object->metaObject()->property(m_lastIndex); + + QScriptClass::QueryFlags rv = + QScriptClass::HandlesReadAccess; + if (prop.isWritable()) + rv |= QScriptClass::HandlesWriteAccess; + + return rv; +} + +QmlValueTypeScriptClass::ScriptValue QmlValueTypeScriptClass::property(Object *obj, const Identifier &) +{ + QmlValueTypeReference *ref = static_cast<QmlValueTypeReference *>(obj); + + QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); + ref->type->read(ref->object, ref->property); + QVariant rv = p.read(ref->type); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + return Value(scriptEngine, static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv)); +} + +void QmlValueTypeScriptClass::setProperty(Object *obj, const Identifier &, + const QScriptValue &value) +{ + QmlValueTypeReference *ref = static_cast<QmlValueTypeReference *>(obj); + + QVariant v = QmlScriptClass::toVariant(engine, value); + + ref->type->read(ref->object, ref->property); + QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); + p.write(ref->type, v); + ref->type->write(ref->object, ref->property, 0); +} + +QVariant QmlValueTypeScriptClass::toVariant(Object *obj, bool *ok) +{ + QmlValueTypeReference *ref = static_cast<QmlValueTypeReference *>(obj); + + if (ok) *ok = true; + + if (ref->object) { + ref->type->read(ref->object, ref->property); + return ref->type->value(); + } else { + return QVariant(); + } +} + +QVariant QmlValueTypeScriptClass::toVariant(const QScriptValue &value) +{ + Q_ASSERT(scriptClass(value) == this); + + return toVariant(object(value), 0); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlvaluetypescriptclass_p.h b/src/declarative/qml/qmlvaluetypescriptclass_p.h new file mode 100644 index 0000000..09af967 --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVALUETYPESCRIPTCLASS_P_H +#define QMLVALUETYPESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include <private/qmlscriptclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlValueType; +class QmlValueTypeScriptClass : public QmlScriptClass +{ +public: + QmlValueTypeScriptClass(QmlEngine *); + ~QmlValueTypeScriptClass(); + + QScriptValue newObject(QObject *object, int coreIndex, QmlValueType *); + + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual ScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + + virtual QVariant toVariant(Object *, bool *ok = 0); + QVariant toVariant(const QScriptValue &); +private: + QmlEngine *engine; + int m_lastIndex; +}; + +QT_END_NAMESPACE + +#endif // QMLVALUETYPESCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp new file mode 100644 index 0000000..e9a0449 --- /dev/null +++ b/src/declarative/qml/qmlvme.cpp @@ -0,0 +1,891 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvme_p.h" + +#include "qmlcompiler_p.h" +#include "qmlboundsignal_p.h" +#include "qmlstringconverters_p.h" +#include "qmetaobjectbuilder_p.h" +#include "qmldeclarativedata_p.h" +#include "qml.h" +#include "qmlcustomparser_p.h" +#include "qmlengine.h" +#include "qmlcontext.h" +#include "qmlcomponent.h" +#include "qmlbinding.h" +#include "qmlengine_p.h" +#include "qmlcomponent_p.h" +#include "qmlvmemetaobject_p.h" +#include "qmlbinding_p.h" +#include "qmlcontext_p.h" +#include "qmlcompiledbindings_p.h" +#include "qmlglobal_p.h" +#include "qmlscriptstring.h" + +#include <qfxperf_p_p.h> + +#include <QStack> +#include <QWidget> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QtCore/qdebug.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +QmlVME::QmlVME() +{ +} + +#define VME_EXCEPTION(desc) \ + { \ + QmlError error; \ + error.setDescription(desc.trimmed()); \ + error.setLine(instr.line); \ + error.setUrl(comp->url); \ + vmeErrors << error; \ + break; \ + } + +struct ListInstance +{ + ListInstance() {} + ListInstance(QList<void *> *q, int t) + : type(t), qListInterface(q), qmlListInterface(0) {} + ListInstance(QmlPrivate::ListInterface *q, int t) + : type(t), qListInterface(0), qmlListInterface(q) {} + + int type; + QList<void *> *qListInterface; + QmlPrivate::ListInterface *qmlListInterface; +}; + +QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledData *comp, + int start, int count, + const QBitField &bindingSkipList) +{ + QmlVMEStack<QObject *> stack; + + if (start == -1) start = 0; + if (count == -1) count = comp->bytecode.count(); + + return run(stack, ctxt, comp, start, count, bindingSkipList); +} + +void QmlVME::runDeferred(QObject *object) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object); + + if (!data || !data->context || !data->deferredComponent) + return; + + QmlContext *ctxt = data->context; + QmlCompiledData *comp = data->deferredComponent; + int start = data->deferredIdx + 1; + int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; + QmlVMEStack<QObject *> stack; + stack.push(object); + + run(stack, ctxt, comp, start, count, QBitField()); +} + +QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt, + QmlCompiledData *comp, + int start, int count, + const QBitField &bindingSkipList) +{ + Q_ASSERT(comp); + Q_ASSERT(ctxt); + const QList<QmlCompiledData::TypeReference> &types = comp->types; + const QList<QString> &primitives = comp->primitives; + const QList<QByteArray> &datas = comp->datas; + const QList<QmlCompiledData::CustomTypeData> &customTypeData = comp->customTypeData; + const QList<int> &intData = comp->intData; + const QList<float> &floatData = comp->floatData; + const QList<QmlPropertyCache *> &propertyCaches = comp->propertyCaches; + const QList<QmlParser::Object::ScriptBlock> &scripts = comp->scripts; + const QList<QUrl> &urls = comp->urls; + + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bindValues; + QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus; + + QmlVMEStack<ListInstance> qliststack; + + vmeErrors.clear(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(ctxt->engine()); + QmlContextPrivate *cp = (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + int status = -1; //for dbus + QmlMetaProperty::WriteFlags flags = QmlMetaProperty::BypassInterceptor; + + for (int ii = start; !isError() && ii < (start + count); ++ii) { + const QmlInstruction &instr = comp->bytecode.at(ii); + + switch(instr.type) { + case QmlInstruction::Init: + { + if (instr.init.bindingsSize) + bindValues = QmlEnginePrivate::SimpleList<QmlAbstractBinding>(instr.init.bindingsSize); + if (instr.init.parserStatusSize) + parserStatus = QmlEnginePrivate::SimpleList<QmlParserStatus>(instr.init.parserStatusSize); + if (instr.init.contextCache != -1) + cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); + if (instr.init.compiledBinding != -1) + cp->optimizedBindings = new QmlCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt); + } + break; + + case QmlInstruction::CreateObject: + { + QBitField bindings; + if (instr.create.bindingBits != -1) { + const QByteArray &bits = datas.at(instr.create.bindingBits); + bindings = QBitField((const quint32*)bits.constData(), + bits.size() * 8); + } + if (stack.isEmpty()) + bindings = bindings.united(bindingSkipList); + + QObject *o = + types.at(instr.create.type).createInstance(ctxt, bindings); + if (!o) { + if(types.at(instr.create.type).component) + vmeErrors << types.at(instr.create.type).component->errors(); + + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.create.type).className))); + } + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(o); + Q_ASSERT(ddata); + ddata->outerContext = ctxt; + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.create.column; + + if (instr.create.data != -1) { + QmlCustomParser *customParser = + types.at(instr.create.type).type->customParser(); + customParser->setCustomData(o, datas.at(instr.create.data)); + } + if (!stack.isEmpty()) { + QObject *parent = stack.top(); + if (o->isWidgetType()) { + QWidget *widget = static_cast<QWidget*>(o); + if (parent->isWidgetType()) { + QWidget *parentWidget = static_cast<QWidget*>(parent); + widget->setParent(parentWidget); + } else { + // TODO: parent might be a layout + } + } else { + QmlGraphics_setParent_noEvent(o, parent); + // o->setParent(parent); + } + } + stack.push(o); + } + break; + + case QmlInstruction::SetId: + { + QObject *target = stack.top(); + cp->setIdProperty(instr.setId.index, target); + } + break; + + + case QmlInstruction::SetDefault: + { + QObject *target = stack.top(); + ctxt->addDefaultObject(target); + } + break; + + case QmlInstruction::CreateComponent: + { + QObject *qcomp = new QmlComponent(ctxt->engine(), comp, ii + 1, instr.createComponent.count, stack.isEmpty() ? 0 : stack.top()); + + QmlEngine::setContextForObject(qcomp, ctxt); + QmlDeclarativeData *ddata = QmlDeclarativeData::get(qcomp); + Q_ASSERT(ddata); + ddata->outerContext = ctxt; + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.create.column; + + stack.push(qcomp); + ii += instr.createComponent.count; + } + break; + + case QmlInstruction::StoreMetaObject: + { + QObject *target = stack.top(); + + QMetaObject mo; + const QByteArray &metadata = datas.at(instr.storeMeta.data); + QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + + const QmlVMEMetaData *data = + (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + + (void)new QmlVMEMetaObject(target, &mo, data, comp); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); + } + break; + + case QmlInstruction::StoreVariant: + { + QObject *target = stack.top(); + // XXX - can be more efficient + QVariant v = QmlStringConverters::variantFromString(primitives.at(instr.storeString.value)); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QmlInstruction::StoreString: + { + QObject *target = stack.top(); + void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QmlInstruction::StoreUrl: + { + QObject *target = stack.top(); + void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeUrl.propertyIndex, a); + } + break; + + case QmlInstruction::StoreFloat: + { + QObject *target = stack.top(); + float f = instr.storeFloat.value; + void *a[] = { &f, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeFloat.propertyIndex, a); + } + break; + + case QmlInstruction::StoreDouble: + { + QObject *target = stack.top(); + double d = instr.storeDouble.value; + void *a[] = { &d, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDouble.propertyIndex, a); + } + break; + + case QmlInstruction::StoreBool: + { + QObject *target = stack.top(); + void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeBool.propertyIndex, a); + } + break; + + case QmlInstruction::StoreInteger: + { + QObject *target = stack.top(); + void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeInteger.propertyIndex, a); + } + break; + + case QmlInstruction::StoreColor: + { + QObject *target = stack.top(); + QColor c = QColor::fromRgba(instr.storeColor.value); + void *a[] = { &c, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeColor.propertyIndex, a); + } + break; + + case QmlInstruction::StoreDate: + { + QObject *target = stack.top(); + QDate d = QDate::fromJulianDay(instr.storeDate.value); + void *a[] = { &d, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDate.propertyIndex, a); + } + break; + + case QmlInstruction::StoreTime: + { + QObject *target = stack.top(); + QTime t; + t.setHMS(intData.at(instr.storeTime.valueIndex), + intData.at(instr.storeTime.valueIndex+1), + intData.at(instr.storeTime.valueIndex+2), + intData.at(instr.storeTime.valueIndex+3)); + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeTime.propertyIndex, a); + } + break; + + case QmlInstruction::StoreDateTime: + { + QObject *target = stack.top(); + QTime t; + t.setHMS(intData.at(instr.storeDateTime.valueIndex+1), + intData.at(instr.storeDateTime.valueIndex+2), + intData.at(instr.storeDateTime.valueIndex+3), + intData.at(instr.storeDateTime.valueIndex+4)); + QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t); + void *a[] = { &dt, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDateTime.propertyIndex, a); + } + break; + + case QmlInstruction::StorePoint: + { + QObject *target = stack.top(); + QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toPoint(); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StorePointF: + { + QObject *target = stack.top(); + QPointF p(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreSize: + { + QObject *target = stack.top(); + QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toSize(); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreSizeF: + { + QObject *target = stack.top(); + QSizeF s(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + void *a[] = { &s, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreRect: + { + QObject *target = stack.top(); + QRect r = QRectF(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)).toRect(); + void *a[] = { &r, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QmlInstruction::StoreRectF: + { + QObject *target = stack.top(); + QRectF r(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)); + void *a[] = { &r, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QmlInstruction::StoreVector3D: + { + QObject *target = stack.top(); + QVector3D p(floatData.at(instr.storeVector3D.valueIndex), + floatData.at(instr.storeVector3D.valueIndex+1), + floatData.at(instr.storeVector3D.valueIndex+2)); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeVector3D.propertyIndex, a); + } + break; + + case QmlInstruction::StoreObject: + { + QObject *assignObj = stack.pop(); + QObject *target = stack.top(); + + void *a[] = { (void *)&assignObj, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeObject.propertyIndex, a); + } + break; + + + case QmlInstruction::AssignCustomType: + { + QObject *target = stack.top(); + QmlCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); + const QString &primitive = primitives.at(data.index); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(data.type); + QVariant v = (*converter)(primitive); + + QMetaProperty prop = + target->metaObject()->property(instr.assignCustomType.propertyIndex); + if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type)) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name()))); + + void *a[] = { (void *)v.data(), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.assignCustomType.propertyIndex, a); + } + break; + + case QmlInstruction::AssignSignalObject: + { + // XXX optimize + + QObject *assign = stack.pop(); + QObject *target = stack.top(); + int sigIdx = instr.assignSignalObject.signal; + const QByteArray &pr = datas.at(sigIdx); + + QmlMetaProperty prop(target, QString::fromUtf8(pr)); + if (prop.type() & QmlMetaProperty::SignalProperty) { + + QMetaMethod method = QmlMetaType::defaultMethod(assign); + if (method.signature() == 0) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className()))); + + if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature())) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature()))); + + QMetaObject::connect(target, prop.coreIndex(), assign, method.methodIndex()); + + } else { + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr))); + } + + + } + break; + + case QmlInstruction::StoreSignal: + { + QObject *target = stack.top(); + // XXX scope + QMetaMethod signal = + target->metaObject()->method(instr.storeSignal.signalIndex); + + QmlBoundSignal *bs = new QmlBoundSignal(target, signal, target); + QmlExpression *expr = + new QmlExpression(ctxt, primitives.at(instr.storeSignal.value), target); + expr->setSourceLocation(comp->name, instr.line); + bs->setExpression(expr); + } + break; + + case QmlInstruction::StoreScript: + { + QObject *target = stack.top(); + cp->addScript(scripts.at(instr.storeScript.value), target); + } + break; + + case QmlInstruction::StoreScriptString: + { + QObject *target = stack.top(); + QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); + QmlScriptString ss; + ss.setContext(ctxt); + ss.setScopeObject(scope); + ss.setScript(primitives.at(instr.storeScriptString.value)); + + void *a[] = { &ss, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeScriptString.propertyIndex, a); + } + break; + + case QmlInstruction::BeginObject: + { + QObject *target = stack.top(); + QmlParserStatus *status = reinterpret_cast<QmlParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue); + parserStatus.append(status); + status->d = &parserStatus.values[parserStatus.count - 1]; + + status->classBegin(); + } + break; + + case QmlInstruction::StoreBinding: + { + QObject *target = + stack.at(stack.count() - 1 - instr.assignBinding.owner); + QObject *context = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + QmlMetaProperty mp = + QmlMetaPropertyPrivate::restore(datas.at(instr.assignBinding.property), target, ctxt); + + int coreIndex = mp.coreIndex(); + + if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) + break; + + QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->name, instr.line, 0); + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->setTarget(mp); + bind->addToObject(target); + } + break; + + case QmlInstruction::StoreCompiledBinding: + { + QObject *target = + stack.at(stack.count() - 1 - instr.assignBinding.owner); + QObject *scope = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + int property = instr.assignBinding.property; + if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF)) + break; + + QmlAbstractBinding *binding = + cp->optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property); + bindValues.append(binding); + binding->m_mePtr = &bindValues.values[bindValues.count - 1]; + binding->addToObject(target); + } + break; + + case QmlInstruction::StoreValueSource: + { + QObject *obj = stack.pop(); + QmlPropertyValueSource *vs = reinterpret_cast<QmlPropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.assignValueSource.castValue); + QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner); + + QmlMetaProperty prop = + QmlMetaPropertyPrivate::restore(datas.at(instr.assignValueSource.property), target, ctxt); + obj->setParent(target); + vs->setTarget(prop); + } + break; + + case QmlInstruction::StoreValueInterceptor: + { + QObject *obj = stack.pop(); + QmlPropertyValueInterceptor *vi = reinterpret_cast<QmlPropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.assignValueInterceptor.castValue); + QObject *target = stack.at(stack.count() - 1 - instr.assignValueInterceptor.owner); + QmlMetaProperty prop = + QmlMetaPropertyPrivate::restore(datas.at(instr.assignValueInterceptor.property), target, ctxt); + obj->setParent(target); + vi->setTarget(prop); + QmlVMEMetaObject *mo = static_cast<QmlVMEMetaObject *>((QMetaObject*)target->metaObject()); + mo->registerInterceptor(prop.coreIndex(), prop.valueTypeCoreIndex(), vi); + } + break; + + case QmlInstruction::StoreObjectQmlList: + { + QObject *assign = stack.pop(); + const ListInstance &list = qliststack.top(); + + void *d = (void *)&assign; + list.qmlListInterface->append(d); + } + break; + + case QmlInstruction::StoreObjectQList: + { + QObject *assign = stack.pop(); + + const ListInstance &list = qliststack.top(); + list.qListInterface->append((void *)assign); + } + break; + + case QmlInstruction::AssignObjectList: + { + // This is only used for assigning interfaces + QObject *assign = stack.pop(); + const ListInstance &list = qliststack.top(); + + int type = list.type; + + void *ptr = 0; + + const char *iid = QmlMetaType::interfaceIId(type); + if (iid) + ptr = assign->qt_metacast(iid); + if (!ptr) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign object to list")); + + + if (list.qmlListInterface) { + void *d = (void *)&ptr; + list.qmlListInterface->append(d); + } else { + list.qListInterface->append(ptr); + } + } + break; + + case QmlInstruction::StoreVariantObject: + { + QObject *assign = stack.pop(); + QObject *target = stack.top(); + + QVariant v = QVariant::fromValue(assign); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeObject.propertyIndex, a); + } + break; + + case QmlInstruction::StoreInterface: + { + QObject *assign = stack.pop(); + QObject *target = stack.top(); + + int coreIdx = instr.storeObject.propertyIndex; + QMetaProperty prop = target->metaObject()->property(coreIdx); + int t = prop.userType(); + const char *iid = QmlMetaType::interfaceIId(t); + bool ok = false; + if (iid) { + void *ptr = assign->qt_metacast(iid); + if (ptr) { + void *a[] = { &ptr, 0, &status, &flags }; + QMetaObject::metacall(target, + QMetaObject::WriteProperty, + coreIdx, a); + ok = true; + } + } + + if (!ok) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign object to interface property")); + } + break; + + case QmlInstruction::FetchAttached: + { + QObject *target = stack.top(); + + QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.fetchAttached.id, target); + + if (!qmlObject) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Unable to create attached object")); + + stack.push(qmlObject); + } + break; + + case QmlInstruction::FetchQmlList: + { + QObject *target = stack.top(); + + void *a[1]; + // We know that QmlList<*> can be converted to + // QmlPrivate::ListInterface + QmlPrivate::ListInterface *list = 0; + a[0] = &list; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetchQmlList.property, a); + if (!list) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign to null list")); + + qliststack.push(ListInstance(list, instr.fetchQmlList.type)); + } + break; + + case QmlInstruction::FetchQList: + { + QObject *target = stack.top(); + + void *a[1]; + // We know that QList<T *>* can be converted to + // QList<void *>* + QList<void *> *list = 0; + a[0] = &list; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetchQmlList.property, a); + if (!list) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot assign to null list")); + + qliststack.push(ListInstance(list, instr.fetchQmlList.type)); + } + break; + + case QmlInstruction::FetchObject: + { + QObject *target = stack.top(); + + QObject *obj = 0; + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); + + if (!obj) + VME_EXCEPTION(QCoreApplication::translate("QmlVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.fetch.property).name()))); + + stack.push(obj); + } + break; + + case QmlInstruction::PopQList: + { + qliststack.pop(); + } + break; + + case QmlInstruction::Defer: + { + if (instr.defer.deferCount) { + QObject *target = stack.top(); + QmlDeclarativeData *data = + QmlDeclarativeData::get(target, true); + comp->addref(); + data->deferredComponent = comp; + data->deferredIdx = ii; + ii += instr.defer.deferCount; + } + } + break; + + case QmlInstruction::PopFetchedObject: + { + stack.pop(); + } + break; + + case QmlInstruction::FetchValueType: + { + QObject *target = stack.top(); + QmlValueType *valueHandler = + ep->valueTypes[instr.fetchValue.type]; + valueHandler->read(target, instr.fetchValue.property); + stack.push(valueHandler); + } + break; + + case QmlInstruction::PopValueType: + { + QmlValueType *valueHandler = + static_cast<QmlValueType *>(stack.pop()); + QObject *target = stack.top(); + valueHandler->write(target, instr.fetchValue.property, QmlMetaProperty::BypassInterceptor); + } + break; + + default: + qFatal("QmlCompiledData: Internal error - unknown instruction %d", instr.type); + break; + } + } + + if (isError()) { + if (!stack.isEmpty()) { + delete stack.at(0); + } + + QmlEnginePrivate::clear(bindValues); + QmlEnginePrivate::clear(parserStatus); + return 0; + } + + if (bindValues.count) + ep->bindValues << bindValues; + if (parserStatus.count) + ep->parserStatus << parserStatus; + + if (stack.isEmpty()) + return 0; + else + return stack.top(); + return 0; +} + +bool QmlVME::isError() const +{ + return !vmeErrors.isEmpty(); +} + +QList<QmlError> QmlVME::errors() const +{ + return vmeErrors; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h new file mode 100644 index 0000000..9c45dc1 --- /dev/null +++ b/src/declarative/qml/qmlvme_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVME_P_H +#define QMLVME_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmlerror.h" +#include "qbitfield_p.h" + +#include <QtCore/QString> +#include <QtCore/QStack> + +QT_BEGIN_NAMESPACE + +class QObject; +class QmlInstruction; +class QmlCompiledData; +class QmlCompiledData; +class QmlContext; + +template<typename T, int N = 128> +class QmlVMEStack { +public: + QmlVMEStack() : index(-1), maxSize(N), data(fixedData) {} + ~QmlVMEStack() { if (data != fixedData) qFree(fixedData); } + + bool isEmpty() const { return index == -1; } + const T &top() const { return data[index]; } + void push(const T &i) { ++index; if (index == maxSize) realloc(); data[index] = i; } + const T &pop() { --index; return data[index + 1]; } + int count() const { return index + 1; } + const T &at(int idx) { return data[idx]; } + +private: + void realloc() { + maxSize += N; + if (data != fixedData) { + data = (T*)qRealloc(data, maxSize * sizeof(T)); + } else { + data = (T*)qMalloc(maxSize * sizeof(T)); + } + } + int index; + int maxSize; + T *data; + T fixedData[N]; +}; + +class QmlVME +{ +public: + QmlVME(); + + QObject *run(QmlContext *, QmlCompiledData *, + int start = -1, int count = -1, + const QBitField & = QBitField()); + void runDeferred(QObject *); + + bool isError() const; + QList<QmlError> errors() const; + +private: + QObject *run(QmlVMEStack<QObject *> &, QmlContext *, QmlCompiledData *, + int start, int count, const QBitField &); + QList<QmlError> vmeErrors; +}; + +QT_END_NAMESPACE + +#endif // QMLVME_P_H diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp new file mode 100644 index 0000000..8faa922 --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvmemetaobject_p.h" + +#include "qml.h" +#include "qmlrefcount_p.h" +#include "qmlexpression.h" +#include "qmlexpression_p.h" +#include "qmlcontext_p.h" + +#include <QColor> +#include <QDate> +#include <QtCore/qlist.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, + const QMetaObject *other, + const QmlVMEMetaData *meta, + QmlCompiledData *cdata) +: object(obj), compiledData(cdata), ctxt(qmlContext(obj)), metaData(meta), methods(0), + parent(0) +{ + compiledData->addref(); + + *static_cast<QMetaObject *>(this) = *other; + this->d.superdata = obj->metaObject(); + + QObjectPrivate *op = QObjectPrivate::get(obj); + if (op->metaObject) + parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + op->metaObject = this; + + propOffset = QAbstractDynamicMetaObject::propertyOffset(); + methodOffset = QAbstractDynamicMetaObject::methodOffset(); + + data = new QVariant[metaData->propertyCount]; + aConnected.resize(metaData->aliasCount); + + int list_type = qMetaTypeId<QmlList<QObject*>* >(); + // ### Optimize + for (int ii = 0; ii < metaData->propertyCount; ++ii) { + int t = (metaData->propertyData() + ii)->propertyType; + if (t == list_type) { + listProperties.append(new List(this, ii)); + data[ii] = QVariant::fromValue((QmlList<QObject *>*)listProperties.last()); + } else if (t != -1) { + data[ii] = QVariant((QVariant::Type)t); + } + } +} + +QmlVMEMetaObject::~QmlVMEMetaObject() +{ + compiledData->release(); + delete parent; + qDeleteAll(listProperties); + delete [] data; + delete [] methods; +} + +int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) +{ + int id = _id; + if(c == QMetaObject::WriteProperty) { + int flags = *reinterpret_cast<int*>(a[3]); + if (!(flags & QmlMetaProperty::BypassInterceptor) + && !aInterceptors.isEmpty() + && aInterceptors.testBit(id)) { + QPair<int, QmlPropertyValueInterceptor*> pair = interceptors.value(id); + int valueIndex = pair.first; + QmlPropertyValueInterceptor *vi = pair.second; + int type = property(id).userType(); + + if (type != QVariant::Invalid) { + if (valueIndex != -1) { + QmlEnginePrivate *ep = ctxt?QmlEnginePrivate::get(ctxt->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[type]; + else valueType = QmlValueTypeFactory::valueType(type); + Q_ASSERT(valueType); + + valueType->setValue(QVariant(type, a[0])); + QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); + vi->write(valueProp.read(valueType)); + + if (!ep) delete valueType; + return -1; + } else { + vi->write(QVariant(type, a[0])); + return -1; + } + } + } + } + if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { + if (id >= propOffset) { + id -= propOffset; + + if (id < metaData->propertyCount) { + int t = (metaData->propertyData() + id)->propertyType; + bool needActivate = false; + + if (t == -1) { + + if (c == QMetaObject::ReadProperty) { + *reinterpret_cast<QVariant *>(a[0]) = data[id]; + } else if (c == QMetaObject::WriteProperty) { + needActivate = + (data[id] != *reinterpret_cast<QVariant *>(a[0])); + data[id] = *reinterpret_cast<QVariant *>(a[0]); + } + + } else { + + if (c == QMetaObject::ReadProperty) { + switch(t) { + case QVariant::Int: + *reinterpret_cast<int *>(a[0]) = data[id].toInt(); + break; + case QVariant::Bool: + *reinterpret_cast<bool *>(a[0]) = data[id].toBool(); + break; + case QVariant::Double: + *reinterpret_cast<double *>(a[0]) = data[id].toDouble(); + break; + case QVariant::String: + *reinterpret_cast<QString *>(a[0]) = data[id].toString(); + break; + case QVariant::Url: + *reinterpret_cast<QUrl *>(a[0]) = data[id].toUrl(); + break; + case QVariant::Color: + *reinterpret_cast<QColor *>(a[0]) = data[id].value<QColor>(); + break; + case QVariant::Date: + *reinterpret_cast<QDate *>(a[0]) = data[id].toDate(); + break; + case QMetaType::QObjectStar: + *reinterpret_cast<QObject **>(a[0]) = data[id].value<QObject*>(); + break; + default: + break; + } + if (t == qMetaTypeId<QmlList<QObject*>* >()) { + *reinterpret_cast<QmlList<QObject *> **>(a[0]) = data[id].value<QmlList<QObject*>*>(); + } + + } else if (c == QMetaObject::WriteProperty) { + + QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]); + needActivate = (data[id] != value); + data[id] = value; + } + + } + + if (c == QMetaObject::WriteProperty && needActivate) { + activate(object, methodOffset + id, 0); + } + + return -1; + } + + id -= metaData->propertyCount; + + if (id < metaData->aliasCount) { + + QmlVMEMetaData::AliasData *d = metaData->aliasData() + id; + + if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) + *reinterpret_cast<void **>(a[0]) = 0; + + if (!ctxt) return -1; + QmlContextPrivate *ctxtPriv = + (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + QObject *target = ctxtPriv->idValues[d->contextIdx].data(); + if (!target) + return -1; + + if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) { + int sigIdx = methodOffset + id + metaData->propertyCount; + QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx); + + if (d->propertyIdx != -1) { + QMetaProperty prop = + target->metaObject()->property(d->propertyIdx); + if (prop.hasNotifySignal()) + QMetaObject::connect(target, prop.notifySignalIndex(), + object, sigIdx); + } + aConnected.setBit(id); + } + + if (d->propertyIdx == -1) { + *reinterpret_cast<QObject **>(a[0]) = target; + return -1; + } else { + return QMetaObject::metacall(target, c, d->propertyIdx, a); + } + + } + return -1; + + } + + } else if(c == QMetaObject::InvokeMetaMethod) { + + if (id >= methodOffset) { + + id -= methodOffset; + int plainSignals = metaData->signalCount + metaData->propertyCount + + metaData->aliasCount; + if (id < plainSignals) { + QMetaObject::activate(object, _id, a); + return -1; + } + + id -= plainSignals; + + if (id < metaData->methodCount) { + if (!ctxt->engine()) + return -1; // We can't run the method + + QmlEnginePrivate *ep = QmlEnginePrivate::get(ctxt->engine()); + + QScriptValue function = method(id); + + QScriptValueList args; + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; + if (data->parameterCount) { + for (int ii = 0; ii < data->parameterCount; ++ii) { + args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); + } + } + QScriptValue rv = function.call(ep->objectClass->newQObject(object), args); + + if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv); + + return -1; + } + return -1; + } + } + + if (parent) + return parent->metaCall(c, _id, a); + else + return object->qt_metacall(c, _id, a); +} + +QScriptValue QmlVMEMetaObject::method(int index) +{ + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + + if (!methods[index].isValid()) { + QmlVMEMetaData::MethodData *data = metaData->methodData() + index; + + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); + + // XXX Use QScriptProgram + // XXX We should evaluate all methods in a single big script block to + // improve the call time between dynamic methods defined on the same + // object + methods[index] = QmlExpressionPrivate::evalInObjectScope(ctxt, object, code); + } + + return methods[index]; +} + +void QmlVMEMetaObject::listChanged(int id) +{ + activate(object, methodOffset + id, 0); +} + +void QmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor) +{ + if (aInterceptors.isEmpty()) + aInterceptors.resize(propertyCount() + metaData->propertyCount); + aInterceptors.setBit(index); + interceptors.insert(index, qMakePair(valueIndex, interceptor)); +} + +QScriptValue QmlVMEMetaObject::vmeMethod(int index) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast<QmlVMEMetaObject *>(parent)->vmeMethod(index); + } + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + return method(index - methodOffset - plainSignals); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h new file mode 100644 index 0000000..497d8f6 --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVMEMETAOBJECT_P_H +#define QMLVMEMETAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qml.h" + +#include <QtCore/QMetaObject> +#include <QtCore/QBitArray> +#include <QtCore/QPair> + +#include <private/qobject_p.h> + +#include "qmlguard_p.h" +#include "qmlcompiler_p.h" + +QT_BEGIN_NAMESPACE + +#define QML_ALIAS_FLAG_PTR 0x00000001 + +struct QmlVMEMetaData +{ + short propertyCount; + short aliasCount; + short signalCount; + short methodCount; + + struct AliasData { + int contextIdx; + int propertyIdx; + int flags; + }; + + struct PropertyData { + int propertyType; + }; + + struct MethodData { + int parameterCount; + int bodyOffset; + int bodyLength; + int scriptProgram; + }; + + PropertyData *propertyData() const { + return (PropertyData *)(((const char *)this) + sizeof(QmlVMEMetaData)); + } + + AliasData *aliasData() const { + return (AliasData *)(propertyData() + propertyCount); + } + + MethodData *methodData() const { + return (MethodData *)(aliasData() + aliasCount); + } +}; + +class QmlRefCount; +class QmlVMEMetaObject : public QAbstractDynamicMetaObject +{ +public: + QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *data, + QmlCompiledData *compiledData); + ~QmlVMEMetaObject(); + + void registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor); + QScriptValue vmeMethod(int index); +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QObject *object; + QmlCompiledData *compiledData; + QmlGuard<QmlContext> ctxt; + + const QmlVMEMetaData *metaData; + int propOffset; + int methodOffset; + + QVariant *data; + QBitArray aConnected; + QBitArray aInterceptors; + QHash<int, QPair<int, QmlPropertyValueInterceptor*> > interceptors; + + QScriptValue *methods; + QScriptValue method(int); + + QAbstractDynamicMetaObject *parent; + + void listChanged(int); + class List : public QmlConcreteList<QObject*> + { + public: + List(QmlVMEMetaObject *p, int propIdx) + : parent(p), parentProperty(propIdx) { } + + virtual void append(QObject *v) { + QmlConcreteList<QObject*>::append(v); + parent->listChanged(parentProperty); + } + virtual void insert(int i, QObject *v) { + QmlConcreteList<QObject*>::insert(i, v); + parent->listChanged(parentProperty); + } + virtual void clear() { + QmlConcreteList<QObject*>::clear(); + parent->listChanged(parentProperty); + } + virtual void removeAt(int i) { + QmlConcreteList<QObject*>::removeAt(i); + parent->listChanged(parentProperty); + } + private: + QmlVMEMetaObject *parent; + int parentProperty; + }; + QList<List *> listProperties; +}; + +QT_END_NAMESPACE + +#endif // QMLVMEMETAOBJECT_P_H diff --git a/src/declarative/qml/qmlwatcher.cpp b/src/declarative/qml/qmlwatcher.cpp new file mode 100644 index 0000000..507c11d --- /dev/null +++ b/src/declarative/qml/qmlwatcher.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlwatcher_p.h" + +#include "qmlexpression.h" +#include "qmlcontext.h" +#include "qml.h" + +#include <qmldebugservice_p.h> + +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + + +class QmlWatchProxy : public QObject +{ + Q_OBJECT +public: + QmlWatchProxy(int id, + QObject *object, + int debugId, + const QMetaProperty &prop, + QmlWatcher *parent = 0); + + QmlWatchProxy(int id, + QmlExpression *exp, + int debugId, + QmlWatcher *parent = 0); + +public slots: + void notifyValueChanged(); + +private: + friend class QmlWatcher; + int m_id; + QmlWatcher *m_watch; + QObject *m_object; + int m_debugId; + QMetaProperty m_property; + + QmlExpression *m_expr; +}; + +QmlWatchProxy::QmlWatchProxy(int id, + QmlExpression *exp, + int debugId, + QmlWatcher *parent) +: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp) +{ + QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged())); +} + +QmlWatchProxy::QmlWatchProxy(int id, + QObject *object, + int debugId, + const QMetaProperty &prop, + QmlWatcher *parent) +: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0) +{ + static int refreshIdx = -1; + if(refreshIdx == -1) + refreshIdx = QmlWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()"); + + if (prop.hasNotifySignal()) + QMetaObject::connect(m_object, prop.notifySignalIndex(), this, refreshIdx); +} + +void QmlWatchProxy::notifyValueChanged() +{ + QVariant v; + if (m_expr) + v = m_expr->value(); + else + v = m_property.read(m_object); + + emit m_watch->propertyChanged(m_id, m_debugId, m_property, v); +} + + +QmlWatcher::QmlWatcher(QObject *parent) + : QObject(parent) +{ +} + +bool QmlWatcher::addWatch(int id, quint32 debugId) +{ + QObject *object = QmlDebugService::objectForId(debugId); + if (object) { + int propCount = object->metaObject()->propertyCount(); + for (int ii=0; ii<propCount; ii++) + addPropertyWatch(id, object, debugId, object->metaObject()->property(ii)); + return true; + } + return false; +} + +bool QmlWatcher::addWatch(int id, quint32 debugId, const QByteArray &property) +{ + QObject *object = QmlDebugService::objectForId(debugId); + if (object) { + int index = object->metaObject()->indexOfProperty(property.constData()); + if (index >= 0) { + addPropertyWatch(id, object, debugId, object->metaObject()->property(index)); + return true; + } + } + return false; +} + +bool QmlWatcher::addWatch(int id, quint32 objectId, const QString &expr) +{ + QObject *object = QmlDebugService::objectForId(objectId); + QmlContext *context = qmlContext(object); + if (context) { + QmlExpression *exprObj = new QmlExpression(context, expr, object); + QmlWatchProxy *proxy = new QmlWatchProxy(id, exprObj, objectId, this); + exprObj->setParent(proxy); + m_proxies[id].append(proxy); + proxy->notifyValueChanged(); + return true; + } + return false; +} + +void QmlWatcher::removeWatch(int id) +{ + if (!m_proxies.contains(id)) + return; + + QList<QPointer<QmlWatchProxy> > proxies = m_proxies.take(id); + qDeleteAll(proxies); +} + +void QmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property) +{ + QmlWatchProxy *proxy = new QmlWatchProxy(id, object, debugId, property, this); + m_proxies[id].append(proxy); + + proxy->notifyValueChanged(); +} + +QT_END_NAMESPACE + +#include <qmlwatcher.moc> diff --git a/src/declarative/qml/qmlwatcher_p.h b/src/declarative/qml/qmlwatcher_p.h new file mode 100644 index 0000000..5050949 --- /dev/null +++ b/src/declarative/qml/qmlwatcher_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLWATCHER_P_H +#define QMLWATCHER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qhash.h> +#include <QtCore/qset.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QmlWatchProxy; +class QmlExpression; +class QmlContext; +class QMetaProperty; + +class QmlWatcher : public QObject +{ + Q_OBJECT +public: + QmlWatcher(QObject * = 0); + + bool addWatch(int id, quint32 objectId); + bool addWatch(int id, quint32 objectId, const QByteArray &property); + bool addWatch(int id, quint32 objectId, const QString &expr); + + void removeWatch(int id); + +Q_SIGNALS: + void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); + +private: + friend class QmlWatchProxy; + void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property); + + QHash<int, QList<QPointer<QmlWatchProxy> > > m_proxies; +}; + +QT_END_NAMESPACE + +#endif // QMLWATCHER_P_H diff --git a/src/declarative/qml/qmlworkerscript.cpp b/src/declarative/qml/qmlworkerscript.cpp new file mode 100644 index 0000000..5e39eaf --- /dev/null +++ b/src/declarative/qml/qmlworkerscript.cpp @@ -0,0 +1,1037 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlworkerscript_p.h" + +#include "qmlengine_p.h" + +#include <QtCore/qcoreevent.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> +#include <QtScript/qscriptengine.h> +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> +#include <QtScript/qscriptvalueiterator.h> +#include <QtCore/qfile.h> +#include <QtNetwork/qnetworkaccessmanager.h> +#include <QtDeclarative/qmlinfo.h> +#include "qmlnetworkaccessmanagerfactory.h" + +QT_BEGIN_NAMESPACE + +class WorkerDataEvent : public QEvent +{ +public: + enum Type { WorkerData = QEvent::User }; + + WorkerDataEvent(int workerId, const QVariant &data); + virtual ~WorkerDataEvent(); + + int workerId() const; + QVariant data() const; + +private: + int m_id; + QVariant m_data; +}; + +class WorkerLoadEvent : public QEvent +{ +public: + enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 }; + + WorkerLoadEvent(int workerId, const QUrl &url); + + int workerId() const; + QUrl url() const; + +private: + int m_id; + QUrl m_url; +}; + +class WorkerRemoveEvent : public QEvent +{ +public: + enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 }; + + WorkerRemoveEvent(int workerId); + + int workerId() const; + +private: + int m_id; +}; + +class QmlWorkerScriptEnginePrivate : public QObject +{ +public: + QmlWorkerScriptEnginePrivate(QmlEngine *eng); + + struct ScriptEngine : public QmlScriptEngine + { + ScriptEngine(QmlWorkerScriptEnginePrivate *parent) : QmlScriptEngine(0), p(parent), accessManager(0) {} + ~ScriptEngine() { delete accessManager; } + QmlWorkerScriptEnginePrivate *p; + QNetworkAccessManager *accessManager; + + virtual QNetworkAccessManager *networkAccessManager() { + if (!accessManager) { + if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) { + accessManager = p->qmlengine->networkAccessManagerFactory()->create(this); + } else { + accessManager = new QNetworkAccessManager(this); + } + } + return accessManager; + } + }; + ScriptEngine *workerEngine; + static QmlWorkerScriptEnginePrivate *get(QScriptEngine *e) { + return static_cast<ScriptEngine *>(e)->p; + } + + QmlEngine *qmlengine; + + QMutex m_lock; + QWaitCondition m_wait; + + struct WorkerScript { + WorkerScript(); + + int id; + bool initialized; + QmlWorkerScript *owner; + QScriptValue object; + + QScriptValue callback; + }; + + QHash<int, WorkerScript *> workers; + QScriptValue getWorker(int); + + int m_nextId; + + static QVariant scriptValueToVariant(const QScriptValue &); + static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *); + + static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine); + static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine); + +protected: + virtual bool event(QEvent *); + +private: + void processMessage(int, const QVariant &); + void processLoad(int, const QUrl &); +}; + +// Currently this will leak as no-one releases it in the worker thread +class QmlWorkerListModelAgent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int count READ count); + +public: + QmlWorkerListModelAgent(QmlWorkerListModel *); + ~QmlWorkerListModelAgent(); + + void addref(); + void release(); + + int count() const; + + Q_INVOKABLE void clear(); + Q_INVOKABLE void remove(int index); + Q_INVOKABLE void append(const QScriptValue &); + Q_INVOKABLE void insert(int index, const QScriptValue&); + Q_INVOKABLE QScriptValue get(int index) const; + Q_INVOKABLE void set(int index, const QScriptValue &); + Q_INVOKABLE void sync(); + + struct VariantRef + { + VariantRef() : a(0) {} + VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); } + VariantRef(QmlWorkerListModelAgent *_a) : a(_a) { if (a) a->addref(); } + ~VariantRef() { if (a) a->release(); } + + VariantRef &operator=(const VariantRef &o) { + if (o.a) o.a->addref(); + if (a) a->release(); a = o.a; + return *this; + } + + QmlWorkerListModelAgent *a; + }; +protected: + virtual bool event(QEvent *); + +private: + friend class QmlWorkerScriptEnginePrivate; + friend class QmlWorkerListModel; + QScriptEngine *m_engine; + + struct Change { + enum { Inserted, Removed, Moved, Changed } type; + int index; // Inserted/Removed/Moved/Changed + int count; // Inserted/Removed/Moved/Changed + int to; // Moved + }; + + struct Data { + QHash<int, QString> roles; + QHash<QString, int> strings; + QList<QHash<int, QVariant> > values; + QList<Change> changes; + + void clearChange(); + void insertChange(int index, int count); + void removeChange(int index, int count); + void changedChange(int index, int count); + }; + Data data; + + struct Sync : public QEvent { + Sync() : QEvent(QEvent::User) {} + Data data; + }; + + QAtomicInt m_ref; + QmlWorkerListModel *m_model; +}; +Q_DECLARE_METATYPE(QmlWorkerListModelAgent::VariantRef); + +QmlWorkerScriptEnginePrivate::QmlWorkerScriptEnginePrivate(QmlEngine *engine) +: workerEngine(0), qmlengine(engine), m_nextId(0) +{ +} + +QScriptValue QmlWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine) +{ + QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); + + if (ctxt->argumentCount() >= 1) + script->callback = ctxt->argument(0); + + return script->callback; +} + +QScriptValue QmlWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (!ctxt->argumentCount()) + return engine->undefinedValue(); + + QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); + + p->m_lock.lock(); + if (script->owner) + QCoreApplication::postEvent(script->owner, + new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0)))); + p->m_lock.unlock(); + + return engine->undefinedValue(); +} + +QScriptValue QmlWorkerScriptEnginePrivate::getWorker(int id) +{ + QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id); + + if (iter == workers.end()) + return workerEngine->nullValue(); + + WorkerScript *script = *iter; + if (!script->initialized) { + + script->initialized = true; + script->object = workerEngine->newObject(); + + QScriptValue api = workerEngine->newObject(); + api.setData(script->id); + + api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage)); + + script->object.setProperty(QLatin1String("WorkerScript"), api); + } + + return script->object; +} + +bool QmlWorkerScriptEnginePrivate::event(QEvent *event) +{ + if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { + WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); + processMessage(workerEvent->workerId(), workerEvent->data()); + return true; + } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) { + WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event); + processLoad(workerEvent->workerId(), workerEvent->url()); + return true; + } else { + return QObject::event(event); + } +} + +void QmlWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data) +{ + WorkerScript *script = workers.value(id); + if (!script) + return; + + if (script->callback.isFunction()) { + QScriptValue args = workerEngine->newArray(1); + args.setProperty(0, variantToScriptValue(data, workerEngine)); + + script->callback.call(script->object, args); + } +} + +void QmlWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) +{ + if (url.isRelative() || url.scheme() != QLatin1String("file")) + return; + + QString fileName = url.toLocalFile(); + + QFile f(fileName); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QString script = QString::fromUtf8(data); + + QScriptValue activation = getWorker(id); + + QScriptContext *ctxt = workerEngine->pushContext(); + ctxt->setActivationObject(activation); + + workerEngine->baseUrl = url; + workerEngine->evaluate(script); + + workerEngine->popContext(); + } +} + +QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) +{ + if (value.isBool()) { + return QVariant(value.toBool()); + } else if (value.isString()) { + return QVariant(value.toString()); + } else if (value.isNumber()) { + return QVariant((qreal)value.toNumber()); + } else if (value.isArray()) { + QVariantList list; + + quint32 length = (quint32)value.property(QLatin1String("length")).toNumber(); + + for (quint32 ii = 0; ii < length; ++ii) { + QVariant v = scriptValueToVariant(ii); + list << v; + } + + return QVariant(list); + } else if (value.isQObject()) { + QmlWorkerListModel *lm = qobject_cast<QmlWorkerListModel *>(value.toQObject()); + if (lm) { + QmlWorkerListModelAgent::VariantRef v(lm->agent()); + return qVariantFromValue(v); + } else { + // No other QObject's are allowed to be sent + return QVariant(); + } + } else if (value.isObject()) { + QVariantHash hash; + + QScriptValueIterator iter(value); + + while (iter.hasNext()) { + iter.next(); + hash.insert(iter.name(), scriptValueToVariant(iter.value())); + } + + return QVariant(hash); + } + + return QVariant(); + +} + +QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine) +{ + if (value.userType() == QVariant::Bool) { + return QScriptValue(value.toBool()); + } else if (value.userType() == QVariant::String) { + return QScriptValue(value.toString()); + } else if (value.userType() == QMetaType::QReal) { + return QScriptValue(value.toReal()); + } else if (value.userType() == qMetaTypeId<QmlWorkerListModelAgent::VariantRef>()) { + QmlWorkerListModelAgent::VariantRef vr = qvariant_cast<QmlWorkerListModelAgent::VariantRef>(value); + if (vr.a->m_engine == 0) + vr.a->m_engine = engine; + else if (vr.a->m_engine != engine) + return engine->nullValue(); + QScriptValue o = engine->newQObject(vr.a); + o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc + return o; + } else if (value.userType() == QMetaType::QVariantList) { + QVariantList list = qvariant_cast<QVariantList>(value); + QScriptValue rv = engine->newArray(list.count()); + + for (quint32 ii = 0; ii < quint32(list.count()); ++ii) + rv.setProperty(ii, variantToScriptValue(list.at(ii), engine)); + + return rv; + } else if (value.userType() == QMetaType::QVariantHash) { + + QVariantHash hash = qvariant_cast<QVariantHash>(value); + + QScriptValue rv = engine->newObject(); + + for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter) + rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine)); + + return rv; + } else { + return engine->nullValue(); + } +} + +WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data) +: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data) +{ +} + +WorkerDataEvent::~WorkerDataEvent() +{ +} + +int WorkerDataEvent::workerId() const +{ + return m_id; +} + +QVariant WorkerDataEvent::data() const +{ + return m_data; +} + +WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url) +: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url) +{ +} + +int WorkerLoadEvent::workerId() const +{ + return m_id; +} + +QUrl WorkerLoadEvent::url() const +{ + return m_url; +} + +WorkerRemoveEvent::WorkerRemoveEvent(int workerId) +: QEvent((QEvent::Type)WorkerRemove), m_id(workerId) +{ +} + +int WorkerRemoveEvent::workerId() const +{ + return m_id; +} + +QmlWorkerScriptEngine::QmlWorkerScriptEngine(QmlEngine *parent) +: QThread(parent), d(new QmlWorkerScriptEnginePrivate(parent)) +{ + d->m_lock.lock(); + start(QThread::LowPriority); + d->m_wait.wait(&d->m_lock); + d->moveToThread(this); + d->m_lock.unlock(); +} + +QmlWorkerScriptEngine::~QmlWorkerScriptEngine() +{ + qDeleteAll(d->workers); + delete d; d = 0; +} + +QmlWorkerScriptEnginePrivate::WorkerScript::WorkerScript() +: id(-1), initialized(false), owner(0) +{ +} + +int QmlWorkerScriptEngine::registerWorkerScript(QmlWorkerScript *owner) +{ + QmlWorkerScriptEnginePrivate::WorkerScript *script = new QmlWorkerScriptEnginePrivate::WorkerScript; + script->id = d->m_nextId++; + script->owner = owner; + + d->m_lock.lock(); + d->workers.insert(script->id, script); + d->m_lock.unlock(); + + return script->id; +} + +void QmlWorkerScriptEngine::removeWorkerScript(int id) +{ + QCoreApplication::postEvent(d, new WorkerRemoveEvent(id)); +} + +void QmlWorkerScriptEngine::executeUrl(int id, const QUrl &url) +{ + QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url)); +} + +void QmlWorkerScriptEngine::sendMessage(int id, const QVariant &data) +{ + QCoreApplication::postEvent(d, new WorkerDataEvent(id, data)); +} + +void QmlWorkerScriptEngine::run() +{ + d->m_lock.lock(); + + d->workerEngine = new QmlWorkerScriptEnginePrivate::ScriptEngine(d); + + d->m_wait.wakeAll(); + + d->m_lock.unlock(); + + exec(); + + delete d->workerEngine; d->workerEngine = 0; +} + +QmlWorkerScript::QmlWorkerScript(QObject *parent) +: QObject(parent), m_engine(0), m_scriptId(-1) +{ +} + +QmlWorkerScript::~QmlWorkerScript() +{ + if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId); +} + +QUrl QmlWorkerScript::source() const +{ + return m_source; +} + +void QmlWorkerScript::setSource(const QUrl &source) +{ + if (m_source == source) + return; + + m_source = source; + + if (m_engine) + m_engine->executeUrl(m_scriptId, m_source); + + emit sourceChanged(); +} + +void QmlWorkerScript::sendMessage(const QScriptValue &message) +{ + if (!m_engine) { + qWarning("QmlWorkerScript: Attempt to send message before WorkerScript establishment"); + return; + } + + m_engine->sendMessage(m_scriptId, QmlWorkerScriptEnginePrivate::scriptValueToVariant(message)); +} + +void QmlWorkerScript::componentComplete() +{ + if (!m_engine) { + QmlEngine *engine = qmlEngine(this); + if (!engine) { + qWarning("QmlWorkerScript: componentComplete() called without qmlEngine() set"); + return; + } + + m_engine = QmlEnginePrivate::get(engine)->getWorkerScriptEngine(); + m_scriptId = m_engine->registerWorkerScript(this); + + if (m_source.isValid()) + m_engine->executeUrl(m_scriptId, m_source); + } +} + +bool QmlWorkerScript::event(QEvent *event) +{ + if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { + QmlEngine *engine = qmlEngine(this); + if (engine) { + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); + QScriptValue value = + QmlWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine); + emit message(value); + } + return true; + } else { + return QObject::event(event); + } +} + +QML_DEFINE_TYPE(Qt, 4, 6, WorkerScript, QmlWorkerScript); + +void QmlWorkerListModelAgent::Data::clearChange() +{ + changes.clear(); +} + +void QmlWorkerListModelAgent::Data::insertChange(int index, int count) +{ + Change c = { Change::Inserted, index, count, 0 }; + changes << c; +} + +void QmlWorkerListModelAgent::Data::removeChange(int index, int count) +{ + Change c = { Change::Removed, index, count, 0 }; + changes << c; +} + +void QmlWorkerListModelAgent::Data::changedChange(int index, int count) +{ + Change c = { Change::Changed, index, count, 0 }; + changes << c; +} + +QmlWorkerListModelAgent::QmlWorkerListModelAgent(QmlWorkerListModel *m) +: m_engine(0), m_ref(1), m_model(m) +{ + data.roles = m_model->m_roles; + data.strings = m_model->m_strings; + data.values = m_model->m_values; +} + +QmlWorkerListModelAgent::~QmlWorkerListModelAgent() +{ +} + +void QmlWorkerListModelAgent::addref() +{ + m_ref.ref(); +} + +void QmlWorkerListModelAgent::release() +{ + bool del = !m_ref.deref(); + + if (del) + delete this; +} + +int QmlWorkerListModelAgent::count() const +{ + return data.values.count(); +} + +void QmlWorkerListModelAgent::clear() +{ + data.clearChange(); + data.removeChange(0, data.values.count()); + data.values.clear(); +} + +void QmlWorkerListModelAgent::remove(int index) +{ + if (data.values.count() <= index) + return; + + data.values.removeAt(index); + data.removeChange(index, 1); +} + +void QmlWorkerListModelAgent::append(const QScriptValue &value) +{ + QHash<int, QVariant> row; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = data.strings.find(name); + if (iter == data.strings.end()) { + int role = data.roles.count(); + data.roles.insert(role, name); + iter = data.strings.insert(name, role); + } + row.insert(*iter, v); + } + + data.values.append(row); + data.insertChange(data.values.count() - 1, 1); +} + +void QmlWorkerListModelAgent::insert(int index, const QScriptValue &value) +{ + if (index > data.values.count()) + return; + + QHash<int, QVariant> row; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = data.strings.find(name); + if (iter == data.strings.end()) { + int role = data.roles.count(); + data.roles.insert(role, name); + iter = data.strings.insert(name, role); + } + row.insert(*iter, v); + } + + data.values.insert(index, row); + data.insertChange(index, 1); +} + +void QmlWorkerListModelAgent::set(int index, const QScriptValue &value) +{ + if (data.values.count() <= index) + return; + + QHash<int, QVariant> row; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = data.strings.find(name); + if (iter == data.strings.end()) { + int role = data.roles.count(); + data.roles.insert(role, name); + iter = data.strings.insert(name, role); + } + row.insert(*iter, v); + } + + if (data.values.at(index) != row) { + data.values[index] = row; + data.changedChange(index, 1); + } +} + +QScriptValue QmlWorkerListModelAgent::get(int index) const +{ + if (data.values.count() <= index) + return m_engine->undefinedValue(); + + QScriptValue rv = m_engine->newObject(); + + QHash<int, QVariant> row = data.values.at(index); + for (QHash<int, QVariant>::ConstIterator iter = row.begin(); iter != row.end(); ++iter) + rv.setProperty(data.roles.value(iter.key()), qScriptValueFromValue(m_engine, iter.value())); + + return rv; +} + +void QmlWorkerListModelAgent::sync() +{ + Sync *s = new Sync; + s->data = data; + data.changes.clear(); + QCoreApplication::postEvent(this, s); +} + +bool QmlWorkerListModelAgent::event(QEvent *e) +{ + if (e->type() == QEvent::User) { + Sync *s = static_cast<Sync *>(e); + + const QList<Change> &changes = s->data.changes; + + if (m_model) { + bool cc = m_model->m_values.count() != s->data.values.count(); + + m_model->m_roles = s->data.roles; + m_model->m_strings = s->data.strings; + m_model->m_values = s->data.values; + + for (int ii = 0; ii < changes.count(); ++ii) { + const Change &change = changes.at(ii); + switch (change.type) { + case Change::Inserted: + emit m_model->itemsInserted(change.index, change.count); + break; + case Change::Removed: + emit m_model->itemsRemoved(change.index, change.count); + break; + case Change::Moved: + emit m_model->itemsMoved(change.index, change.to, change.count); + break; + case Change::Changed: + emit m_model->itemsMoved(change.index, change.to, change.count); + break; + } + } + + if (cc) + emit m_model->countChanged(); + } + } + + return QObject::event(e); +} + +QmlWorkerListModel::QmlWorkerListModel(QObject *parent) +: QListModelInterface(parent), m_agent(0) +{ +} + +QmlWorkerListModel::~QmlWorkerListModel() +{ + if (m_agent) { + m_agent->m_model = 0; + m_agent->release(); + } +} + +void QmlWorkerListModel::clear() +{ + if (m_agent) { + qmlInfo(this) << "List can only be modified from a WorkerScript"; + return; + } + + int count = m_values.count(); + m_values.clear(); + if (count) { + emit itemsRemoved(0, count); + emit countChanged(); + } +} + +void QmlWorkerListModel::remove(int index) +{ + if (m_agent) { + qmlInfo(this) << "List can only be modified from a WorkerScript"; + return; + } + + if (m_values.count() <= index) + return; + + m_values.removeAt(index); + emit itemsRemoved(index, 1); + emit countChanged(); +} + +void QmlWorkerListModel::append(const QScriptValue &value) +{ + if (m_agent) { + qmlInfo(this) << "List can only be modified from a WorkerScript"; + return; + } + + QHash<int, QVariant> data; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = m_strings.find(name); + if (iter == m_strings.end()) { + int role = m_roles.count(); + m_roles.insert(role, name); + iter = m_strings.insert(name, role); + } + data.insert(*iter, v); + } + + m_values.append(data); + + emit itemsInserted(m_values.count() - 1, 1); + emit countChanged(); +} + +void QmlWorkerListModel::insert(int index, const QScriptValue &value) +{ + if (m_agent) { + qmlInfo(this) << "List can only be modified from a WorkerScript"; + return; + } + + if (index > m_values.count()) + return; + + QHash<int, QVariant> data; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = m_strings.find(name); + if (iter == m_strings.end()) { + int role = m_roles.count(); + m_roles.insert(role, name); + iter = m_strings.insert(name, role); + } + data.insert(*iter, v); + } + + m_values.insert(index, data); + emit itemsInserted(index, 1); + emit countChanged(); +} + +QScriptValue QmlWorkerListModel::get(int index) const +{ + QmlEngine *engine = qmlEngine(this); + if (!engine || m_values.count() <= index) + return QScriptValue(); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QScriptValue rv = scriptEngine->newObject(); + + QHash<int, QVariant> data = m_values.at(index); + for (QHash<int, QVariant>::ConstIterator iter = data.begin(); iter != data.end(); ++iter) + rv.setProperty(m_roles.value(iter.key()), qScriptValueFromValue(scriptEngine, iter.value())); + + return rv; +} + +void QmlWorkerListModel::set(int index, const QScriptValue &value) +{ + if (m_agent) { + qmlInfo(this) << "List can only be modified from a WorkerScript"; + return; + } + + if (m_values.count() <= index) + return; + + QHash<int, QVariant> data; + + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + QString name = it.name(); + QVariant v = it.value().toVariant(); + + QHash<QString, int>::Iterator iter = m_strings.find(name); + if (iter == m_strings.end()) { + int role = m_roles.count(); + m_roles.insert(role, name); + iter = m_strings.insert(name, role); + } + data.insert(*iter, v); + } + + if (m_values.at(index) != data) { + m_values[index] = data; + emit itemsChanged(index, 1, m_roles.keys()); + } +} + +QmlWorkerListModelAgent *QmlWorkerListModel::agent() +{ + if (!m_agent) + m_agent = new QmlWorkerListModelAgent(this); + + return m_agent; +} + +QList<int> QmlWorkerListModel::roles() const +{ + return m_roles.keys(); +} + +QString QmlWorkerListModel::toString(int role) const +{ + return m_roles.value(role); +} + +int QmlWorkerListModel::count() const +{ + return m_values.count(); +} + +QHash<int,QVariant> QmlWorkerListModel::data(int index, const QList<int> &) const +{ + if (m_values.count() <= index) + return QHash<int, QVariant>(); + else + return m_values.at(index); +} + +QVariant QmlWorkerListModel::data(int index, int role) const +{ + if (m_values.count() <= index) + return QVariant(); + else + return m_values.at(index).value(role); +} + +QML_DEFINE_TYPE(Qt,4,6,WorkerListModel,QmlWorkerListModel) + +#include "qmlworkerscript.moc" + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlworkerscript_p.h b/src/declarative/qml/qmlworkerscript_p.h new file mode 100644 index 0000000..3a29498 --- /dev/null +++ b/src/declarative/qml/qmlworkerscript_p.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLWORKERSCRIPT_P_H +#define QMLWORKERSCRIPT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qml.h" +#include "qmlparserstatus.h" +#include <private/qlistmodelinterface_p.h> + +#include <QtCore/qthread.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +class QmlWorkerScript; +class QmlWorkerScriptEnginePrivate; +class QmlWorkerScriptEngine : public QThread +{ +Q_OBJECT +public: + QmlWorkerScriptEngine(QmlEngine *parent = 0); + virtual ~QmlWorkerScriptEngine(); + + int registerWorkerScript(QmlWorkerScript *); + void removeWorkerScript(int); + void executeUrl(int, const QUrl &); + void sendMessage(int, const QVariant &); + +protected: + virtual void run(); + +private: + QmlWorkerScriptEnginePrivate *d; +}; + +class QmlWorkerScript : public QObject, public QmlParserStatus +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + + Q_INTERFACES(QmlParserStatus) +public: + QmlWorkerScript(QObject *parent = 0); + virtual ~QmlWorkerScript(); + + QUrl source() const; + void setSource(const QUrl &); + +public slots: + void sendMessage(const QScriptValue &); + +signals: + void sourceChanged(); + void message(const QScriptValue &messageObject); + +protected: + virtual void componentComplete(); + virtual bool event(QEvent *); + +private: + QmlWorkerScriptEngine *m_engine; + int m_scriptId; + QUrl m_source; +}; + +class QmlWorkerListModelAgent; +class QmlWorkerListModel : public QListModelInterface +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) + +public: + QmlWorkerListModel(QObject * = 0); + virtual ~QmlWorkerListModel(); + + Q_INVOKABLE void clear(); + Q_INVOKABLE void remove(int index); + Q_INVOKABLE void append(const QScriptValue &); + Q_INVOKABLE void insert(int index, const QScriptValue&); + Q_INVOKABLE QScriptValue get(int index) const; + Q_INVOKABLE void set(int index, const QScriptValue &); + + QmlWorkerListModelAgent *agent(); + + virtual QList<int> roles() const; + virtual QString toString(int role) const; + virtual int count() const; + virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; + virtual QVariant data(int index, int role) const; + +Q_SIGNALS: + void countChanged(); + +private: + friend class QmlWorkerListModelAgent; + + QHash<int, QString> m_roles; + QHash<QString, int> m_strings; + QList<QHash<int, QVariant> > m_values; + + QmlWorkerListModelAgent *m_agent; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlWorkerScript); +QML_DECLARE_TYPE(QmlWorkerListModel); + +#endif // QMLWORKERSCRIPT_P_H diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp new file mode 100644 index 0000000..1883d1b --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -0,0 +1,1627 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlxmlhttprequest_p.h" + +#include "qmlengine.h" +#include "qmlengine_p.h" +#include "qmlrefcount_p.h" +#include "qmlengine_p.h" +#include "qmlexpression_p.h" + +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptengine.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtCore/qxmlstream.h> +#include <QtCore/qstack.h> +#include <QtCore/qdebug.h> + +// From DOM-Level-3-Core spec +// http://www.w3.org/TR/DOM-Level-3-Core/core.html +#define INDEX_SIZE_ERR 1 +#define DOMSTRING_SIZE_ERR 2 +#define HIERARCHY_REQUEST_ERR 3 +#define WRONG_DOCUMENT_ERR 4 +#define INVALID_CHARACTER_ERR 5 +#define NO_DATA_ALLOWED_ERR 6 +#define NO_MODIFICATION_ALLOWED_ERR 7 +#define NOT_FOUND_ERR 8 +#define NOT_SUPPORTED_ERR 9 +#define INUSE_ATTRIBUTE_ERR 10 +#define INVALID_STATE_ERR 11 +#define SYNTAX_ERR 12 +#define INVALID_MODIFICATION_ERR 13 +#define NAMESPACE_ERR 14 +#define INVALID_ACCESS_ERR 15 +#define VALIDATION_ERR 16 +#define TYPE_MISMATCH_ERR 17 + +#define THROW_DOM(error, desc) \ +{ \ + QScriptValue errorValue = context->throwError(QLatin1String(desc)); \ + errorValue.setProperty(QLatin1String("code"), error); \ + return errorValue; \ +} + +#define THROW_SYNTAX(desc) \ + return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc)); +#define THROW_REFERENCE(desc) \ + return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc)); + +#define D(arg) (arg)->release() +#define A(arg) (arg)->addref() + +namespace { + +class DocumentImpl; +class NodeImpl +{ +public: + NodeImpl() : type(Element), document(0), parent(0) {} + virtual ~NodeImpl() { + for (int ii = 0; ii < children.count(); ++ii) + delete children.at(ii); + for (int ii = 0; ii < attributes.count(); ++ii) + delete attributes.at(ii); + } + + // These numbers are copied from the Node IDL definition + enum Type { + Attr = 2, + CDATA = 4, + Comment = 8, + Document = 9, + DocumentFragment = 11, + DocumentType = 10, + Element = 1, + Entity = 6, + EntityReference = 5, + Notation = 12, + ProcessingInstruction = 7, + Text = 3 + }; + Type type; + + QString namespaceUri; + QString name; + + QString data; + + void addref(); + void release(); + + DocumentImpl *document; + NodeImpl *parent; + + QList<NodeImpl *> children; + QList<NodeImpl *> attributes; +}; + +class DocumentImpl : public QmlRefCount, public NodeImpl +{ +public: + DocumentImpl() : root(0) { type = Document; } + virtual ~DocumentImpl() { + if (root) delete root; + } + + QString version; + QString encoding; + bool isStandalone; + + NodeImpl *root; + + void addref() { QmlRefCount::addref(); } + void release() { QmlRefCount::release(); } +}; + +class NamedNodeMap +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *); + + NamedNodeMap(); + NamedNodeMap(const NamedNodeMap &); + ~NamedNodeMap(); + bool isNull(); + + NodeImpl *d; + QList<NodeImpl *> *list; +private: + NamedNodeMap &operator=(const NamedNodeMap &); +}; + +class NamedNodeMapClass : public QScriptClass +{ +public: + NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {} + + virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id); +}; + +class NodeList +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *); + + NodeList(); + NodeList(const NodeList &); + ~NodeList(); + bool isNull(); + + NodeImpl *d; +private: + NodeList &operator=(const NodeList &); +}; + +class NodeListClass : public QScriptClass +{ +public: + NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {} + virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id); +}; + +class Node +{ +public: + // JS API + static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine); + + static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine); + static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine); + static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine); + static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine); + static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine); + static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine); + + //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *); + + Node(); + Node(const Node &o); + ~Node(); + bool isNull() const; + + NodeImpl *d; + +private: + Node &operator=(const Node &); +}; + +class Element : public Node +{ +public: + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Attr : public Node +{ +public: + // JS API + static QScriptValue name(QScriptContext *context, QScriptEngine *engine); + static QScriptValue specified(QScriptContext *context, QScriptEngine *engine); + static QScriptValue value(QScriptContext *context, QScriptEngine *engine); + static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine); + static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue isId(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class CharacterData : public Node +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Text : public CharacterData +{ +public: + // JS API + static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine); + static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class CDATA : public Text +{ +public: + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Document : public Node +{ +public: + // JS API + static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine); + static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine); + static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine); + static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue load(QScriptEngine *engine, const QString &data); +}; + +}; // namespace + +Q_DECLARE_METATYPE(Node); +Q_DECLARE_METATYPE(NodeList); +Q_DECLARE_METATYPE(NamedNodeMap); + +void NodeImpl::addref() +{ + A(document); +} + +void NodeImpl::release() +{ + D(document); +} + +QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + switch (node.d->type) { + case NodeImpl::Document: + return QScriptValue(QLatin1String("#document")); + case NodeImpl::CDATA: + return QScriptValue(QLatin1String("#cdata-section")); + case NodeImpl::Text: + return QScriptValue(QLatin1String("#text")); + default: + return QScriptValue(node.d->name); + } +} + +QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->type == NodeImpl::Document || + node.d->type == NodeImpl::DocumentFragment || + node.d->type == NodeImpl::DocumentType || + node.d->type == NodeImpl::Element || + node.d->type == NodeImpl::Entity || + node.d->type == NodeImpl::EntityReference || + node.d->type == NodeImpl::Notation) + return engine->nullValue(); + + return QScriptValue(node.d->data); +} + +QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + return QScriptValue(node.d->type); +} + +QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->parent) return Node::create(engine, node.d->parent); + else return engine->nullValue(); +} + +QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return NodeList::create(engine, node.d); +} + +QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->children.isEmpty()) return engine->nullValue(); + else return Node::create(engine, node.d->children.first()); +} + +QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->children.isEmpty()) return engine->nullValue(); + else return Node::create(engine, node.d->children.last()); +} + +QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (!node.d->parent) return engine->nullValue(); + + for (int ii = 0; ii < node.d->parent->children.count(); ++ii) { + if (node.d->parent->children.at(ii) == node.d) { + if (ii == 0) return engine->nullValue(); + else return Node::create(engine, node.d->parent->children.at(ii - 1)); + } + } + + return engine->nullValue(); +} + +QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (!node.d->parent) return engine->nullValue(); + + for (int ii = 0; ii < node.d->parent->children.count(); ++ii) { + if (node.d->parent->children.at(ii) == node.d) { + if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue(); + else return Node::create(engine, node.d->parent->children.at(ii + 1)); + } + } + + return engine->nullValue(); +} + +QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->type != NodeImpl::Element) + return engine->nullValue(); + else + return NamedNodeMap::create(engine, node.d, &node.d->attributes); +} + +QScriptValue Node::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data) +{ + QScriptValue instance = engine->newObject(); + + switch (data->type) { + case NodeImpl::Attr: + instance.setPrototype(Attr::prototype(engine)); + break; + case NodeImpl::Comment: + case NodeImpl::Document: + case NodeImpl::DocumentFragment: + case NodeImpl::DocumentType: + case NodeImpl::Entity: + case NodeImpl::EntityReference: + case NodeImpl::Notation: + case NodeImpl::ProcessingInstruction: + return QScriptValue(); + case NodeImpl::CDATA: + instance.setPrototype(CDATA::prototype(engine)); + break; + case NodeImpl::Text: + instance.setPrototype(Text::prototype(engine)); + break; + case NodeImpl::Element: + instance.setPrototype(Element::prototype(engine)); + break; + } + + Node node; + node.d = data; + if (data) A(data); + + return engine->newVariant(instance, qVariantFromValue(node)); +} + +QScriptValue Element::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Attr::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->name); +} + +QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->data); +} + +QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return Node::create(engine, node.d->parent); +} + +QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->data.length()); +} + +QScriptValue CharacterData::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return node.d->data.trimmed().isEmpty(); +} + +QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return node.d->data; +} + +QScriptValue Text::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(CharacterData::prototype(engine)); + + proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue CDATA::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Text::prototype(engine)); + return proto; +} + +QScriptValue Document::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Document::load(QScriptEngine *engine, const QString &data) +{ + Q_ASSERT(engine); + + DocumentImpl *document = 0; + QStack<NodeImpl *> nodeStack; + + QXmlStreamReader reader(data); + + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::NoToken: + break; + case QXmlStreamReader::Invalid: + break; + case QXmlStreamReader::StartDocument: + Q_ASSERT(!document); + document = new DocumentImpl; + document->document = document; + document->version = reader.documentVersion().toString(); + document->encoding = reader.documentEncoding().toString(); + document->isStandalone = reader.isStandaloneDocument(); + break; + case QXmlStreamReader::EndDocument: + break; + case QXmlStreamReader::StartElement: + { + Q_ASSERT(document); + NodeImpl *node = new NodeImpl; + node->document = document; + node->namespaceUri = reader.namespaceUri().toString(); + node->name = reader.name().toString(); + if (nodeStack.isEmpty()) { + document->root = node; + } else { + node->parent = nodeStack.top(); + node->parent->children.append(node); + } + nodeStack.append(node); + + foreach (const QXmlStreamAttribute &a, reader.attributes()) { + NodeImpl *attr = new NodeImpl; + attr->document = document; + attr->type = NodeImpl::Attr; + attr->namespaceUri = a.namespaceUri().toString(); + attr->name = a.name().toString(); + attr->data = a.value().toString(); + attr->parent = node; + node->attributes.append(attr); + } + } + break; + case QXmlStreamReader::EndElement: + nodeStack.pop(); + break; + case QXmlStreamReader::Characters: + { + NodeImpl *node = new NodeImpl; + node->document = document; + node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text; + node->parent = nodeStack.top(); + node->parent->children.append(node); + node->data = reader.text().toString(); + } + break; + case QXmlStreamReader::Comment: + break; + case QXmlStreamReader::DTD: + break; + case QXmlStreamReader::EntityReference: + break; + case QXmlStreamReader::ProcessingInstruction: + break; + } + } + + if (!document || reader.hasError()) { + if (document) D(document); + return engine->nullValue(); + } + + QScriptValue instance = engine->newObject(); + instance.setPrototype(Document::prototype(engine)); + Node documentNode; + documentNode.d = document; + return engine->newVariant(instance, qVariantFromValue(documentNode)); +} + +Node::Node() +: d(0) +{ +} + +Node::Node(const Node &o) +: d(o.d) +{ + if (d) A(d); +} + +Node::~Node() +{ + if (d) D(d); +} + +bool Node::isNull() const +{ + return d == 0; +} + +QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine) +{ + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data()); + if (map.isNull()) return engine->undefinedValue(); + + return QScriptValue(map.list->count()); +} + +QScriptValue NamedNodeMap::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list) +{ + QScriptValue instance = engine->newObject(); + instance.setPrototype(NamedNodeMap::prototype(engine)); + + NamedNodeMap map; + map.d = data; + map.list = list; + if (data) A(data); + + instance.setData(engine->newVariant(qVariantFromValue(map))); + + if (!QmlScriptEngine::get(engine)->namedNodeMapClass) + QmlScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine); + + instance.setScriptClass(QmlScriptEngine::get(engine)->namedNodeMapClass); + + return instance; +} + +NamedNodeMap::NamedNodeMap() +: d(0), list(0) +{ +} + +NamedNodeMap::NamedNodeMap(const NamedNodeMap &o) +: d(o.d), list(o.list) +{ + if (d) A(d); +} + +NamedNodeMap::~NamedNodeMap() +{ + if (d) D(d); +} + +bool NamedNodeMap::isNull() +{ + return d == 0; +} + +QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine) +{ + NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data()); + if (list.isNull()) return engine->undefinedValue(); + + return QScriptValue(list.d->children.count()); +} + +QScriptValue NodeList::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data) +{ + QScriptValue instance = engine->newObject(); + instance.setPrototype(NodeList::prototype(engine)); + + NodeList list; + list.d = data; + if (data) A(data); + + instance.setData(engine->newVariant(qVariantFromValue(list))); + + if (!QmlScriptEngine::get(engine)->nodeListClass) + QmlScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine); + + instance.setScriptClass(QmlScriptEngine::get(engine)->nodeListClass); + + return instance; +} + +NodeList::NodeList() +: d(0) +{ +} + +NodeList::NodeList(const NodeList &o) +: d(o.d) +{ + if (d) A(d); +} + +NodeList::~NodeList() +{ + if (d) D(d); +} + +bool NodeList::isNull() +{ + return d == 0; +} + +NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) +{ + if (!(flags & HandlesReadAccess)) + return 0; + + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data()); + Q_ASSERT(!map.isNull()); + + bool ok = false; + QString nameString = name.toString(); + uint index = nameString.toUInt(&ok); + if (ok) { + if ((uint)map.list->count() <= index) + return 0; + + *id = index; + return HandlesReadAccess; + } else { + for (int ii = 0; ii < map.list->count(); ++ii) { + if (map.list->at(ii) && map.list->at(ii)->name == nameString) { + *id = ii; + return HandlesReadAccess; + } + } + } + + return 0; +} + +QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id) +{ + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data()); + return Node::create(engine(), map.list->at(id)); +} + +NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) +{ + if (!(flags & HandlesReadAccess)) + return 0; + + bool ok = false; + uint index = name.toString().toUInt(&ok); + if (!ok) + return 0; + + NodeList list = qscriptvalue_cast<NodeList>(object.data()); + if (list.isNull() || (uint)list.d->children.count() <= index) + return 0; // ### I think we're meant to raise an exception + + *id = index; + return HandlesReadAccess; +} + +QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id) +{ + NodeList list = qscriptvalue_cast<NodeList>(object.data()); + return Node::create(engine(), list.d->children.at(id)); +} + +QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root); +} + +QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone); +} + +QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->version); +} + +QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding); +} + +class QmlXMLHttpRequest : public QObject +{ +Q_OBJECT +public: + enum State { Unsent = 0, + Opened = 1, HeadersReceived = 2, + Loading = 3, Done = 4 }; + + QmlXMLHttpRequest(QNetworkAccessManager *manager); + virtual ~QmlXMLHttpRequest(); + + bool sendFlag() const; + bool errorFlag() const; + quint32 readyState() const; + int replyStatus() const; + QString replyStatusText() const; + + QScriptValue open(QScriptValue *me, const QString &, const QUrl &); + + void addHeader(const QString &, const QString &); + QString header(const QString &name); + QString headers(); + QScriptValue send(QScriptValue *me, const QByteArray &); + QScriptValue abort(QScriptValue *me); + + QString responseBody() const; +private slots: + void downloadProgress(qint64); + void error(QNetworkReply::NetworkError); + void finished(); + +private: + void requestFromUrl(const QUrl &url); + + State m_state; + bool m_errorFlag; + bool m_sendFlag; + QString m_method; + QUrl m_url; + QByteArray m_responseEntityBody; + QByteArray m_data; + int m_redirectCount; + + typedef QPair<QByteArray, QByteArray> HeaderPair; + typedef QList<HeaderPair> HeadersList; + HeadersList m_headersList; + void fillHeadersList(); + + QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback) + + QScriptValue dispatchCallback(QScriptValue *me); + void printError(const QScriptValue&); + + int m_status; + QString m_statusText; + QNetworkRequest m_request; + QNetworkReply *m_network; + void destroyNetwork(); + + QNetworkAccessManager *m_nam; + QNetworkAccessManager *networkAccessManager() { return m_nam; } +}; + +QmlXMLHttpRequest::QmlXMLHttpRequest(QNetworkAccessManager *manager) +: m_state(Unsent), m_errorFlag(false), m_sendFlag(false), + m_redirectCount(0), m_network(0), m_nam(manager) +{ +} + +QmlXMLHttpRequest::~QmlXMLHttpRequest() +{ + destroyNetwork(); +} + +bool QmlXMLHttpRequest::sendFlag() const +{ + return m_sendFlag; +} + +bool QmlXMLHttpRequest::errorFlag() const +{ + return m_errorFlag; +} + +quint32 QmlXMLHttpRequest::readyState() const +{ + return m_state; +} + +int QmlXMLHttpRequest::replyStatus() const +{ + return m_status; +} + +QString QmlXMLHttpRequest::replyStatusText() const +{ + return m_statusText; +} + +QScriptValue QmlXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url) +{ + destroyNetwork(); + m_sendFlag = false; + m_errorFlag = false; + m_responseEntityBody = QByteArray(); + m_method = method; + m_url = url; + m_state = Opened; + return dispatchCallback(me); +} + +void QmlXMLHttpRequest::addHeader(const QString &name, const QString &value) +{ + QByteArray utfname = name.toUtf8(); + + if (m_request.hasRawHeader(utfname)) { + m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8()); + } else { + m_request.setRawHeader(utfname, value.toUtf8()); + } +} + +QString QmlXMLHttpRequest::header(const QString &name) +{ + QByteArray utfname = name.toLower().toUtf8(); + + foreach (const HeaderPair &header, m_headersList) { + if (header.first == utfname) + return QString::fromUtf8(header.second); + } + return QString(); +} + +QString QmlXMLHttpRequest::headers() +{ + QString ret; + + foreach (const HeaderPair &header, m_headersList) { + if (ret.length()) + ret.append(QString::fromUtf8("\r\n")); + ret.append(QString::fromUtf8(header.first)); + ret.append(QString::fromUtf8(": ")); + ret.append(QString::fromUtf8(header.second)); + } + return ret; +} + +void QmlXMLHttpRequest::fillHeadersList() +{ + QList<QByteArray> headerList = m_network->rawHeaderList(); + + m_headersList.clear(); + foreach (const QByteArray &header, headerList) { + HeaderPair pair (header.toLower(), m_network->rawHeader(header)); + if (pair.first == "set-cookie" || + pair.first == "set-cookie2") + continue; + + m_headersList << pair; + } +} + +void QmlXMLHttpRequest::requestFromUrl(const QUrl &url) +{ + QNetworkRequest request = m_request; + request.setUrl(url); + if(m_method == QLatin1String("POST") || + m_method == QLatin1String("PUT")) { + QVariant var = request.header(QNetworkRequest::ContentTypeHeader); + if (var.isValid()) { + QString str = var.toString(); + int charsetIdx = str.indexOf(QLatin1String("charset=")); + if (charsetIdx == -1) { + // No charset - append + if (!str.isEmpty()) str.append(QLatin1Char(';')); + str.append(QLatin1String("charset=UTF-8")); + } else { + charsetIdx += 8; + int n = 0; + int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx); + if (semiColon == -1) { + n = str.length() - charsetIdx; + } else { + n = semiColon - charsetIdx; + } + + str.replace(charsetIdx, n, QLatin1String("UTF-8")); + } + request.setHeader(QNetworkRequest::ContentTypeHeader, str); + } else { + request.setHeader(QNetworkRequest::ContentTypeHeader, + QLatin1String("text/plain;charset=UTF-8")); + } + } + + if (m_method == QLatin1String("GET")) + m_network = networkAccessManager()->get(request); + else if (m_method == QLatin1String("HEAD")) + m_network = networkAccessManager()->head(request); + else if(m_method == QLatin1String("POST")) + m_network = networkAccessManager()->post(request, m_data); + else if(m_method == QLatin1String("PUT")) + m_network = networkAccessManager()->put(request, m_data); + + QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(downloadProgress(qint64))); + QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(error(QNetworkReply::NetworkError))); + QObject::connect(m_network, SIGNAL(finished()), + this, SLOT(finished())); +} + +QScriptValue QmlXMLHttpRequest::send(QScriptValue *me, const QByteArray &data) +{ + m_errorFlag = false; + m_sendFlag = true; + m_redirectCount = 0; + m_data = data; + m_me = *me; + + requestFromUrl(m_url); + + return QScriptValue(); +} + +QScriptValue QmlXMLHttpRequest::abort(QScriptValue *me) +{ + destroyNetwork(); + m_responseEntityBody = QByteArray(); + m_errorFlag = true; + m_request = QNetworkRequest(); + + if (!(m_state == Unsent || + (m_state == Opened && !m_sendFlag) || + m_state == Done)) { + + m_state = Done; + m_sendFlag = false; + QScriptValue cbv = dispatchCallback(me); + if (cbv.isError()) return cbv; + } + + m_state = Unsent; + return QScriptValue(); +} + +void QmlXMLHttpRequest::downloadProgress(qint64 bytes) +{ + Q_UNUSED(bytes) + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + // ### We assume if this is called the headers are now available + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + fillHeadersList (); + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + + bool wasEmpty = m_responseEntityBody.isEmpty(); + m_responseEntityBody.append(m_network->readAll()); + if (wasEmpty && !m_responseEntityBody.isEmpty()) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } +} + +void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error) +{ + Q_UNUSED(error) + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + m_responseEntityBody = QByteArray(); + + m_request = QNetworkRequest(); + m_data.clear(); + destroyNetwork(); + + if (error == QNetworkReply::ContentAccessDenied || + error == QNetworkReply::ContentOperationNotPermittedError || + error == QNetworkReply::ContentNotFoundError || + error == QNetworkReply::AuthenticationRequiredError || + error == QNetworkReply::ContentReSendError) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } else { + m_errorFlag = true; + } + + m_state = Done; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); +} + +#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15 +void QmlXMLHttpRequest::finished() +{ + m_redirectCount++; + if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = redirect.toUrl(); + destroyNetwork(); + requestFromUrl(url); + return; + } + } + + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + fillHeadersList (); + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + m_responseEntityBody.append(m_network->readAll()); + m_data.clear(); + destroyNetwork(); + if (m_state < Loading) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + m_state = Done; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + + m_me = QScriptValue(); +} + + +QString QmlXMLHttpRequest::responseBody() const +{ + return QString::fromUtf8(m_responseEntityBody); +} + +QScriptValue QmlXMLHttpRequest::dispatchCallback(QScriptValue *me) +{ + QScriptValue v = me->property(QLatin1String("callback")); + return v.call(); +} + +void QmlXMLHttpRequest::printError(const QScriptValue& sv) +{ + QmlError error; + QmlExpressionPrivate::exceptionToError(sv.engine(), error); + qWarning().nospace() << qPrintable(error.toString()); +} + +void QmlXMLHttpRequest::destroyNetwork() +{ + if (m_network) { + m_network->disconnect(); + m_network->deleteLater(); + m_network = 0; + } +} + +// XMLHttpRequest methods +static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine) +{ + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() < 2 || context->argumentCount() > 5) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + // Argument 0 - Method + QString method = context->argument(0).toString().toUpper(); + if (method != QLatin1String("GET") && + method != QLatin1String("PUT") && + method != QLatin1String("HEAD") && + method != QLatin1String("POST")) + THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type"); + + + // Argument 1 - URL + QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8()); + + if (url.isRelative()) { + url = QmlScriptEngine::get(engine)->resolvedUrl(context,url); + } + + // Argument 2 - async (optional) + if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) + THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported"); + + + // Argument 3/4 - user/pass (optional) + QString username, password; + if (context->argumentCount() > 3) + username = context->argument(3).toString(); + if (context->argumentCount() > 4) + password = context->argument(4).toString(); + + + // Clear the fragment (if any) + url.setFragment(QString()); + // Set username/password + if (!username.isNull()) url.setUserName(username); + if (!password.isNull()) url.setPassword(password); + + return request->open(&dataObject, method, url); +} + +static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 2) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + + if (request->readyState() != QmlXMLHttpRequest::Opened || + request->sendFlag()) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + + QString name = context->argument(0).toString(); + QString value = context->argument(1).toString(); + + // ### Check that name and value are well formed + + QString nameUpper = name.toUpper(); + if (nameUpper == QLatin1String("ACCEPT-CHARSET") || + nameUpper == QLatin1String("ACCEPT-ENCODING") || + nameUpper == QLatin1String("CONNECTION") || + nameUpper == QLatin1String("CONTENT-LENGTH") || + nameUpper == QLatin1String("COOKIE") || + nameUpper == QLatin1String("COOKIE2") || + nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") || + nameUpper == QLatin1String("DATE") || + nameUpper == QLatin1String("EXPECT") || + nameUpper == QLatin1String("HOST") || + nameUpper == QLatin1String("KEEP-ALIVE") || + nameUpper == QLatin1String("REFERER") || + nameUpper == QLatin1String("TE") || + nameUpper == QLatin1String("TRAILER") || + nameUpper == QLatin1String("TRANSFER-ENCODING") || + nameUpper == QLatin1String("UPGRADE") || + nameUpper == QLatin1String("USER-AGENT") || + nameUpper == QLatin1String("VIA") || + nameUpper.startsWith(QLatin1String("PROXY-")) || + nameUpper.startsWith(QLatin1String("SEC-"))) + return engine->undefinedValue(); + + request->addHeader(nameUpper, value); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *) +{ + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() != QmlXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->sendFlag()) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + QByteArray data; + if (context->argumentCount() > 0) + data = context->argument(0).toString().toUtf8(); + + return request->send(&dataObject, data); +} + +static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *) +{ + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + return request->abort(&dataObject); +} + +static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 1) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done && + request->readyState() != QmlXMLHttpRequest::HeadersReceived) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + QString headerName = context->argument(0).toString(); + + return QScriptValue(request->header(headerName)); +} + +static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 0) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done && + request->readyState() != QmlXMLHttpRequest::HeadersReceived) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + return QScriptValue(request->headers()); +} + +// XMLHttpRequest properties +static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + return QScriptValue(request->readyState()); +} + +static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatus()); +} + +static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatusText()); +} + +static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done) + return QScriptValue(QString()); + else + return QScriptValue(request->responseBody()); +} + +static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done) + return engine->nullValue(); + else + return Document::load(engine, request->responseBody()); +} + +static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine); + QScriptValue dataObject = context->thisObject().data(); + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount()) { + QScriptValue v = context->argument(0); + dataObject.setProperty(QLatin1String("callback"), v); + return v; + } else { + return dataObject.property(QLatin1String("callback")); + } +} + +// Constructor +static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine) +{ + if (context->isCalledAsConstructor()) { + context->thisObject().setData(engine->newQObject(new QmlXMLHttpRequest(QmlScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership)); + } + return engine->undefinedValue(); +} + +void qt_add_qmlxmlhttprequest(QScriptEngine *engine) +{ + QScriptValue prototype = engine->newObject(); + + // Methods + prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2)); + prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2)); + prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send)); + prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort)); + prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1)); + prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders)); + + // Read-only properties + prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + + // State values + prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + // Constructor + QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype); + constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor); + + // DOM Exception + QScriptValue domExceptionPrototype = engine->newObject(); + domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype); +} + +#include <qmlxmlhttprequest.moc> diff --git a/src/declarative/qml/qmlxmlhttprequest_p.h b/src/declarative/qml/qmlxmlhttprequest_p.h new file mode 100644 index 0000000..dfed5d2 --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLXMLHTTPREQUEST_P_H +#define QMLXMLHTTPREQUEST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +class QScriptEngine; +void qt_add_qmlxmlhttprequest(QScriptEngine *engine); + +#endif // QMLXMLHTTPREQUEST_P_H + diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h new file mode 100644 index 0000000..42d6017 --- /dev/null +++ b/src/declarative/qml/qpodvector_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPODVECTOR_P_H +#define QPODVECTOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +template<class T, int Increment=1024> +class QPODVector +{ +public: + QPODVector() + : m_count(0), m_capacity(0), m_data(0) {} + ~QPODVector() { if (m_data) ::free(m_data); } + + const T &at(int idx) const { + return m_data[idx]; + } + + T &operator[](int idx) { + return m_data[idx]; + } + + void clear() { + m_count = 0; + } + + void prepend(const T &v) { + insert(0, v); + } + + void append(const T &v) { + insert(m_count, v); + } + + void insert(int idx, const T &v) { + if (m_count == m_capacity) { + m_capacity += Increment; + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T)); + m_count++; + m_data[idx] = v; + } + + void reserve(int count) { + if (count >= m_capacity) { + m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1); + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + } + + void insertBlank(int idx, int count) { + int newSize = m_count + count; + reserve(newSize); + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + count, m_data + idx, + moveCount * sizeof(T)); + m_count = newSize; + } + + void remove(int idx, int count = 1) { + int moveCount = m_count - (idx + count); + if (moveCount) + ::memmove(m_data + idx, m_data + idx + count, + moveCount * sizeof(T)); + m_count -= count; + } + + void removeOne(const T &v) { + int idx = 0; + while (idx < m_count) { + if (m_data[idx] == v) { + remove(idx); + return; + } + ++idx; + } + } + + int find(const T &v) { + for (int idx = 0; idx < m_count; ++idx) + if (m_data[idx] == v) + return idx; + return -1; + } + + bool contains(const T &v) { + return find(v) != -1; + } + + int count() const { + return m_count; + } + + void copyAndClear(QPODVector<T,Increment> &other) { + if (other.m_data) ::free(other.m_data); + other.m_count = m_count; + other.m_capacity = m_capacity; + other.m_data = m_data; + m_count = 0; + m_capacity = 0; + m_data = 0; + } + + QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; } +private: + QPODVector(const QPODVector &); + QPODVector &operator=(const QPODVector &); + int m_count; + int m_capacity; + T *m_data; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/rewriter/rewriter.cpp b/src/declarative/qml/rewriter/rewriter.cpp new file mode 100644 index 0000000..237d33f --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rewriter_p.h" + +#include <qmljsast_p.h> + +QT_QML_BEGIN_NAMESPACE + +using namespace QmlJS; + +void Rewriter::replace(const AST::SourceLocation &loc, const QString &text) +{ replace(loc.offset, loc.length, text); } + +void Rewriter::remove(const AST::SourceLocation &loc) +{ return replace(loc.offset, loc.length, QString()); } + +void Rewriter::remove(const AST::SourceLocation &firstLoc, const AST::SourceLocation &lastLoc) +{ return replace(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, QString()); } + +void Rewriter::insertTextBefore(const AST::SourceLocation &loc, const QString &text) +{ replace(loc.offset, 0, text); } + +void Rewriter::insertTextAfter(const AST::SourceLocation &loc, const QString &text) +{ replace(loc.offset + loc.length, 0, text); } + +void Rewriter::replace(int offset, int length, const QString &text) +{ textWriter.replace(offset, length, text); } + +void Rewriter::insertText(int offset, const QString &text) +{ replace(offset, 0, text); } + +void Rewriter::removeText(int offset, int length) +{ replace(offset, length, QString()); } + +QString Rewriter::textAt(const AST::SourceLocation &loc) const +{ return _code.mid(loc.offset, loc.length); } + +QString Rewriter::textAt(const AST::SourceLocation &firstLoc, const AST::SourceLocation &lastLoc) const +{ return _code.mid(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset); } + +void Rewriter::accept(QmlJS::AST::Node *node) +{ QmlJS::AST::Node::acceptChild(node, this); } + +void Rewriter::moveTextBefore(const AST::SourceLocation &firstLoc, + const AST::SourceLocation &lastLoc, + const AST::SourceLocation &loc) +{ + move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset); +} + +void Rewriter::moveTextAfter(const AST::SourceLocation &firstLoc, + const AST::SourceLocation &lastLoc, + const AST::SourceLocation &loc) +{ + move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset + loc.length); +} + +void Rewriter::move(int pos, int length, int to) +{ + textWriter.move(pos, length, to); +} + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/rewriter/rewriter.pri b/src/declarative/qml/rewriter/rewriter.pri new file mode 100644 index 0000000..2c29061 --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter.pri @@ -0,0 +1,9 @@ +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/textwriter_p.h +SOURCES += $$PWD/textwriter.cpp + +!no_ast_rewriter { + HEADERS += $$PWD/rewriter_p.h + SOURCES += $$PWD/rewriter.cpp +} diff --git a/src/declarative/qml/rewriter/rewriter_p.h b/src/declarative/qml/rewriter/rewriter_p.h new file mode 100644 index 0000000..57e7ea2 --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REWRITER_H +#define REWRITER_H + +#include "textwriter_p.h" + +#include <qmljsastvisitor_p.h> + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_BEGIN_HEADER +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +//////////////////////////////////////////////////////////////////////////////// +// Replacement +//////////////////////////////////////////////////////////////////////////////// +class Replacement +{ + int _offset; + int _length; + QString _text; + +public: + Replacement(int offset = 0, int length = 0, const QString &text = QString()) + : _offset(offset), _length(length), _text(text) + { } + + bool isNull() const { return _offset == _length; } + operator bool() const { return ! isNull(); } + + int offset() const { return _offset; } + int length() const { return _length; } + QString text() const { return _text; } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +// Rewriter +//////////////////////////////////////////////////////////////////////////////// +class Rewriter: public AST::Visitor +{ +protected: + TextWriter textWriter; +public: + // + // Token based API + // + + /// Returns the text of the token at the given \a location. + QString textAt(const AST::SourceLocation &location) const; + + QString textAt(const AST::SourceLocation &firstLoc, + const AST::SourceLocation &lastLoc) const; + + /// Replace the token at \a loc with the given \a text. + void replace(const AST::SourceLocation &loc, const QString &text); + + /// Remove the token at the given \a location. + void remove(const AST::SourceLocation &location); + + /// Remove all tokens in the range [\a firstLoc, \a lastLoc]. + void remove(const AST::SourceLocation &firstLoc, const AST::SourceLocation &lastLoc); + + /// Insert \a text before the token at the given \a location. + void insertTextBefore(const AST::SourceLocation &location, const QString &text); + + /// Insert \a text after the token at the given \a location. + void insertTextAfter(const AST::SourceLocation &loc, const QString &text); + + void moveTextBefore(const AST::SourceLocation &firstLoc, + const AST::SourceLocation &lastLoc, + const AST::SourceLocation &loc); + + void moveTextAfter(const AST::SourceLocation &firstLoc, + const AST::SourceLocation &lastLoc, + const AST::SourceLocation &loc); + + // + // low-level offset based API + // + virtual void replace(int offset, int length, const QString &text); + virtual void move(int pos, int length, int to); + void insertText(int offset, const QString &text); + void removeText(int offset, int length); + + /// Visit the given \a node. + void accept(AST::Node *node); + + /// Returns the original unchanged source code. + QString code() const { return _code; } + + /// Returns the list of replacements. + QList<Replacement> replacementList() const { return _replacementList; } + +protected: + /// \internal + void setCode(const QString &code) { _code = code; } + +private: + QString _code; + QList<Replacement> _replacementList; +}; + +} // end of namespace QmlJS + +QT_QML_END_NAMESPACE +QT_END_HEADER + +#endif // REWRITER_H diff --git a/src/declarative/qml/rewriter/textwriter.cpp b/src/declarative/qml/rewriter/textwriter.cpp new file mode 100644 index 0000000..8f89f12 --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "textwriter_p.h" + +QT_QML_BEGIN_NAMESPACE + +using namespace QmlJS; + +TextWriter::TextWriter() + :string(0), cursor(0) +{ +} + +static bool overlaps(int posA, int lengthA, int posB, int lengthB) { + return (posA < posB + lengthB && posA + lengthA > posB + lengthB) + || (posA < posB && posA + lengthA > posB); +} + +bool TextWriter::hasOverlap(int pos, int length) +{ + { + QListIterator<Replace> i(replaceList); + while (i.hasNext()) { + const Replace &cmd = i.next(); + if (overlaps(pos, length, cmd.pos, cmd.length)) + return true; + } + } + { + QListIterator<Move> i(moveList); + while (i.hasNext()) { + const Move &cmd = i.next(); + if (overlaps(pos, length, cmd.pos, cmd.length)) + return true; + } + return false; + } +} + +bool TextWriter::hasMoveInto(int pos, int length) +{ + QListIterator<Move> i(moveList); + while (i.hasNext()) { + const Move &cmd = i.next(); + if (cmd.to >= pos && cmd.to < pos + length) + return true; + } + return false; +} + +void TextWriter::replace(int pos, int length, const QString &replacement) +{ + Q_ASSERT(!hasOverlap(pos, length)); + Q_ASSERT(!hasMoveInto(pos, length)); + + Replace cmd; + cmd.pos = pos; + cmd.length = length; + cmd.replacement = replacement; + replaceList += cmd; +} + +void TextWriter::move(int pos, int length, int to) +{ + Q_ASSERT(!hasOverlap(pos, length)); + + Move cmd; + cmd.pos = pos; + cmd.length = length; + cmd.to = to; + moveList += cmd; +} + +void TextWriter::doReplace(const Replace &replace) +{ + int diff = replace.replacement.size() - replace.length; + { + QMutableListIterator<Replace> i(replaceList); + while (i.hasNext()) { + Replace &c = i.next(); + if (replace.pos < c.pos) + c.pos += diff; + else if (replace.pos + replace.length < c.pos + c.length) + c.length += diff; + } + } + { + QMutableListIterator<Move> i(moveList); + while (i.hasNext()) { + Move &c = i.next(); + if (replace.pos < c.pos) + c.pos += diff; + else if (replace.pos + replace.length < c.pos + c.length) + c.length += diff; + + if (replace.pos < c.to) + c.to += diff; + } + } + + if (string) { + string->replace(replace.pos, replace.length, replace.replacement); + } else if (cursor) { + cursor->setPosition(replace.pos); + cursor->setPosition(replace.pos + replace.length, QTextCursor::KeepAnchor); + cursor->insertText(replace.replacement); + } +} + +void TextWriter::doMove(const Move &move) +{ + QString text; + if (string) { + text = string->mid(move.pos, move.length); + } else if (cursor) { + cursor->setPosition(move.pos); + cursor->setPosition(move.pos + move.length, QTextCursor::KeepAnchor); + text = cursor->selectedText(); + } + + Replace cut; + cut.pos = move.pos; + cut.length = move.length; + Replace paste; + paste.pos = move.to; + paste.length = 0; + paste.replacement = text; + + replaceList.append(cut); + replaceList.append(paste); + + Replace cmd; + while (!replaceList.isEmpty()) { + cmd = replaceList.first(); + replaceList.removeFirst(); + doReplace(cmd); + } +} + +void TextWriter::write(QString *s) +{ + string = s; + write_helper(); + string = 0; +} + +void TextWriter::write(QTextCursor *textCursor) +{ + cursor = textCursor; + write_helper(); + cursor = 0; +} + +void TextWriter::write_helper() +{ + if (cursor) + cursor->beginEditBlock(); + { + Replace cmd; + while (!replaceList.isEmpty()) { + cmd = replaceList.first(); + replaceList.removeFirst(); + doReplace(cmd); + } + } + { + Move cmd; + while (!moveList.isEmpty()) { + cmd = moveList.first(); + moveList.removeFirst(); + doMove(cmd); + } + } + if (cursor) + cursor->endEditBlock(); +} + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/rewriter/textwriter_p.h b/src/declarative/qml/rewriter/textwriter_p.h new file mode 100644 index 0000000..a19fa5e --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTWRITER_H +#define TEXTWRITER_H + +#include <qmljsglobal_p.h> + +#include <QtCore/QString> +#include <QtCore/QList> +#include <QtGui/QTextCursor> + +QT_BEGIN_HEADER +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class TextWriter +{ + QString *string; + QTextCursor *cursor; + + struct Replace { + int pos; + int length; + QString replacement; + }; + + QList<Replace> replaceList; + + struct Move { + int pos; + int length; + int to; + }; + + QList<Move> moveList; + + bool hasOverlap(int pos, int length); + bool hasMoveInto(int pos, int length); + + void doReplace(const Replace &replace); + void doMove(const Move &move); + + void write_helper(); + +public: + TextWriter(); + + void replace(int pos, int length, const QString &replacement); + void move(int pos, int length, int to); + + void write(QString *s); + void write(QTextCursor *textCursor); + +}; + +} // end of namespace QmlJS + +QT_QML_END_NAMESPACE +QT_END_HEADER + +#endif // TEXTWRITER_H |