diff options
Diffstat (limited to 'src/declarative/qml')
137 files changed, 46655 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..986b146 --- /dev/null +++ b/src/declarative/qml/parser/parser.pri @@ -0,0 +1,22 @@ + +INCLUDEPATH += $$PWD +DEPENDPATH += $$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..eb9a8ab --- /dev/null +++ b/src/declarative/qml/parser/qmljs.g @@ -0,0 +1,3069 @@ +---------------------------------------------------------------------------- +-- +-- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +-- Contact: Qt Software Information (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 either Technology Preview License Agreement or the +-- Beta Release License Agreement. +-- +-- 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.0, included in the file LGPL_EXCEPTION.txt in this +-- package. +-- +-- GNU General Public License Usage +-- Alternatively, this file may be used under the terms of the GNU +-- General Public License version 3.0 as published by the Free Software +-- Foundation and appearing in the file LICENSE.GPL included in the +-- packaging of this file. Please review the following information to +-- ensure the GNU General Public License version 3.0 requirements will be +-- met: http://www.gnu.org/copyleft/gpl.html. +-- +-- If you are unsure which license is appropriate for your use, please +-- contact the sales department at qt-sales@nokia.com. +-- $QT_END_LICENSE$ +-- +-- This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +-- WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- +---------------------------------------------------------------------------- + +%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 + +%nonassoc SHIFT_THERE +%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY +%nonassoc REDUCE_HERE + +%start TopLevel + +/. +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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 parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + + 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(); + } + + 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_UI_OBJECT_MEMBER UiObjectMember ; +/. +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; +./ + +--QmlJSProgram: SourceElements ; +--/. +--case $rule_number: { +-- sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); +-- driver->changeAbstractSyntaxTree(sym(1).Node); +--} 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 (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)) { + const QString msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token_buffer[0].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) + 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..4c45bc8 --- /dev/null +++ b/src/declarative/qml/parser/qmljsast.cpp @@ -0,0 +1,955 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..ef8a66b --- /dev/null +++ b/src/declarative/qml/parser/qmljsast_p.h @@ -0,0 +1,2677 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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 ExpressionNode: public Node +{ +public: + ExpressionNode() {} + virtual ~ExpressionNode() {} + + virtual ExpressionNode *expressionCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class Statement: public Node +{ +public: + Statement() {} + virtual ~Statement() {} + + virtual Statement *statementCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 PropertyName: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(PropertyName) + + PropertyName() { kind = K; } + virtual ~PropertyName() {} + +// attributes + SourceLocation propertyNameToken; +}; + +class 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 SourceElement: public Node +{ +public: + QMLJS_DECLARE_AST_NODE(SourceElement) + + inline SourceElement() + { kind = K; } + + virtual ~SourceElement() {} +}; + +class 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 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 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 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 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 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 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 UiObjectMember: public Node +{ +public: + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; + + virtual UiObjectMember *uiObjectMemberCast(); +}; + +class 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 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 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 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 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 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 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 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 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 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 lbracketToken; } + + 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..fcb97ad --- /dev/null +++ b/src/declarative/qml/parser/qmljsastfwd_p.h @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLJSAST_FWD_P_H +#define QMLJSAST_FWD_P_H + +#include <QtCore/qglobal.h> +#include "qmljsglobal_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. +// + +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..642bcee --- /dev/null +++ b/src/declarative/qml/parser/qmljsastvisitor.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlJS { namespace AST { + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +} } // namespace QmlJS::AST + +QT_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..eea492a --- /dev/null +++ b/src/declarative/qml/parser/qmljsastvisitor_p.h @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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..32068c0 --- /dev/null +++ b/src/declarative/qml/parser/qmljsengine_p.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsglobal_p.h" +#include "qmljsengine_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..8627a99 --- /dev/null +++ b/src/declarative/qml/parser/qmljsengine_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QString> +#include <QSet> + +#include "qmljsglobal_p.h" +#include "qmljsastfwd_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { +class 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 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 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 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..99bb19f --- /dev/null +++ b/src/declarative/qml/parser/qmljsglobal_p.h @@ -0,0 +1,14 @@ +#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 +#else // !QT_CREATOR +#define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE +#define QT_QML_END_NAMESPACE QT_END_NAMESPACE +#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..da3ce2a --- /dev/null +++ b/src/declarative/qml/parser/qmljsgrammar.cpp @@ -0,0 +1,960 @@ +// This file was generated by qlalr - DO NOT EDIT! +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmljsgrammar_p.h" + +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}; + +const int QmlJSGrammar::lhs [] = { + 98, 98, 98, 98, 99, 103, 103, 106, 106, 108, + 107, 107, 107, 107, 107, 107, 107, 107, 110, 105, + 104, 113, 113, 114, 114, 115, 115, 112, 102, 102, + 102, 102, 102, 102, 102, 121, 121, 121, 122, 122, + 123, 123, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 111, 111, 111, 111, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 116, 128, 128, 128, 128, 127, 127, 130, + 130, 132, 132, 132, 132, 132, 132, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, + 109, 109, 109, 109, 109, 137, 137, 138, 138, 138, + 138, 136, 136, 139, 139, 140, 140, 141, 141, 141, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 143, 143, 143, 143, 144, 144, 144, 145, 145, 145, + 145, 146, 146, 146, 146, 146, 146, 146, 147, 147, + 147, 147, 147, 147, 148, 148, 148, 148, 148, 149, + 149, 149, 149, 149, 150, 150, 151, 151, 152, 152, + 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, + 158, 158, 159, 159, 160, 160, 161, 161, 131, 131, + 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 101, 101, 164, 164, 165, 165, + 166, 166, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 117, 178, 178, + 177, 177, 125, 125, 179, 179, 180, 180, 182, 182, + 181, 183, 186, 184, 184, 187, 185, 185, 118, 119, + 119, 120, 120, 167, 167, 167, 167, 167, 167, 167, + 168, 168, 168, 168, 169, 169, 169, 169, 170, 170, + 171, 173, 188, 188, 191, 191, 189, 189, 192, 190, + 172, 172, 172, 174, 174, 175, 175, 175, 193, 194, + 176, 176, 124, 135, 198, 198, 195, 195, 196, 196, + 199, 200, 200, 201, 201, 197, 197, 129, 129, 202}; + +const int QmlJSGrammar:: rhs[] = { + 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, 2, 1, 1, 0, 1, 0, 1, 2}; + +const int QmlJSGrammar::action_default [] = { + 0, 0, 0, 0, 20, 0, 168, 235, 199, 207, + 203, 147, 219, 195, 3, 132, 66, 148, 211, 215, + 136, 165, 146, 151, 131, 185, 172, 0, 73, 74, + 69, 336, 61, 338, 0, 0, 0, 0, 71, 0, + 0, 67, 70, 0, 0, 62, 64, 63, 72, 65, + 0, 68, 0, 0, 161, 0, 0, 148, 167, 150, + 149, 0, 0, 0, 163, 164, 162, 166, 0, 196, + 0, 0, 0, 0, 186, 0, 0, 0, 0, 0, + 0, 176, 0, 0, 0, 170, 171, 169, 174, 178, + 177, 175, 173, 188, 187, 189, 0, 204, 0, 200, + 0, 0, 142, 129, 141, 130, 98, 99, 100, 125, + 101, 126, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 127, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 128, 0, 0, 140, + 236, 143, 0, 144, 0, 145, 139, 0, 232, 225, + 223, 230, 231, 229, 228, 234, 227, 226, 224, 233, + 220, 0, 208, 0, 0, 212, 0, 0, 216, 0, + 0, 142, 134, 0, 133, 0, 138, 152, 0, 337, + 327, 328, 0, 325, 0, 326, 0, 329, 243, 250, + 249, 257, 245, 0, 246, 330, 0, 335, 247, 248, + 253, 251, 332, 331, 334, 254, 0, 265, 0, 0, + 0, 0, 336, 61, 0, 338, 62, 237, 279, 63, + 0, 0, 0, 266, 0, 0, 255, 256, 0, 244, + 252, 280, 281, 324, 333, 0, 295, 296, 297, 298, + 0, 291, 292, 293, 294, 321, 322, 0, 0, 0, + 0, 0, 284, 285, 241, 239, 201, 209, 205, 221, + 197, 242, 0, 148, 213, 217, 190, 179, 0, 0, + 198, 0, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 183, 181, 184, 182, 180, 193, 192, 194, 0, + 206, 0, 202, 0, 240, 148, 0, 222, 237, 238, + 0, 237, 0, 0, 287, 0, 0, 0, 289, 0, + 210, 0, 0, 214, 0, 0, 218, 277, 0, 269, + 278, 272, 0, 276, 0, 237, 270, 0, 237, 0, + 0, 288, 0, 0, 0, 290, 337, 327, 0, 0, + 329, 0, 323, 0, 313, 0, 0, 0, 283, 0, + 282, 0, 339, 0, 97, 259, 262, 0, 98, 265, + 101, 126, 103, 104, 69, 108, 109, 61, 110, 113, + 67, 70, 62, 237, 63, 72, 116, 65, 118, 68, + 120, 121, 266, 123, 124, 128, 0, 90, 0, 0, + 92, 96, 94, 81, 93, 95, 0, 91, 80, 260, + 258, 136, 137, 142, 0, 135, 0, 312, 0, 299, + 300, 0, 311, 0, 0, 0, 302, 307, 305, 308, + 0, 0, 306, 307, 0, 303, 0, 304, 261, 310, + 0, 261, 309, 0, 314, 315, 0, 261, 316, 317, + 0, 0, 318, 0, 0, 0, 319, 320, 154, 153, + 0, 0, 0, 286, 0, 0, 0, 301, 274, 267, + 0, 275, 271, 0, 273, 263, 0, 264, 268, 84, + 0, 0, 88, 75, 0, 77, 86, 0, 78, 87, + 89, 79, 85, 76, 0, 82, 158, 156, 160, 157, + 155, 159, 2, 59, 83, 0, 0, 62, 64, 63, + 29, 4, 0, 60, 0, 38, 37, 36, 0, 0, + 51, 0, 52, 0, 57, 58, 0, 38, 0, 0, + 0, 0, 0, 47, 48, 0, 49, 0, 50, 0, + 53, 54, 0, 0, 0, 0, 0, 55, 56, 0, + 45, 39, 46, 40, 0, 0, 0, 0, 42, 0, + 43, 44, 41, 0, 0, 28, 32, 33, 34, 35, + 136, 261, 0, 0, 98, 265, 101, 126, 103, 104, + 69, 108, 109, 61, 110, 113, 67, 70, 62, 237, + 63, 72, 116, 65, 118, 68, 120, 121, 266, 123, + 124, 128, 136, 0, 24, 0, 0, 30, 25, 31, + 26, 22, 0, 27, 23, 6, 0, 8, 0, 7, + 0, 1, 19, 10, 0, 11, 0, 12, 0, 17, + 18, 0, 13, 14, 0, 15, 16, 9, 21, 5, + 340}; + +const int QmlJSGrammar::goto_default [] = { + 5, 611, 355, 193, 501, 610, 629, 605, 609, 607, + 612, 20, 608, 16, 500, 602, 593, 555, 502, 188, + 192, 194, 198, 518, 544, 543, 197, 229, 24, 471, + 470, 353, 352, 7, 351, 354, 104, 15, 142, 22, + 11, 141, 17, 23, 54, 21, 6, 26, 25, 266, + 13, 260, 8, 256, 10, 258, 9, 257, 18, 264, + 19, 265, 12, 259, 255, 296, 408, 261, 262, 199, + 190, 189, 201, 230, 200, 205, 226, 227, 191, 357, + 356, 228, 460, 459, 318, 319, 462, 321, 461, 320, + 416, 420, 423, 419, 418, 438, 439, 182, 196, 178, + 181, 195, 203, 202, 0}; + +const int QmlJSGrammar::action_index [] = { + 251, 1237, 2238, 974, -45, 51, 122, -98, 52, -11, + -39, 182, -98, 389, 36, -98, -98, 628, 58, 75, + 246, 228, -98, -98, -98, 438, 309, 1237, -98, -98, + -98, 348, -98, 2050, 1772, 1237, 1237, 1237, -98, 800, + 1237, -98, -98, 1237, 1237, -98, -98, -98, -98, -98, + 1237, -98, 1237, 1237, -98, 1237, 1237, 97, 226, -98, + -98, 1237, 1237, 1237, -98, -98, -98, 200, 1237, 389, + 1237, 1237, 1237, 1237, 418, 1237, 1237, 1237, 1237, 1237, + 1237, 212, 1237, 1237, 1237, 144, 121, 71, 309, 309, + 164, 156, 179, 448, 428, 408, 1237, -51, 1237, 101, + 1956, 1237, 1237, -98, -98, -98, -98, -98, -98, -98, + -98, -98, -98, -98, -98, -98, -98, -98, -98, -98, + -98, -98, -98, -98, -98, -98, -98, -98, -98, -98, + -98, -98, -98, -98, -98, -98, -98, 236, 1237, -98, + -98, 31, 16, -98, 1237, -98, -98, 1237, -98, -98, + -98, -98, -98, -98, -98, -98, -98, -98, -98, -98, + -98, 1237, 2, 1237, 1237, 41, 35, 1237, -98, 1956, + 1237, 1237, -98, 102, -98, 6, -98, -98, 20, -98, + 299, 53, 14, -98, 321, -98, -22, 2332, -98, -98, + -98, -98, -98, 216, -98, -98, -28, -98, -98, -98, + -98, -98, -98, 2332, -98, -98, 469, -98, 533, 115, + 2238, -2, 335, -3, -36, 2520, 50, 1237, -98, 64, + 33, 1237, 21, -98, 5, -14, -98, -98, 306, -98, + -98, -98, -98, -98, -98, 74, -98, -98, -98, -98, + 117, -98, -98, -98, -98, -98, -98, -57, -18, 1237, + 140, 109, -98, -98, 1324, -98, 104, 67, 27, -98, + 330, 84, 29, 585, 80, 92, 464, 171, 295, 1237, + 314, 1237, 1237, 1237, 1237, 346, 1237, 1237, 1237, 1237, + 1237, 309, 309, 309, 309, 309, 386, 464, 464, 1237, + 27, 1237, 87, 1237, -98, 529, 1237, -98, 1237, 83, + 38, 1237, 48, 2238, -98, 1237, 143, 2238, -98, 1237, + 30, 1237, 1237, 81, 77, 1237, -98, 56, 126, 90, + -98, -98, 1237, -98, 290, 1237, -98, 42, 1237, 44, + 2238, -98, 1237, 133, 2238, -98, 22, 285, -37, -9, + 2332, -30, -98, 2238, -98, 1237, 141, 2238, 10, 2238, + -98, 26, 24, -24, -98, -98, 2238, 25, 453, 23, + 533, 106, 1237, 2238, 9, -29, 361, -4, -31, 800, + -6, 55, -98, 1415, -98, -1, -23, 8, 1237, 7, + -21, 1237, 1, 1237, -27, -19, 1237, -98, 2144, 28, + -98, -98, -98, -98, -98, -98, 1237, -98, -98, -98, + -98, 211, -98, 1237, 17, -98, 2238, -98, 98, -98, + -98, 2238, -98, 1237, 105, 37, -98, 63, -98, 62, + 99, 1237, -98, 60, 57, -98, 4, -98, 2238, -98, + 116, 2238, -98, 180, -98, -98, 112, 2238, 18, -98, + 11, 13, -98, 325, 3, 19, -98, -98, -98, -98, + 1237, 132, 2238, -98, 1237, 139, 2238, -98, 32, -98, + 174, -98, -98, 1237, -98, -98, 229, -98, -98, -98, + 108, 1682, -98, -98, 1862, -98, -98, 1505, -98, -98, + -98, -98, -98, -98, 125, -98, -98, -98, -98, -98, + -98, -98, -98, -98, 111, 46, 792, 184, 34, 85, + -98, -98, 136, -98, 185, -98, -98, -98, 65, 204, + -98, 1237, -98, 207, -98, -98, 193, 61, 43, 225, + 73, 88, 66, -98, -98, 214, -98, 1237, -98, 158, + -98, -98, 181, 91, 72, 1237, 172, -98, -98, 187, + -98, 157, -98, 47, -50, 274, 178, 250, -98, 113, + -98, -98, -98, 1592, 1062, -98, -98, -98, -98, -98, + 271, 2426, 1772, 15, 461, 146, 445, 76, 1237, 2238, + -5, 0, 370, 12, -15, 706, 89, 78, -98, 1415, + -98, 100, 59, 82, 1237, 86, 54, 1237, 79, 1237, + 45, 39, 279, 149, -98, 68, 617, -98, -98, -98, + -98, -98, 1150, -98, -98, -98, 886, -98, 240, -61, + 714, -98, -98, 129, 259, -98, 190, -98, 69, -98, + -98, 255, -98, -98, 94, -98, -98, -98, -98, -98, + -98, + + -105, 23, 25, 216, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -44, -105, -105, + -105, -105, -105, -105, -105, -105, -105, 70, -105, -105, + -105, 28, -105, -105, 20, 39, 97, 163, -105, 178, + 159, -105, -105, 156, 164, -105, -105, -105, -105, -105, + 132, -105, 153, 135, -105, 139, 140, -105, -105, -105, + -105, 103, 92, 144, -105, -105, -105, -105, 125, -105, + 154, 162, 83, 84, -105, 88, 82, 81, 75, 66, + 122, -105, 116, 98, 104, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 106, -105, 113, -105, + 86, 80, 52, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, 34, -105, + -105, -105, -105, -105, 38, -105, -105, 43, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, 136, -105, 91, -29, -105, -105, 3, -105, 225, + 37, 71, -105, -105, -105, -105, -105, -105, -105, -105, + -3, -105, -105, -105, 18, -105, -105, 27, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, 87, -105, -105, 62, -105, 56, -105, + 50, -105, 31, -105, -105, -105, -105, 59, -105, -105, + -105, 47, 69, -105, -105, -105, -105, -105, 67, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, 30, + -105, -105, -105, -105, 96, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, 10, 184, + -105, 222, 226, 232, 202, -105, 124, 114, 112, 110, + 95, -105, -105, -105, -105, -105, -105, -105, -105, 212, + -105, 192, -105, 177, -105, -105, 208, -105, 107, -105, + -105, 255, -105, 11, -105, 13, -105, 44, -105, 206, + -105, 169, 176, -105, -105, 183, -105, -105, -105, -105, + -105, -105, 173, -105, 167, 117, -105, -105, 191, -105, + 54, -105, 55, -105, 58, -105, -105, 102, -105, -105, + 89, -105, -105, 57, -105, 46, -105, 45, -105, 49, + -105, -105, -105, -105, -105, -105, 77, -105, 64, -105, + 51, -105, 109, 61, -105, -105, 48, -105, -105, 152, + -105, -105, -105, 79, -105, -105, -105, -105, 4, -105, + -16, 153, -105, 74, -105, -105, -11, -105, 0, -105, + -105, -105, -105, -105, -105, -105, -5, -105, -105, -105, + -105, -105, -105, 68, -105, -105, 41, -105, -105, -105, + -105, 90, -105, -1, -105, -105, -105, -105, -105, -93, + -105, 32, -105, -4, -105, -105, -105, -105, -22, -105, + -105, -14, -105, -105, -105, -105, -105, -105, -26, -105, + -105, -2, -105, 60, -105, 53, -105, -105, -105, -105, + 65, -105, 76, -105, 78, -105, 72, -105, -105, -105, + -105, -105, -105, 21, -105, -105, 85, -105, -105, -105, + -105, 22, -105, -105, 180, -105, -105, 33, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 73, -105, -105, -105, + -105, -105, -105, -105, 63, -105, -105, -105, -105, -105, + -105, 12, -105, -105, -105, -105, -105, -105, -105, -12, + -105, -105, -105, -105, -105, -105, -105, 6, -105, -105, + -105, -105, -15, -105, -105, 9, -105, -105, -105, -105, + -105, -9, -105, -105, -105, -7, -18, -13, -105, -105, + -105, -105, -105, 277, 266, -105, -105, -105, -105, -105, + -105, -105, 269, 2, 26, -105, 24, -105, 170, 16, + -105, -105, 19, -105, -105, 182, -105, -105, -105, 35, + -105, -105, -105, -105, 42, -105, 29, 153, -105, 128, + -105, -105, -105, -105, -105, -105, 349, -105, -105, -105, + -105, -105, 274, -105, -105, -105, 14, -105, -105, 15, + 218, -105, -105, -105, 7, -105, -105, -105, -105, -105, + -105, 17, -105, -105, -105, -105, -105, -105, -105, -105, + -105}; + +const int QmlJSGrammar::action_info [] = { + 345, -114, -106, -92, 343, 345, -95, 254, -122, 450, + 549, 187, 437, 413, -119, -117, -106, 454, 249, -92, + 248, 345, 454, 339, 340, 342, 349, 233, 98, 606, + -125, 398, 388, 386, 254, 396, 254, 96, 441, 144, + 98, 450, 167, 161, 138, 606, 437, 443, 554, 463, + 96, 630, 437, 68, 437, 546, 180, 406, 337, 427, + 161, 184, -96, 445, 428, 421, 176, 421, 421, 413, + 417, 411, 525, 322, 186, 454, 146, 405, 289, 535, + 400, 450, 309, 309, 315, -96, -122, 437, 269, -117, + 298, 138, 293, -119, 509, 413, -114, 521, 519, 301, + 532, 554, 68, 328, 330, 269, 291, -95, 303, 424, + 138, 55, 504, 138, 539, 289, 474, 522, 440, 0, + 534, 332, 56, 431, 138, 163, 169, 524, 523, 164, + 620, 619, 441, 138, 324, 239, 238, 246, 245, 59, + 138, 138, 311, 553, 169, 170, 312, 138, 138, 138, + 60, 138, 0, -125, 425, 626, 625, 596, 174, 410, + 409, 55, 55, 170, 475, 415, 138, 246, 245, 554, + 253, 252, 56, 56, 551, 550, 246, 245, 244, 243, + 138, 82, 466, 83, 55, 485, 505, 325, 138, 82, + 0, 83, 452, 334, 84, 56, 82, 100, 83, 456, + 251, 347, 84, 307, 82, 597, 83, 505, 169, 84, + 505, 511, 61, 517, 505, 138, 101, 84, 102, 531, + 530, 527, 0, 541, 138, 0, 169, 170, 0, 403, + 0, 0, 507, 538, 537, 467, 465, 82, 61, 83, + 61, 435, 434, 506, 138, 170, 0, 403, 542, 540, + 84, 623, 622, 507, 505, 0, 507, 62, 32, 507, + 507, 169, 0, 63, 506, 512, 510, 506, 515, 514, + 506, 506, 0, 0, 0, 528, 526, 232, 231, 32, + 170, 621, 171, 62, 32, 62, 169, 616, 32, 63, + 0, 63, 139, 0, 169, 45, 47, 46, 0, 0, + 507, 617, 615, 32, -83, 170, 0, 171, 0, 0, + 0, 506, -83, 170, 32, 171, 45, 47, 46, 32, + 0, 45, 47, 46, 32, 45, 47, 46, 32, 0, + 0, 614, 271, 272, 82, 32, 83, 0, 0, 0, + 45, 47, 46, 4, 3, 2, 1, 84, 271, 272, + 32, 45, 47, 46, 32, 0, 45, 47, 46, 273, + 274, 45, 47, 46, 32, 45, 47, 46, 0, 276, + 277, 0, 45, 47, 46, 273, 274, 32, 278, 0, + 0, 279, 0, 280, 0, 0, 0, 45, 47, 46, + 32, 45, 47, 46, 0, 0, 0, -336, 0, 32, + 0, 45, 47, 46, 0, 0, -336, 70, 71, 276, + 277, 0, 0, 0, 45, 47, 46, 0, 278, 0, + 0, 279, 0, 280, 0, 0, 0, 45, 47, 46, + 0, 75, 76, 0, 72, 73, 45, 47, 46, 77, + 78, 75, 76, 79, 0, 80, 0, 0, 0, 77, + 78, 75, 76, 79, 0, 80, 0, 0, 0, 77, + 78, 75, 76, 79, 0, 80, 0, 0, 0, 77, + 78, 75, 76, 79, 32, 80, 0, 0, 0, 77, + 78, 0, 32, 79, 0, 80, 0, 276, 277, 0, + 32, 0, 0, 0, 0, 0, 278, 0, 32, 279, + 0, 280, 0, 0, 0, 0, 242, 241, 0, 0, + 0, 45, 47, 46, 237, 236, 0, 0, 0, 45, + 47, 46, 237, 236, 0, 0, 0, 45, 47, 46, + 237, 236, 148, 0, 0, 45, 47, 46, 0, 0, + 0, 0, 149, 0, 0, 0, 150, 0, 0, 0, + 0, 0, 0, 0, 0, 151, 0, 152, 0, 0, + 0, 0, 32, 0, 0, 0, 0, 0, 153, 0, + 154, 59, 0, 0, 0, 0, 0, 0, 155, 0, + 0, 156, 60, 0, 0, 0, 0, 157, 148, 0, + 0, 0, 0, 158, 242, 241, 0, 0, 149, 45, + 47, 46, 150, 0, 0, 0, 0, 0, 0, 159, + 0, 151, 0, 152, 0, 0, 305, 0, 0, 0, + 0, 0, 0, 0, 153, 0, 154, 59, 0, 28, + 29, 148, 0, 0, 155, 0, 0, 156, 60, 31, + 0, 149, 0, 157, 0, 150, 32, 0, 0, 158, + 33, 34, 0, 35, 151, 0, 152, 0, 0, 0, + 496, 0, 0, 0, 42, 159, 0, 153, 0, 154, + 59, 0, 0, 0, 0, 0, 0, 155, 0, 0, + 156, 60, 48, 45, 47, 46, 157, 49, 0, 0, + 0, 0, 158, 0, 0, 0, 0, 0, 41, 51, + 30, 0, 0, 0, 38, 0, 0, 0, 159, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, + 0, 0, 0, 0, 0, 0, 28, 29, 31, 0, + 0, 0, 0, 0, 0, 32, 31, 0, 0, 33, + 34, 0, 35, 32, 0, 0, 0, 33, 34, 39, + 35, 0, 0, 42, 0, 0, 0, 496, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 48, 45, 47, 46, 0, 49, 0, 0, 48, + 45, 47, 46, 0, 49, 0, 0, 41, 51, 30, + 0, 0, 0, 38, 0, 41, 51, 30, 0, 0, + 0, 38, 0, 0, 28, 29, 0, 0, 0, 0, + 0, 0, 28, 29, 31, 0, 0, 0, 0, 0, + 0, 32, 31, 0, 0, 33, 34, 0, 35, 32, + 0, 0, 0, 33, 34, 496, 35, 0, 0, 42, + 0, 0, 0, 39, 0, 0, 0, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 45, 47, + 46, 0, 49, 0, 0, 48, 45, 47, 46, 0, + 49, 0, 0, 41, 51, 30, 0, 0, 0, 38, + 0, 41, 51, 30, 0, 0, 0, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, + 0, 0, 0, 0, 0, 32, 0, 0, 0, 33, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 496, + 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 48, 45, 47, 46, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 51, 30, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 495, 0, 28, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, + 0, 0, 0, 32, 0, 0, 0, 33, 34, 0, + 35, 0, 0, 0, 0, 0, 0, 496, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, + 497, 499, 498, 0, 49, 0, 0, 0, 0, 223, + 0, 0, 0, 0, 0, 41, 51, 30, 207, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 495, 0, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 33, 34, 0, 35, 0, + 0, 0, 0, 0, 0, 496, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 600, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 497, 499, + 498, 0, 49, 0, 0, 0, 0, 223, 0, 0, + 0, 0, 0, 41, 51, 30, 207, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 495, 0, 28, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 212, 0, 0, 0, 0, 0, 0, 32, + 0, 0, 0, 33, 34, 0, 35, 0, 0, 0, + 0, 0, 0, 496, 0, 0, 0, 42, 0, 0, + 0, 0, 0, 0, 0, 603, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 48, 497, 499, 498, 0, + 49, 0, 0, 0, 0, 223, 0, 0, 0, 0, + 0, 41, 51, 30, 207, 0, 0, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, + 29, 0, 0, 0, 0, 0, 0, 0, 0, 31, + 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, + 33, 34, 0, 35, 0, 0, 0, 36, 0, 37, + 39, 40, 0, 0, 42, 0, 0, 0, 43, 0, + 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 45, 47, 46, 0, 49, 0, 50, + 0, 52, 0, 53, 0, 0, 0, 0, 41, 51, + 30, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, + 0, 0, 0, 32, 0, 0, 0, 33, 34, 0, + 35, 0, 0, 0, 36, 0, 37, 39, 40, 0, + 0, 42, 0, 0, 0, 43, 0, 44, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, + 45, 47, 46, 0, 49, 0, 50, 0, 52, 268, + 53, 0, 0, 0, 0, 41, 51, 30, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -115, 0, 0, 0, 27, 28, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 33, 34, + 0, 35, 0, 0, 0, 36, 0, 37, 39, 40, + 0, 0, 42, 0, 0, 0, 43, 0, 44, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 45, 47, 46, 0, 49, 0, 50, 0, 52, + 0, 53, 0, 0, 0, 0, 41, 51, 30, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 480, 0, 0, 27, 28, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 33, 34, + 0, 35, 0, 0, 0, 36, 0, 37, 39, 40, + 0, 0, 42, 0, 0, 0, 43, 0, 44, 0, + 0, 481, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 45, 47, 46, 0, 49, 0, 50, 0, 52, + 0, 53, 0, 0, 0, 0, 41, 51, 30, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 27, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, + 0, 32, 214, 0, 0, 561, 562, 0, 35, 0, + 0, 0, 36, 0, 37, 39, 40, 0, 0, 42, + 0, 0, 0, 43, 0, 44, 0, 0, 0, 0, + 0, 0, 0, 218, 0, 0, 0, 48, 45, 47, + 46, 0, 49, 0, 50, 0, 52, 0, 53, 0, + 0, 0, 0, 41, 51, 30, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 480, 0, 0, 27, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 33, 34, 0, 35, 0, + 0, 0, 36, 0, 37, 39, 40, 0, 0, 42, + 0, 0, 0, 43, 0, 44, 0, 0, 483, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 45, 47, + 46, 0, 49, 0, 50, 0, 52, 0, 53, 0, + 0, 0, 0, 41, 51, 30, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 472, 0, 0, 27, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 33, 34, 0, 35, 0, + 0, 0, 36, 0, 37, 39, 40, 0, 0, 42, + 0, 0, 0, 43, 0, 44, 0, 0, 473, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 45, 47, + 46, 0, 49, 0, 50, 0, 52, 0, 53, 0, + 0, 0, 0, 41, 51, 30, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 472, 0, 0, 27, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 33, 34, 0, 35, 0, + 0, 0, 36, 0, 37, 39, 40, 0, 0, 42, + 0, 0, 0, 43, 0, 44, 0, 0, 478, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 45, 47, + 46, 0, 49, 0, 50, 0, 52, 0, 53, 0, + 0, 0, 0, 41, 51, 30, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 107, 108, 0, 0, 110, 112, 113, 0, 0, + 114, 0, 115, 0, 0, 0, 117, 118, 119, 0, + 0, 0, 0, 0, 0, 32, 120, 121, 122, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, + 0, 0, 45, 47, 46, 127, 128, 129, 0, 131, + 132, 133, 134, 135, 136, 0, 0, 124, 130, 116, + 109, 111, 125, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 106, 107, 108, 0, 0, 110, + 112, 113, 0, 0, 114, 0, 115, 0, 0, 0, + 117, 118, 119, 0, 0, 0, 0, 0, 0, 390, + 120, 121, 122, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 123, 0, 0, 0, 391, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, + 0, 0, 0, 0, 0, 395, 392, 394, 0, 127, + 128, 129, 0, 131, 132, 133, 134, 135, 136, 0, + 0, 124, 130, 116, 109, 111, 125, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, + 108, 0, 0, 110, 112, 113, 0, 0, 114, 0, + 115, 0, 0, 0, 117, 118, 119, 0, 0, 0, + 0, 0, 0, 390, 120, 121, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, + 0, 391, 0, 0, 0, 0, 0, 0, 0, 393, + 0, 0, 0, 126, 0, 0, 0, 0, 0, 395, + 392, 394, 0, 127, 128, 129, 0, 131, 132, 133, + 134, 135, 136, 0, 0, 124, 130, 116, 109, 111, + 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 206, 0, 0, 0, 0, 208, 0, 27, + 28, 29, 210, 0, 0, 0, 0, 0, 0, 211, + 31, 0, 0, 0, 0, 0, 0, 213, 214, 0, + 0, 215, 34, 0, 35, 0, 0, 0, 36, 0, + 37, 39, 40, 0, 0, 42, 0, 0, 0, 43, + 0, 44, 0, 0, 0, 0, 0, 217, 0, 218, + 0, 0, 0, 48, 216, 219, 46, 220, 49, 221, + 50, 222, 52, 223, 53, 224, 225, 0, 0, 41, + 51, 30, 207, 209, 0, 38, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, + 0, 208, 0, 27, 28, 29, 210, 0, 0, 0, + 0, 0, 0, 211, 212, 0, 0, 0, 0, 0, + 0, 213, 214, 0, 0, 215, 34, 0, 35, 0, + 0, 0, 36, 0, 37, 39, 40, 0, 0, 42, + 0, 0, 0, 43, 0, 44, 0, 0, 0, 0, + 0, 217, 0, 218, 0, 0, 0, 48, 216, 219, + 46, 220, 49, 221, 50, 222, 52, 223, 53, 224, + 225, 0, 0, 41, 51, 30, 207, 209, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 564, 107, 108, 0, 0, 566, 112, 568, 28, 29, + 569, 0, 115, 0, 0, 0, 117, 571, 572, 0, + 0, 0, 0, 0, 0, 573, 574, 121, 122, 215, + 34, 0, 35, 0, 0, 0, 36, 0, 37, 575, + 40, 0, 0, 577, 0, 0, 0, 43, 0, 44, + 0, 0, 0, 0, 0, 579, 0, 218, 0, 0, + 0, 581, 578, 580, 46, 582, 583, 584, 50, 586, + 587, 588, 589, 590, 591, 0, 0, 576, 585, 570, + 565, 567, 125, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 358, 107, 108, 0, 0, 360, + 112, 362, 28, 29, 363, 0, 115, 0, 0, 0, + 117, 365, 366, 0, 0, 0, 0, 0, 0, 367, + 368, 121, 122, 215, 34, 0, 35, 0, 0, 0, + 36, 0, 37, 369, 40, 0, 0, 371, 0, 0, + 0, 43, 0, 44, 0, -261, 0, 0, 0, 373, + 0, 218, 0, 0, 0, 375, 372, 374, 46, 376, + 377, 378, 50, 380, 381, 382, 383, 384, 385, 0, + 0, 370, 379, 364, 359, 361, 125, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 548, 422, 414, 436, 166, 547, 552, 433, 533, 529, + 183, 520, 536, 304, 545, 513, 306, 447, 247, 599, + 618, 147, 387, 317, 627, 613, 14, 492, 397, 204, + 624, 185, 179, 250, 389, 430, 168, 240, 299, 235, + 173, 179, 484, 407, 336, 433, 308, 348, 436, 346, + 433, 350, 247, 469, 464, 482, 331, 429, 333, 344, + 335, 179, 299, 247, 240, 432, 479, 140, 451, 240, + 442, 145, 446, 444, 457, 235, 160, 235, 453, 399, + 458, 455, 299, 137, 516, 143, 508, 426, 436, 204, + 0, 204, 412, 0, 0, 0, 0, 0, 458, 103, + 0, 143, 0, 0, 143, 0, 404, 0, 57, 175, + 299, 0, 57, 91, 177, 183, 57, 57, 449, 0, + 299, 105, 90, 57, 57, 57, 57, 0, 89, 88, + 57, 94, 95, 57, 57, 81, 65, 57, 263, 57, + 57, 486, 285, 267, 86, 57, 57, 64, 57, 165, + 87, 57, 57, 177, 57, 57, 57, 284, 57, 283, + 97, 282, 85, 401, 57, 99, 57, 57, 468, 92, + 57, 281, 449, 300, 57, 69, 491, 57, 57, 449, + 317, 57, 57, 327, 58, 67, 57, 341, 66, 401, + 234, 402, 162, 401, 299, 57, 57, 448, 57, 338, + 489, 57, 74, 488, 57, 57, 57, 487, 490, 477, + 93, 57, 57, 476, 177, 295, 267, 402, 295, 295, + 267, 402, 0, 267, 267, 295, 57, 494, 313, 494, + 267, 267, 628, 0, 57, 270, 595, 323, 103, 267, + 314, 294, 493, 503, 57, 292, 0, 316, 57, 267, + 295, 288, 326, 267, 57, 267, 0, 329, 299, 267, + 105, 172, 0, 310, 57, 0, 0, 290, 57, 267, + 601, 275, 297, 267, 57, 286, 0, 494, 604, 267, + 592, 287, 0, 594, 0, 494, 0, 595, 560, 0, + 0, 0, 493, 503, 0, 563, 556, 557, 558, 559, + 493, 503, 469, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 302, 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, + 494, 0, 0, 598, 0, 0, 0, 595, 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, 0}; + +const int QmlJSGrammar::action_check [] = { + 36, 7, 7, 7, 7, 36, 7, 36, 7, 36, + 60, 33, 33, 36, 7, 7, 7, 36, 36, 7, + 77, 36, 36, 60, 33, 55, 16, 55, 79, 90, + 7, 55, 8, 7, 36, 7, 36, 48, 20, 8, + 79, 36, 7, 2, 8, 90, 33, 36, 33, 17, + 48, 0, 33, 1, 33, 8, 36, 7, 36, 55, + 2, 8, 7, 60, 7, 5, 60, 5, 5, 36, + 33, 7, 29, 17, 60, 36, 60, 60, 48, 7, + 55, 36, 2, 2, 7, 7, 7, 33, 1, 7, + 61, 8, 8, 7, 29, 36, 7, 24, 37, 61, + 66, 33, 1, 61, 60, 1, 79, 7, 60, 10, + 8, 40, 66, 8, 29, 48, 8, 29, 6, -1, + 29, 31, 51, 7, 8, 50, 15, 61, 62, 54, + 61, 62, 20, 8, 8, 61, 62, 61, 62, 42, + 8, 8, 50, 7, 15, 34, 54, 8, 8, 8, + 53, 8, -1, 7, 55, 61, 62, 8, 56, 61, + 62, 40, 40, 34, 56, 60, 8, 61, 62, 33, + 61, 62, 51, 51, 61, 62, 61, 62, 61, 62, + 8, 25, 8, 27, 40, 60, 29, 61, 8, 25, + -1, 27, 60, 60, 38, 51, 25, 15, 27, 60, + 60, 60, 38, 60, 25, 56, 27, 29, 15, 38, + 29, 7, 12, 29, 29, 8, 34, 38, 36, 61, + 62, 7, -1, 36, 8, -1, 15, 34, -1, 36, + -1, -1, 75, 61, 62, 61, 62, 25, 12, 27, + 12, 61, 62, 86, 8, 34, -1, 36, 61, 62, + 38, 61, 62, 75, 29, -1, 75, 57, 29, 75, + 75, 15, -1, 63, 86, 61, 62, 86, 61, 62, + 86, 86, -1, -1, -1, 61, 62, 61, 62, 29, + 34, 91, 36, 57, 29, 57, 15, 47, 29, 63, + -1, 63, 56, -1, 15, 66, 67, 68, -1, -1, + 75, 61, 62, 29, 33, 34, -1, 36, -1, -1, + -1, 86, 33, 34, 29, 36, 66, 67, 68, 29, + -1, 66, 67, 68, 29, 66, 67, 68, 29, -1, + -1, 91, 18, 19, 25, 29, 27, -1, -1, -1, + 66, 67, 68, 92, 93, 94, 95, 38, 18, 19, + 29, 66, 67, 68, 29, -1, 66, 67, 68, 45, + 46, 66, 67, 68, 29, 66, 67, 68, -1, 23, + 24, -1, 66, 67, 68, 45, 46, 29, 32, -1, + -1, 35, -1, 37, -1, -1, -1, 66, 67, 68, + 29, 66, 67, 68, -1, -1, -1, 36, -1, 29, + -1, 66, 67, 68, -1, -1, 36, 18, 19, 23, + 24, -1, -1, -1, 66, 67, 68, -1, 32, -1, + -1, 35, -1, 37, -1, -1, -1, 66, 67, 68, + -1, 23, 24, -1, 45, 46, 66, 67, 68, 31, + 32, 23, 24, 35, -1, 37, -1, -1, -1, 31, + 32, 23, 24, 35, -1, 37, -1, -1, -1, 31, + 32, 23, 24, 35, -1, 37, -1, -1, -1, 31, + 32, 23, 24, 35, 29, 37, -1, -1, -1, 31, + 32, -1, 29, 35, -1, 37, -1, 23, 24, -1, + 29, -1, -1, -1, -1, -1, 32, -1, 29, 35, + -1, 37, -1, -1, -1, -1, 61, 62, -1, -1, + -1, 66, 67, 68, 61, 62, -1, -1, -1, 66, + 67, 68, 61, 62, -1, -1, -1, 66, 67, 68, + 61, 62, 3, -1, -1, 66, 67, 68, -1, -1, + -1, -1, 13, -1, -1, -1, 17, -1, -1, -1, + -1, -1, -1, -1, -1, 26, -1, 28, -1, -1, + -1, -1, 29, -1, -1, -1, -1, -1, 39, -1, + 41, 42, -1, -1, -1, -1, -1, -1, 49, -1, + -1, 52, 53, -1, -1, -1, -1, 58, 3, -1, + -1, -1, -1, 64, 61, 62, -1, -1, 13, 66, + 67, 68, 17, -1, -1, -1, -1, -1, -1, 80, + -1, 26, -1, 28, -1, -1, 31, -1, -1, -1, + -1, -1, -1, -1, 39, -1, 41, 42, -1, 12, + 13, 3, -1, -1, 49, -1, -1, 52, 53, 22, + -1, 13, -1, 58, -1, 17, 29, -1, -1, 64, + 33, 34, -1, 36, 26, -1, 28, -1, -1, -1, + 43, -1, -1, -1, 47, 80, -1, 39, -1, 41, + 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, + 52, 53, 65, 66, 67, 68, 58, 70, -1, -1, + -1, -1, 64, -1, -1, -1, -1, -1, 81, 82, + 83, -1, -1, -1, 87, -1, -1, -1, 80, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 12, 13, + -1, -1, -1, -1, -1, -1, 12, 13, 22, -1, + -1, -1, -1, -1, -1, 29, 22, -1, -1, 33, + 34, -1, 36, 29, -1, -1, -1, 33, 34, 43, + 36, -1, -1, 47, -1, -1, -1, 43, -1, -1, + -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, 68, -1, 70, -1, -1, 65, + 66, 67, 68, -1, 70, -1, -1, 81, 82, 83, + -1, -1, -1, 87, -1, 81, 82, 83, -1, -1, + -1, 87, -1, -1, 12, 13, -1, -1, -1, -1, + -1, -1, 12, 13, 22, -1, -1, -1, -1, -1, + -1, 29, 22, -1, -1, 33, 34, -1, 36, 29, + -1, -1, -1, 33, 34, 43, 36, -1, -1, 47, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -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, -1, -1, -1, -1, -1, -1, -1, -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, 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, -1, + -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, 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, + 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, 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, 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, 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, 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, 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, + 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, + 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, + 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, + 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, 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, 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, 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, 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, + 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, 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, + + 13, 94, 3, 19, 33, 23, 13, 3, 23, 3, + 13, 23, 3, 2, 23, 3, 3, 19, 2, 17, + 13, 65, 33, 13, 9, 11, 3, 2, 33, 2, + 13, 13, 13, 3, 34, 3, 33, 13, 3, 13, + 3, 13, 3, 2, 13, 3, 2, 2, 19, 3, + 3, 2, 2, 33, 33, 33, 2, 79, 3, 2, + 2, 13, 3, 2, 13, 79, 33, 33, 3, 13, + 96, 33, 19, 13, 2, 13, 33, 13, 2, 2, + 13, 3, 3, 3, 11, 33, 23, 91, 19, 2, + -1, 2, 2, -1, -1, -1, -1, -1, 13, 13, + -1, 33, -1, -1, 33, -1, 38, -1, 42, 38, + 3, -1, 42, 47, 44, 13, 42, 42, 44, -1, + 3, 35, 47, 42, 42, 42, 42, -1, 47, 47, + 42, 48, 48, 42, 42, 47, 44, 42, 42, 42, + 42, 44, 47, 47, 46, 42, 42, 44, 42, 58, + 46, 42, 42, 44, 42, 42, 42, 47, 42, 47, + 54, 47, 46, 11, 42, 52, 42, 42, 83, 47, + 42, 47, 44, 66, 42, 50, 44, 42, 42, 44, + 13, 42, 42, 66, 45, 45, 42, 98, 44, 11, + 103, 39, 56, 11, 3, 42, 42, 44, 42, 97, + 44, 42, 48, 44, 42, 42, 42, 44, 44, 29, + 48, 42, 42, 33, 44, 42, 47, 39, 42, 42, + 47, 39, -1, 47, 47, 42, 42, 11, 59, 11, + 47, 47, 14, -1, 42, 51, 18, 64, 13, 47, + 64, 64, 26, 27, 42, 53, -1, 64, 42, 47, + 42, 49, 85, 47, 42, 47, -1, 66, 3, 47, + 35, 36, -1, 57, 42, -1, -1, 55, 42, 47, + 4, 49, 64, 47, 42, 49, -1, 11, 4, 47, + 11, 49, -1, 14, -1, 11, -1, 18, 11, -1, + -1, -1, 26, 27, -1, 18, 19, 20, 21, 22, + 26, 27, 33, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 66, -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, + 11, -1, -1, 14, -1, -1, -1, 18, -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, -1}; + diff --git a/src/declarative/qml/parser/qmljsgrammar_p.h b/src/declarative/qml/parser/qmljsgrammar_p.h new file mode 100644 index 0000000..b297f81 --- /dev/null +++ b/src/declarative/qml/parser/qmljsgrammar_p.h @@ -0,0 +1,207 @@ +// This file was generated by qlalr - DO NOT EDIT! +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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. +// + +#ifndef QMLJSGRAMMAR_P_H +#define QMLJSGRAMMAR_P_H + +class QmlJSGrammar +{ +public: + enum { + EOF_SYMBOL = 0, + REDUCE_HERE = 97, + SHIFT_THERE = 96, + 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_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 = 630, + RULE_COUNT = 340, + STATE_COUNT = 631, + TERMINAL_COUNT = 98, + NON_TERMINAL_COUNT = 105, + + GOTO_INDEX_OFFSET = 631, + GOTO_INFO_OFFSET = 2618, + GOTO_CHECK_OFFSET = 2618 + }; + + static const char *const spell []; + static const int lhs []; + static const int rhs []; + static const int goto_default []; + static const int action_default []; + static const int action_index []; + static const int action_info []; + static const int action_check []; + + static inline int nt_action (int state, int nt) + { + const int *const goto_index = &action_index [GOTO_INDEX_OFFSET]; + const int *const goto_check = &action_check [GOTO_CHECK_OFFSET]; + + const int yyn = goto_index [state] + nt; + + if (yyn < 0 || goto_check [yyn] != nt) + return goto_default [nt]; + + const int *const goto_info = &action_info [GOTO_INFO_OFFSET]; + return goto_info [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]; + } +}; + + +#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..2c03c21 --- /dev/null +++ b/src/declarative/qml/parser/qmljslexer.cpp @@ -0,0 +1,1160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "qmljsglobal_p.h" +#include "qmljsengine_p.h" +#include "qmljslexer_p.h" +#include "qmljsgrammar_p.h" + +#include <QtGui/qapplication.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 = qApp->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 = qApp->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 = qApp->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 = qApp->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 = qApp->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 = qApp->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 = qApp->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 = qApp->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 = qApp->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..50f7c4b --- /dev/null +++ b/src/declarative/qml/parser/qmljslexer_p.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QString> + +#include "qmljsglobal_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class Engine; +class NameId; + +class 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..70e7737 --- /dev/null +++ b/src/declarative/qml/parser/qmljsmemorypool_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> +#include <string.h> + +#include "qmljsglobal_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QmlJS { + +class 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..dfe3bac --- /dev/null +++ b/src/declarative/qml/parser/qmljsnodepool_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QHash> +#include <QtCore/QString> + +#include "qmljsglobal_p.h" +#include "qmljsmemorypool_p.h" + +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 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..402aaeb --- /dev/null +++ b/src/declarative/qml/parser/qmljsparser.cpp @@ -0,0 +1,1825 @@ +// This file was generated by qlalr - DO NOT EDIT! + +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; + +case 6: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; + +case 7: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; + +case 8: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), + sym(1).UiImportList, sym(2).UiImport); +} break; + +case 11: { + sym(1).UiImport->semicolonToken = loc(2); +} break; + +case 13: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->semicolonToken = loc(3); +} break; + +case 15: { + 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 17: { + 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 18: { + 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 19: { + sym(1).Node = 0; +} break; + +case 20: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 21: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 22: { + AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; + +case 23: { + sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 24: { + AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 25: { + 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 26: { + 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 27: { + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; + +case 29: { + 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 30: { + 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 31:case 32:case 33:case 34: +{ + AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 35: + +case 36: { + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); + break; +} + +case 38: { + sym(1).Node = 0; +} break; + +case 39: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; + +case 40: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; + +case 41: { + 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 43: { + 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 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->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 47: { + 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 49: { + 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 51: { + 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 53: { + 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 55: { + 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 57: { + 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 58: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 59: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 61: { + QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 62: { + QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 63: { + QString s = QLatin1String(QmlJSGrammar::spell[T_READONLY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 64: { + AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); + node->thisToken = loc(1); + sym(1).Node = node; +} break; + +case 65: { + AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 66: { + AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); + node->nullToken = loc(1); + sym(1).Node = node; +} break; + +case 67: { + AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); + node->trueToken = loc(1); + sym(1).Node = node; +} break; + +case 68: { + AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); + node->falseToken = loc(1); + sym(1).Node = node; +} break; + +case 69: { + AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +case 70: +case 71: { + AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 72: { + 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 73: { + 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 74: { + 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 75: { + 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 76: { + 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 77: { + 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 78: { + 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 79: { + 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 80: { + 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 81: { + 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 82: { + 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 83: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); +} break; + +case 84: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; + +case 85: { + 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 86: { + 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 87: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; +} break; + +case 88: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 89: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 90: { + 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 91: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +case 92: +case 93: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 94: { + AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 95: { + AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 96: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 97: + +case 98: + +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: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; + +case 132: { + 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 133: { + 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 134: { + 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 136: { + AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; + +case 137: { + 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 138: { + 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 139: { + 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 140: { + 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 141: { + sym(1).Node = 0; +} break; + +case 142: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; + +case 143: { + sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); +} break; + +case 144: { + AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 148: { + AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; + +case 149: { + AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; + +case 151: { + AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; + +case 152: { + AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; + +case 153: { + AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; + +case 154: { + AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; + +case 155: { + AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; + +case 156: { + AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; + +case 157: { + AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; + +case 158: { + AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; + +case 159: { + AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; + +case 161: { + 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 162: { + 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 163: { + 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 165: { + 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 166: { + 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 168: { + 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 169: { + 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 170: { + 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 172: { + 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 173: { + 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 174: { + 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 175: { + 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 176: { + 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 177: { + 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 179: { + 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 180: { + 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 181: { + 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 182: { + 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 183: { + 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 185: { + 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 186: { + 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 187: { + 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 188: { + 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 190: { + 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 191: { + 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 192: { + 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 193: { + 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 195: { + 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 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::BitXor, 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::BitOr, 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::And, 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::Or, 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::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 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::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 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 222: { + sym(1).ival = QSOperator::Assign; +} break; + +case 223: { + sym(1).ival = QSOperator::InplaceMul; +} break; + +case 224: { + sym(1).ival = QSOperator::InplaceDiv; +} break; + +case 225: { + sym(1).ival = QSOperator::InplaceMod; +} break; + +case 226: { + sym(1).ival = QSOperator::InplaceAdd; +} break; + +case 227: { + sym(1).ival = QSOperator::InplaceSub; +} break; + +case 228: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; + +case 229: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; + +case 230: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; + +case 231: { + sym(1).ival = QSOperator::InplaceAnd; +} break; + +case 232: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 233: { + sym(1).ival = QSOperator::InplaceOr; +} break; + +case 235: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 236: { + sym(1).Node = 0; +} break; + +case 239: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 240: { + sym(1).Node = 0; +} break; + +case 257: { + 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 258: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); +} break; + +case 259: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); +} break; + +case 260: { + sym(1).Node = 0; +} break; + +case 261: { + sym(1).Node = sym(1).StatementList->finish (); +} break; + +case 263: { + 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 264: { + sym(1).ival = T_CONST; +} break; + +case 265: { + sym(1).ival = T_VAR; +} break; + +case 266: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 267: { + AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 268: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 269: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; + +case 270: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 271: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 272: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 273: { + sym(1).Node = 0; +} break; + +case 275: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 276: { + sym(1).Node = 0; +} break; + +case 278: { + AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; + +case 280: { + AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 281: { + 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 282: { + 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 284: { + 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 285: { + 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 286: { + 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 287: { + 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 288: { + 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 289: { + 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 291: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 293: { + 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 295: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 297: { + 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 299: { + 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 300: { + 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 301: { + 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 302: { + 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 303: { + 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 304: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); +} break; + +case 305: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); +} break; + +case 306: { + sym(1).Node = 0; +} break; + +case 307: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; + +case 308: { + 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 309: { + 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 310: +case 311: { + 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 312: { + 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 314: { + 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 315: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 316: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 317: { + 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 318: { + 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 319: { + AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; + +case 321: { + AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 322: { + 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 323: { + 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 324: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 325: { + 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 326: { + sym(1).Node = 0; +} break; + +case 327: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; + +case 328: { + sym(1).Node = 0; +} break; + +case 330: { + sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; + +case 331: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); +} break; + +case 332: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); +} break; + +case 333: { + sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); +} break; + +case 334: { + sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); +} break; + +case 335: { + sym(1).sval = 0; +} break; + +case 337: { + 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 (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)) { + const QString msg = qApp->translate("QmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token_buffer[0].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) + 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..b35bec3 --- /dev/null +++ b/src/declarative/qml/parser/qmljsparser_p.h @@ -0,0 +1,242 @@ +// This file was generated by qlalr - DO NOT EDIT! + +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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 parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + + 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(); + } + + 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 72 + +#define J_SCRIPT_REGEXPLITERAL_RULE2 73 + +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..70d5041 --- /dev/null +++ b/src/declarative/qml/qbitfield_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + 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 + 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..e7a7591 --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder.cpp @@ -0,0 +1,2573 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $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; + 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..fc26c11 --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder_p.h @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $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..818b4e7 --- /dev/null +++ b/src/declarative/qml/qml.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QML_H +#define QML_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qurl.h> +#include <QtCore/qmetaobject.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmlmetatype.h> +#include <QtDeclarative/qmlmetaproperty.h> +#include <QtDeclarative/qmlparserstatus.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qmllist.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_FROM, VERSION_MIN_TO, NAME, TYPE, EXTENSION) \ + static int registerExtended##TYPE = qmlRegisterExtendedType<TYPE,EXTENSION>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, #NAME, #TYPE); + +#define QML_DEFINE_TYPE(URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, NAME, TYPE) \ + static int defineType##TYPE = qmlRegisterType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, #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,0>::instance(qmlRegisterInterface<INTERFACE>(#INTERFACE)); + +#define QML_DEFINE_EXTENDED_TYPE(URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, NAME, TYPE, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN_FROM), (VERSION_MIN_TO)>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, #NAME, #TYPE)); + +#define QML_DEFINE_TYPE(URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, NAME, TYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN_FROM), (VERSION_MIN_TO)>::instance(qmlRegisterType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MIN_TO, #NAME, #TYPE)); + +#define QML_DEFINE_EXTENDED_NOCREATE_TYPE(TYPE, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,0,0,0>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#TYPE)); + +#define QML_DEFINE_NOCREATE_TYPE(TYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,0,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..cbc2f85 --- /dev/null +++ b/src/declarative/qml/qml.pri @@ -0,0 +1,121 @@ +SOURCES += qml/qmlparser.cpp \ + qml/qmlinstruction.cpp \ + qml/qmlvmemetaobject.cpp \ + qml/qmlengine.cpp \ + qml/qmlexpression.cpp \ + qml/qmlbinding.cpp \ + qml/qmlmetaproperty.cpp \ + qml/qmlcomponentjs.cpp \ + qml/qmlcomponent.cpp \ + qml/qmlcontext.cpp \ + qml/qmlcustomparser.cpp \ + qml/qmlpropertyvaluesource.cpp \ + qml/qmlpropertyvalueinterceptor.cpp \ + qml/qmlproxymetaobject.cpp \ + qml/qmlvme.cpp \ + qml/qmlcompiler.cpp \ + qml/qmlcompileddata.cpp \ + qml/qmlboundsignal.cpp \ + qml/qmldom.cpp \ + qml/qmlrefcount.cpp \ + qml/qmlprivate.cpp \ + qml/qmlmetatype.cpp \ + qml/qmlstringconverters.cpp \ + qml/qmlclassfactory.cpp \ + qml/qmlparserstatus.cpp \ + qml/qmlcompositetypemanager.cpp \ + qml/qmlinfo.cpp \ + qml/qmlerror.cpp \ + qml/qmlscriptparser.cpp \ + qml/qmlenginedebug.cpp \ + qml/qmlrewrite.cpp \ + qml/qmlbasicscript.cpp \ + qml/qmlvaluetype.cpp \ + qml/qmlbindingoptimizations.cpp \ + qml/qmlxmlhttprequest.cpp \ + qml/qmlsqldatabase.cpp \ + qml/qmetaobjectbuilder.cpp \ + qml/qmlwatcher.cpp \ + qml/qmlscript.cpp \ + qml/qmlcleanup.cpp \ + qml/qmlpropertycache.cpp \ + qml/qmlintegercache.cpp \ + qml/qmltypenamecache.cpp \ + qml/qmlscriptstring.cpp \ + qml/qmlobjectscriptclass.cpp \ + qml/qmlcontextscriptclass.cpp \ + qml/qmlglobalscriptclass.cpp \ + qml/qmlvaluetypescriptclass.cpp \ + qml/qmltypenamescriptclass.cpp \ + qml/qmllistscriptclass.cpp + +HEADERS += qml/qmlparser_p.h \ + qml/qmlinstruction_p.h \ + qml/qmlvmemetaobject_p.h \ + qml/qml.h \ + qml/qmlbinding.h \ + qml/qmlbinding_p.h \ + qml/qmlmetaproperty.h \ + qml/qmlcomponentjs_p.h \ + qml/qmlcomponentjs_p_p.h \ + qml/qmlcomponent.h \ + qml/qmlcomponent_p.h \ + qml/qmlcustomparser_p.h \ + qml/qmlcustomparser_p_p.h \ + qml/qmlpropertyvaluesource.h \ + qml/qmlpropertyvalueinterceptor.h \ + qml/qmlboundsignal_p.h \ + qml/qmlparserstatus.h \ + qml/qmlproxymetaobject_p.h \ + qml/qmlvme_p.h \ + qml/qmlcompiler_p.h \ + qml/qmlengine_p.h \ + qml/qmlexpression_p.h \ + qml/qmlprivate.h \ + qml/qmldom.h \ + qml/qmldom_p.h \ + qml/qmlrefcount_p.h \ + qml/qmlmetatype.h \ + qml/qmlengine.h \ + qml/qmlcontext.h \ + qml/qmlexpression.h \ + qml/qmlstringconverters_p.h \ + qml/qmlclassfactory_p.h \ + qml/qmlinfo.h \ + qml/qmlmetaproperty_p.h \ + qml/qmlcontext_p.h \ + qml/qmlcompositetypedata_p.h \ + qml/qmlcompositetypemanager_p.h \ + qml/qmllist.h \ + qml/qmldeclarativedata_p.h \ + qml/qmlerror.h \ + qml/qmlscriptparser_p.h \ + qml/qmlbasicscript_p.h \ + qml/qmlenginedebug_p.h \ + qml/qmlrewrite_p.h \ + qml/qpodvector_p.h \ + qml/qbitfield_p.h \ + qml/qmlvaluetype_p.h \ + qml/qmlbindingoptimizations_p.h \ + qml/qmlxmlhttprequest_p.h \ + qml/qmlsqldatabase_p.h \ + qml/qmetaobjectbuilder_p.h \ + qml/qmlwatcher_p.h \ + qml/qmlcleanup_p.h \ + qml/qmlpropertycache_p.h \ + qml/qmlintegercache_p.h \ + qml/qmltypenamecache_p.h \ + qml/qmlscriptstring.h \ + qml/qmlobjectscriptclass_p.h \ + qml/qmlcontextscriptclass_p.h \ + qml/qmlglobalscriptclass_p.h \ + qml/qmlvaluetypescriptclass_p.h \ + qml/qmltypenamescriptclass_p.h \ + qml/qmllistscriptclass_p.h + +# for qtscript debugger +contains(QT_CONFIG, scripttools):QT += scripttools + +include(parser/parser.pri) +include(rewriter/rewriter.pri) + diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp new file mode 100644 index 0000000..b7aac54 --- /dev/null +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -0,0 +1,763 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlbasicscript_p.h" +#include <QColor> +#include <QDebug> +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> +#include <QStack> +#include <private/qfxperf_p.h> +#include <private/qmlrefcount_p.h> +#include <private/qmljsast_p.h> +#include <private/qmljsengine_p.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(qmlBasicScriptDump, QML_BASICSCRIPT_DUMP); + +using namespace QmlJS; + +struct ScriptInstruction { + enum { + LoadIdObject, // fetch + FetchConstant, // constant + FetchContextConstant, // constant + FetchRootConstant, // constant + + Equals, // NA + + Int, // integer + Bool, // boolean + } type; + + union { + struct { + int idx; + } fetch; + struct { + int value; + } integer; + struct { + bool value; + } boolean; + struct { + short idx; + short notify; + int type; + } constant; + }; +}; + +class QmlBasicScriptPrivate +{ +public: + enum Flags { OwnData = 0x00000001 }; + + int size; + int stateSize; + int instructionCount; + int exprLen; + + ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } + + const char *expr() const + { + return (const char *)(instructions() + instructionCount); + } + + const char *data() const + { + return (const char *)(instructions() + instructionCount) + exprLen + 1; + } + + static unsigned int alignRound(int s) + { + if (s % 4) + s += 4 - (s % 4); + return s; + } +}; + +static QVariant fetch_value(QObject *o, int idx, int type) +{ + if (!o) + return QVariant(); + + switch(type) { + case QVariant::String: + { + QString val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::UInt: + { + uint val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Int: + { + int val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QMetaType::Float: + { + float val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Double: + { + double val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Color: + { + QColor val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Bool: + { + bool val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + default: + { + // 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 (QmlMetaType::isObject(type)) { + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *val = 0; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + if (!val) return QVariant(type, &val); + else return QVariant::fromValue(val); + } else { + QVariant var = o->metaObject()->property(idx).read(o); + if (QmlMetaType::isObject(var.userType())) { + QObject *obj = 0; + obj = *(QObject **)var.data(); + if (!obj) var = QVariant(var.userType(), &obj); + else var = QVariant::fromValue(obj); + } + return var; + } + } + break; + }; +} + +struct QmlBasicScriptCompiler +{ + QmlBasicScriptCompiler() + : script(0), stateSize(0) {} + + QmlBasicScript *script; + int stateSize; + + QmlParser::Object *context; + QmlParser::Object *component; + QHash<QString, QmlParser::Object *> ids; + + bool compile(QmlJS::AST::Node *); + + bool compileExpression(QmlJS::AST::Node *); + + bool tryConstant(QmlJS::AST::Node *); + bool parseConstant(QmlJS::AST::Node *); + bool tryName(QmlJS::AST::Node *); + bool parseName(QmlJS::AST::Node *); + + bool buildName(QStringList &, QmlJS::AST::Node *); + const QMetaObject *fetch(int type, const QMetaObject *, int idx); + + bool tryBinaryExpression(QmlJS::AST::Node *); + bool compileBinaryExpression(QmlJS::AST::Node *); + + QByteArray data; + QList<ScriptInstruction> bytecode; +}; + +/*! + \internal + \class QmlBasicScript + \brief The QmlBasicScript class provides a fast implementation of a limited subset of QmlJS bindings. + + QmlBasicScript instances are used to accelerate binding. Instead of using + the slower, fully fledged QmlJS engine, many simple bindings can be + evaluated using the QmlBasicScript engine. + + To see if the QmlBasicScript engine can handle a binding, call compile() + and check the return value, or isValid() afterwards. + + To accelerate binding, QmlBasicScript can return a precompiled + version of itself that can be saved for future use. Call compileData() to + get an opaque pointer to the compiled state, and compileDataSize() for the + size of this data in bytes. This data can be saved and passed to future + instances of the QmlBasicScript constructor. The initial copy of compile + data is owned by the QmlBindScript instance on which compile() was called. +*/ + +/*! + Create a new QmlBasicScript instance. +*/ +QmlBasicScript::QmlBasicScript() +: flags(0), d(0), rc(0) +{ +} + +/*! + Load the QmlBasicScript instance with saved \a data. + + \a data \b must be data previously acquired from calling compileData() on a + previously created QmlBasicScript instance. Any other data will almost + certainly cause the QmlBasicScript engine to crash. + + \a data must continue to be valid throughout the QmlBasicScript instance + life. It does not assume ownership of the memory. + + If \a owner is set, it is referenced on creation and dereferenced on + destruction of this instance. +*/ + +void QmlBasicScript::load(const char *data, QmlRefCount *owner) +{ + clear(); + d = (QmlBasicScriptPrivate *)data; + rc = owner; + if (rc) rc->addref(); +} + +/*! + Return the text of the script expression. + */ +QByteArray QmlBasicScript::expression() const +{ + if (!d) + return QByteArray(); + else + return QByteArray(d->expr()); +} + +/*! + Destroy the script instance. +*/ +QmlBasicScript::~QmlBasicScript() +{ + clear(); +} + +/*! + Clear this script. The object will then be in its initial state, as though + it were freshly constructed with default constructor. +*/ +void QmlBasicScript::clear() +{ + if (flags & QmlBasicScriptPrivate::OwnData) + free(d); + if (rc) rc->release(); + d = 0; + rc = 0; + flags = 0; +} + +/*! + Dump the script instructions to stderr for debugging. + */ +void QmlBasicScript::dump() +{ + if (!d) + return; + + qWarning() << d->instructionCount << "instructions:"; + for (int ii = 0; ii < d->instructionCount; ++ii) { + const ScriptInstruction &instr = d->instructions()[ii]; + + switch(instr.type) { + case ScriptInstruction::LoadIdObject: + qWarning().nospace() << "LOAD_ID_OBJECT"; + break; + case ScriptInstruction::FetchConstant: + qWarning().nospace() << "FETCH_CONSTANT"; + break; + case ScriptInstruction::FetchContextConstant: + qWarning().nospace() << "FETCH_CONTEXT_CONSTANT"; + break; + case ScriptInstruction::FetchRootConstant: + qWarning().nospace() << "FETCH_ROOT_CONSTANT"; + break; + case ScriptInstruction::Equals: + qWarning().nospace() << "EQUALS"; + break; + case ScriptInstruction::Int: + qWarning().nospace() << "INT\t\t" << instr.integer.value; + break; + case ScriptInstruction::Bool: + qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; + break; + default: + qWarning().nospace() << "UNKNOWN"; + break; + } + } +} + +/*! + Return true if this is a valid script binding, otherwise returns false. + */ +bool QmlBasicScript::isValid() const +{ + return d != 0; +} + +bool QmlBasicScript::compile(const Expression &expression) +{ + if (!expression.expression.asAST()) return false; + + QByteArray expr = expression.expression.asScript().toUtf8(); + const char *src = expr.constData(); + + QmlBasicScriptCompiler bsc; + bsc.script = this; + bsc.context = expression.context; + bsc.component = expression.component; + bsc.ids = expression.ids; + + if (d) { + if (flags & QmlBasicScriptPrivate::OwnData) + free(d); + d = 0; + flags = 0; + } + + if (bsc.compile(expression.expression.asAST())) { + int len = ::strlen(src); + flags = QmlBasicScriptPrivate::OwnData; + int size = sizeof(QmlBasicScriptPrivate) + + bsc.bytecode.count() * sizeof(ScriptInstruction) + + QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); + d = (QmlBasicScriptPrivate *) malloc(size); + d->size = size; + d->stateSize = bsc.stateSize; + d->instructionCount = bsc.bytecode.count(); + d->exprLen = len; + ::memcpy((char *)d->expr(), src, len + 1); + for (int ii = 0; ii < d->instructionCount; ++ii) + d->instructions()[ii] = bsc.bytecode.at(ii); + ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); + } + + if (d && qmlBasicScriptDump()) + dump(); + return d != 0; +} + +bool QmlBasicScriptCompiler::compile(QmlJS::AST::Node *node) +{ + return compileExpression(node); +} + +bool QmlBasicScriptCompiler::tryConstant(QmlJS::AST::Node *node) +{ + if (node->kind == AST::Node::Kind_TrueLiteral || + node->kind == AST::Node::Kind_FalseLiteral) + return true; + + if (node->kind == AST::Node::Kind_NumericLiteral) { + AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node); + + return double(int(lit->value)) == lit->value; + } + + return false; +} + +bool QmlBasicScriptCompiler::parseConstant(QmlJS::AST::Node *node) +{ + ScriptInstruction instr; + + if (node->kind == AST::Node::Kind_NumericLiteral) { + AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node); + instr.type = ScriptInstruction::Int; + instr.integer.value = int(lit->value); + } else { + instr.type = ScriptInstruction::Bool; + instr.boolean.value = node->kind == AST::Node::Kind_TrueLiteral; + } + + bytecode.append(instr); + + return true; +} + +bool QmlBasicScriptCompiler::tryName(QmlJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_IdentifierExpression || + node->kind == AST::Node::Kind_FieldMemberExpression; +} + +bool QmlBasicScriptCompiler::buildName(QStringList &name, + QmlJS::AST::Node *node) +{ + if (node->kind == AST::Node::Kind_IdentifierExpression) { + name << static_cast<AST::IdentifierExpression*>(node)->name->asString(); + } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { + AST::FieldMemberExpression *expr = + static_cast<AST::FieldMemberExpression *>(node); + + if (!buildName(name, expr->base)) + return false; + + name << expr->name->asString(); + } else { + return false; + } + + return true; +} + +const QMetaObject * +QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx) +{ + ScriptInstruction instr; + (int &)instr.type = type; + instr.constant.idx = idx; + QMetaProperty prop = mo->property(idx); + if (prop.isConstant()) + instr.constant.notify = 0; + else + instr.constant.notify = prop.notifySignalIndex(); + instr.constant.type = prop.userType(); + bytecode << instr; + return QmlMetaType::metaObjectForType(prop.userType()); +} + +bool QmlBasicScriptCompiler::parseName(AST::Node *node) +{ + QStringList nameParts; + if (!buildName(nameParts, node)) + return false; + + QmlParser::Object *absType = 0; + const QMetaObject *metaType = 0; + + for (int ii = 0; ii < nameParts.count(); ++ii) { + const QString &name = nameParts.at(ii); + + // We don't handle signal properties + if (name.length() > 2 && name.startsWith(QLatin1String("on")) && + name.at(2).isUpper()) + return false; + + if (ii == 0) { + + if (0) { + // ### - Must test for an attached type name + } else if (ids.contains(name)) { + ScriptInstruction instr; + instr.type = ScriptInstruction::LoadIdObject; + instr.fetch.idx = ids.value(name)->idIndex; + bytecode << instr; + absType = ids.value(name); + } else if(name.at(0).isLower()) { + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + + int d0Idx = context->metaObject()->indexOfProperty(cname); + int d1Idx = -1; + if (d0Idx == -1) + d1Idx = component->metaObject()->indexOfProperty(cname); + + if (d0Idx != -1) { + metaType = fetch(ScriptInstruction::FetchContextConstant, + context->metaObject(), d0Idx); + } else if(d1Idx != -1) { + metaType = fetch(ScriptInstruction::FetchRootConstant, + component->metaObject(), d1Idx); + } else { + return false; + } + + } else { + return false; + } + } else { + + if (!name.at(0).isLower()) + return false; + + const QMetaObject *mo = 0; + if (absType) + mo = absType->metaObject(); + else if(metaType) + mo = metaType; + else + return false; + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + int idx = mo->indexOfProperty(cname); + if (idx == -1) + return false; + + if (absType || mo->property(idx).isFinal()) { + absType = 0; metaType = 0; + metaType = fetch(ScriptInstruction::FetchConstant, mo, idx); + } else { + return false; + } + + } + } + + return true; +} + +bool QmlBasicScriptCompiler::compileExpression(QmlJS::AST::Node *node) +{ + if (tryBinaryExpression(node)) + return compileBinaryExpression(node); + else if (tryConstant(node)) + return parseConstant(node); + else if (tryName(node)) + return parseName(node); + else + return false; +} + +bool QmlBasicScriptCompiler::tryBinaryExpression(AST::Node *node) +{ + if (node->kind == AST::Node::Kind_BinaryExpression) { + AST::BinaryExpression *expr = + static_cast<AST::BinaryExpression *>(node); + + if (expr->op == QSOperator::Equal) + return true; + } + return false; +} + +bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) +{ + if (node->kind == AST::Node::Kind_BinaryExpression) { + AST::BinaryExpression *expr = + static_cast<AST::BinaryExpression *>(node); + + if (!compileExpression(expr->left)) return false; + if (!compileExpression(expr->right)) return false; + + ScriptInstruction instr; + switch (expr->op) { + case QSOperator::Equal: + instr.type = ScriptInstruction::Equals; + break; + default: + return false; + } + + bytecode.append(instr); + return true; + } + return false; +} + +/*! + Run the script in \a context and return the result. + */ +QVariant QmlBasicScript::run(QmlContext *context, QObject *me) +{ + if (!isValid()) + return QVariant(); + + QmlContextPrivate *contextPrivate = context->d_func(); + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(context->engine()); + + QStack<QVariant> stack; + + for (int idx = 0; idx < d->instructionCount; ++idx) { + const ScriptInstruction &instr = d->instructions()[idx]; + + switch(instr.type) { + case ScriptInstruction::LoadIdObject: + { + stack.push(QVariant::fromValue(contextPrivate->idValues[instr.fetch.idx].data())); + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx); + } + break; + + case ScriptInstruction::FetchContextConstant: + { + stack.push(fetch_value(me, instr.constant.idx, instr.constant.type)); + if (me && instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(me, instr.constant.idx, instr.constant.notify); + } + break; + + case ScriptInstruction::FetchRootConstant: + { + QObject *obj = contextPrivate->defaultObjects.last(); + + stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); + if (obj && instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); + } + break; + + case ScriptInstruction::FetchConstant: + { + QVariant o = stack.pop(); + QObject *obj = *(QObject **)o.constData(); + + stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); + if (obj && instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); + } + break; + + case ScriptInstruction::Int: + stack.push(QVariant(instr.integer.value)); + break; + + case ScriptInstruction::Bool: + stack.push(QVariant(instr.boolean.value)); + break; + + case ScriptInstruction::Equals: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs == lhs); + } + break; + default: + break; + } + } + + if (stack.isEmpty()) + return QVariant(); + else + return stack.top(); +} + +bool QmlBasicScript::isSingleIdFetch() const +{ + if (!isValid()) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::LoadIdObject; +} + +int QmlBasicScript::singleIdFetchIndex() const +{ + if (!isSingleIdFetch()) + return -1; + + return d->instructions()[0].fetch.idx; +} + +bool QmlBasicScript::isSingleContextProperty() const +{ + if (!isValid()) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::FetchContextConstant; +} + +int QmlBasicScript::singleContextPropertyIndex() const +{ + if (!isSingleContextProperty()) + return -1; + + return d->instructions()[0].constant.idx; +} + +/*! + Return a pointer to the script's compile data, or null if there is no data. + */ +const char *QmlBasicScript::compileData() const +{ + return (const char *)d; +} + +/*! + Return the size of the script's compile data, or zero if there is no data. + The size will always be a multiple of 4. + */ +unsigned int QmlBasicScript::compileDataSize() const +{ + if (d) + return d->size; + else + return 0; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h new file mode 100644 index 0000000..5ad7735 --- /dev/null +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_P_H +#define QMLBASICSCRIPT_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/QList> +#include <QtCore/QByteArray> +#include <QtCore/QVariant> +#include <private/qmlparser_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QmlRefCount; +class QmlContext; +class QmlBasicScriptPrivate; +class QmlBasicScriptNodeCache; +class QmlBasicScript +{ +public: + QmlBasicScript(); + ~QmlBasicScript(); + + void load(const char *, QmlRefCount * = 0); + + // Always 4-byte aligned + const char *compileData() const; + unsigned int compileDataSize() const; + + QByteArray expression() const; + + struct Expression + { + QmlParser::Object *component; + QmlParser::Object *context; + QmlParser::Property *property; + QmlParser::Variant expression; + QHash<QString, QmlParser::Object *> ids; + }; + + bool compile(const Expression &); + bool isValid() const; + + void clear(); + + void dump(); + + QVariant run(QmlContext *, QObject *); + + bool isSingleIdFetch() const; + int singleIdFetchIndex() const; + + bool isSingleContextProperty() const; + int singleContextPropertyIndex() const; +private: + int flags; + QmlBasicScriptPrivate *d; + QmlRefCount *rc; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLBASICSCRIPT_P_H diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp new file mode 100644 index 0000000..65ff789 --- /dev/null +++ b/src/declarative/qml/qmlbinding.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qml.h> +#include "qmlbinding.h" +#include "qmlbinding_p.h" +#include <qmlcontext.h> +#include <qmlinfo.h> +#include <QVariant> +#include <private/qfxperf_p.h> +#include <QtCore/qdebug.h> +#include <private/qmlcontext_p.h> +#include <private/qmldeclarativedata_p.h> +#include <private/qmlstringconverters_p.h> + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +QML_DEFINE_NOCREATE_TYPE(QmlBinding); + +QmlBindingData::QmlBindingData() +: updating(false), enabled(false) +{ +} + +QmlBindingPrivate::QmlBindingPrivate() +: QmlExpressionPrivate(new QmlBindingData) +{ +} + +QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, const QUrl &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 + QFxPerfTimer<QFxPerf::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 undefined = false; + QVariant value = this->value(&undefined); + + if (!undefined && data->property.object() && !data->property.write(value, flags)) { + QString fileName = data->fileName; + int line = data->line; + if (fileName.isEmpty()) fileName = QLatin1String("<Unknown File>"); + + const char *valueType = 0; + if (value.userType() == QVariant::Invalid) valueType = "null"; + else valueType = QMetaType::typeName(value.userType()); + qWarning().nospace() << qPrintable(fileName) << ":" << line + << " Unable to assign " << valueType << " to " + << QMetaType::typeName(data->property.propertyType()); + } + } + + data->updating = false; + } else { + qmlInfo(tr("Binding loop detected for property \"%1\"").arg(data->property.name()), data->property.object()); + } + + data->release(); +} + +void QmlBinding::valueChanged() +{ + update(); +} + +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::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..6a3e92a --- /dev/null +++ b/src/declarative/qml/qmlbinding.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDING_H +#define QMLBINDING_H + +#include <QtCore/QObject> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qmlexpression.h> +#include <QtCore/QMetaProperty> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlAbstractBinding +{ +public: + QmlAbstractBinding(); + virtual ~QmlAbstractBinding(); + + 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 QUrl &, 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: + virtual void valueChanged(); + +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..2c0c6b9 --- /dev/null +++ b/src/declarative/qml/qmlbinding_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qmlbinding.h> +#include <QtDeclarative/qmlmetaproperty.h> +#include "qmlexpression_p.h" + +QT_BEGIN_NAMESPACE + +class QmlBindingData : public QmlExpressionData +{ +public: + QmlBindingData(); + + bool updating:1; + bool enabled:1; + + QmlMetaProperty property; +}; + +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/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp new file mode 100644 index 0000000..6dc221e --- /dev/null +++ b/src/declarative/qml/qmlbindingoptimizations.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlbindingoptimizations_p.h" +#include <private/qmlcontext_p.h> + +QT_BEGIN_NAMESPACE + +/* + The QmlBinding_Id optimization handles expressions of the type: + + property: id + + where id is a local context id, and property is an object property. + Coercian between id and property must be checked outside the QmlBinding_Id - + it assumes that they coerce successfully. + + The QmlBinding_Id class avoids any signal slot connections, through the + special "bindings" linked list maintained in the + QmlContextPrivate::ContextGuard instance for each id object. +*/ +QmlBinding_Id::QmlBinding_Id(QObject *object, int propertyIdx, + QmlContext *context, int id) +: m_prev(0), m_next(0), m_object(object), m_propertyIdx(propertyIdx), m_id(id) +{ + QmlAbstractExpression::setContext(context); +} + +QmlBinding_Id::~QmlBinding_Id() +{ + removeFromContext(); +} + +void QmlBinding_Id::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +{ + if (e) { + addToObject(m_object); + update(flags); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e, flags); +} + +int QmlBinding_Id::propertyIndex() +{ + return m_propertyIdx; +} + +void QmlBinding_Id::update(QmlMetaProperty::WriteFlags flags) +{ + QmlContextPrivate *ctxtPriv = + static_cast<QmlContextPrivate *>(QObjectPrivate::get(context())); + + if (ctxtPriv) { + + if (!m_prev) { + m_next = ctxtPriv->idValues[m_id].bindings; + if (m_next) m_next->m_prev = &m_next; + + m_prev = &ctxtPriv->idValues[m_id].bindings; + ctxtPriv->idValues[m_id].bindings = this; + } + + QObject *o = ctxtPriv->idValues[m_id].data(); + int status = -1; + void *a[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, a); + } +} + +void QmlBinding_Id::removeFromContext() +{ + if (m_prev) { + *m_prev = m_next; + if (m_next) m_next->m_prev = m_prev; + m_next = 0; + m_prev = 0; + } +} + +void QmlBinding_Id::reset() +{ + removeFromContext(); + + QObject *o = 0; + int status = -1; + QmlMetaProperty::WriteFlags flags = QmlMetaProperty::DontRemoveBinding; + void *a[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, a); +} + +/* + The QmlBinding_ObjectProperty optimization handles expressions of the type: + + property: objectProperty + + where both property and objectProperty are object properties on the target + object. Coercian between the two must be checked outside the + QmlBinding_ObjectProperty - it assumes that they coerce successfully. + + Due to dot properties, property does not have to be on the same object as + objectProperty. For example: + + anchors.fill: parent +*/ +QmlBinding_ObjProperty::QmlBinding_ObjProperty(QObject *object, int propertyIdx, + QObject *context, int contextIdx, + int notifyIdx) +: m_enabled(false), m_object(object), m_propertyIdx(propertyIdx), + m_context(context), m_contextIdx(contextIdx), m_notifyIdx(notifyIdx) +{ +} + +void QmlBinding_ObjProperty::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +{ + m_enabled = e; + if (e) { + addToObject(m_object); + update(flags); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e, flags); +} + +int QmlBinding_ObjProperty::propertyIndex() +{ + return m_propertyIdx; +} + +void QmlBinding_ObjProperty::update(QmlMetaProperty::WriteFlags flags) +{ + if (!m_enabled) + return; + + QObject *value = 0; + int status = -1; + void *ra[] = { &value, 0, &status }; + + // Read + QMetaObject::metacall(m_context, QMetaObject::ReadProperty, + m_contextIdx, ra); + + void *wa[] = { &value, 0, &status, &flags }; + + // Write + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, wa); + + // Connect notify if needed. Only need to connect once, so we set + // m_notifyIdx back to -1 afterwards + static int slotIdx = -1; + if (m_notifyIdx != -1) { + if (slotIdx == -1) + slotIdx = QmlBinding_ObjProperty::staticMetaObject.indexOfMethod("update()"); + + QMetaObject::connect(m_context, m_notifyIdx, this, slotIdx); + m_notifyIdx = -1; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h new file mode 100644 index 0000000..d0a4df4 --- /dev/null +++ b/src/declarative/qml/qmlbindingoptimizations_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qmlexpression_p.h> +#include <QtDeclarative/qmlbinding.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QmlBinding_Id : public QmlAbstractExpression, + public QmlAbstractBinding +{ +public: + QmlBinding_Id(QObject *object, int propertyIdx, + QmlContext *context, int id); + virtual ~QmlBinding_Id(); + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + + void reset(); + +private: + void removeFromContext(); + + QmlBinding_Id **m_prev; + QmlBinding_Id *m_next; + + QObject *m_object; + int m_propertyIdx; + int m_id; +}; + +class QmlBinding_ObjProperty : public QObject, + public QmlAbstractExpression, + public QmlAbstractBinding +{ + Q_OBJECT +public: + QmlBinding_ObjProperty(QObject *object, int propertyIdx, + QObject *context, int contextIdx, int notifyIdx); + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + +private Q_SLOTS: + void update() { update(QmlMetaProperty::DontRemoveBinding); } + +private: + bool m_enabled; + QObject *m_object; + int m_propertyIdx; + QObject *m_context; + int m_contextIdx; + int m_notifyIdx; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLBINDINGOPTIMIZATIONS_P_H + diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp new file mode 100644 index 0000000..ce591e8 --- /dev/null +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlboundsignal_p.h" +#include "private/qmetaobjectbuilder_p.h" +#include "private/qmlengine_p.h" +#include "private/qmlexpression_p.h" +#include "private/qmlcontext_p.h" +#include <qfxglobal.h> +#include <qmlmetatype.h> +#include <qml.h> +#include <qmlcontext.h> +#include <QDebug> + +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_idx(signal.methodIndex()), 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(); + + QFx_setParent_noEvent(this, parent); + QMetaObject::connect(scope, m_idx, this, evaluateIdx); + + if (!signal.parameterTypes().isEmpty()) + m_params = new QmlBoundSignalParameters(signal, this); +} + +QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val, + QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_idx(signal.methodIndex()), 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(); + + QFx_setParent_noEvent(this, parent); + QMetaObject::connect(scope, m_idx, this, evaluateIdx); + + m_expression = new QmlExpression(ctxt, val, scope); + m_expression->setTrackChange(false); + + if (!signal.parameterTypes().isEmpty()) + m_params = new QmlBoundSignalParameters(signal, this); +} + +QmlBoundSignal::~QmlBoundSignal() +{ + delete m_expression; + m_expression = 0; +} + +int QmlBoundSignal::index() const +{ + return m_idx; +} + +/*! + 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_params) m_params->setValues(a); + if (m_expression) + QmlExpressionPrivate::get(m_expression)->value(m_params); + 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..51c7155 --- /dev/null +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qmlexpression.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; + int m_idx; + 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..ddfbd78 --- /dev/null +++ b/src/declarative/qml/qmlclassfactory.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..cd80ffc --- /dev/null +++ b/src/declarative/qml/qmlclassfactory_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..7799cfc --- /dev/null +++ b/src/declarative/qml/qmlcleanup.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcleanup_p.h" +#include <private/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) +{ + Q_ASSERT(engine); + 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..e9196a3 --- /dev/null +++ b/src/declarative/qml/qmlcleanup_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp new file mode 100644 index 0000000..7032a3b --- /dev/null +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qobject_p.h> +#include <QtCore/qdebug.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::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() +: importCache(0), root(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(); + + if (importCache) + importCache->release(); + + qDeleteAll(programs); +} + +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() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; + qWarning() << "-------------------------------------------------------------------------------"; + for (int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning() << "-------------------------------------------------------------------------------"; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp new file mode 100644 index 0000000..69ebf9c --- /dev/null +++ b/src/declarative/qml/qmlcompiler.cpp @@ -0,0 +1,2565 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmlcompiler_p.h" +#include "private/qmlcompositetypedata_p.h" +#include <private/qfxperf_p.h> +#include "qmlparser_p.h" +#include "private/qmlscriptparser_p.h" +#include <qmlpropertyvaluesource.h> +#include <qmlcomponent.h> +#include "private/qmetaobjectbuilder_p.h" +#include "qmlbasicscript_p.h" +#include <QColor> +#include <QDebug> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QAtomicInt> +#include <private/qmlstringconverters_p.h> +#include <private/qmlengine_p.h> +#include <qmlengine.h> +#include <qmlcontext.h> +#include <qmlmetatype.h> +#include <QtCore/qdebug.h> +#include <QtGui/qapplication.h> +#include "private/qmlcustomparser_p_p.h" +#include <private/qmlcontext_p.h> +#include <private/qmlcomponent_p.h> +#include "parser/qmljsast_p.h" +#include <private/qmlvmemetaobject_p.h> +#include <private/qmlexpression_p.h> +#include "qmlmetaproperty_p.h" +#include "qmlrewrite_p.h" +#include <QtDeclarative/qmlscriptstring.h> + +#include "qmlscriptparser_p.h" + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); + +using namespace QmlParser; + +/*! + Instantiate a new QmlCompiler. +*/ +QmlCompiler::QmlCompiler() +: output(0), engine(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 letter or underscore, and contain only + letters, numbers and underscores. +*/ +bool QmlCompiler::isValidId(const QString &val) +{ + if (val.isEmpty()) + return false; + + 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); +} + +/*! + 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, qApp->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; \ + } + +/*! + 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, qApp->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, qApp->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, qApp->translate("QmlCompiler","Invalid property assignment: string expected")); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: url expected")); + break; + case QVariant::UInt: + { + bool ok; + string.toUInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, qApp->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, qApp->translate("QmlCompiler","Invalid property assignment: int expected")); + } + break; + case QMetaType::Float: + { + bool ok; + string.toFloat(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: float expected")); + } + break; + case QVariant::Double: + { + bool ok; + string.toDouble(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: double expected")); + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(string); + if (!c.isValid()) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: color expected")); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(string, Qt::ISODate); + if (!d.isValid()) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: date expected")); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(string, Qt::ISODate); + if (!time.isValid()) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: time expected")); + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (!dateTime.isValid()) COMPILE_EXCEPTION(v, qApp->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, qApp->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, qApp->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, qApp->translate("QmlCompiler","Invalid property assignment: rect expected")); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: boolean expected")); + } + break; + case QVariant::Vector3D: + { + bool ok; + QVector3D point = QmlStringConverters::vector3DFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, qApp->translate("QmlCompiler","Invalid property assignment: 3D vector expected")); + } + break; + default: + { + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION(v, qApp->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->indexForString(u.toString()); + } + 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 = QDate::fromString(string, Qt::ISODate); + instr.type = QmlInstruction::StoreDate; + instr.storeDate.propertyIndex = prop.propertyIndex(); + instr.storeDate.value = d.toJulianDay(); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(string, Qt::ISODate); + 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 = QDateTime::fromString(string, Qt::ISODate); + 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.type(); + if (t == QVariant::UserType) + 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 + QFxPerfTimer<QFxPerf::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; + compileTree(root); + + if (!isError()) { + if (compilerDump()) + out->dumpInstructions(); + } else { + reset(out); + } + + compileState = ComponentCompileState(); + savedCompileStates.clear(); + output = 0; + this->engine = 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(); + 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); +} + +bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) +{ + 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; + } + } + + // Build all explicit properties specified + foreach(Property *prop, obj->properties) { + + 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 (obj->defaultProperty) { + Property *prop = obj->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; + } + + // 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()) { + while (obj->bindingBitmask.size() % 4) + obj->bindingBitmask.append(char(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 + output->propertyCaches << QmlPropertyCache::create(engine, obj->metaObject()); + 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->scriptBlocks.count(); ++ii) { + QmlInstruction script; + script.type = QmlInstruction::StoreScript; + script.line = 0; // ### + script.storeScript.fileName = output->indexForString(obj->scriptBlocksFile.at(ii)); + script.storeScript.lineNumber = obj->scriptBlocksLineNumber.at(ii); + script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii)); + 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; + + 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(); + 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") || + !obj->scriptBlockObjects.isEmpty()) + COMPILE_EXCEPTION(obj, qApp->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(obj, qApp->translate("QmlCompiler","Invalid component id specification")); + + if (idProp) { + QString idVal = idProp->values.first()->primitive(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION(obj, qApp->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, qApp->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, qApp->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) +{ + QString scriptCode; + QString sourceUrl; + int lineNumber = 1; + + if (script->properties.count() == 1 && + script->properties.begin().key() == QByteArray("source")) { + + Property *source = *script->properties.begin(); + if (script->defaultProperty) + COMPILE_EXCEPTION(source, qApp->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.isString()) + COMPILE_EXCEPTION(source, qApp->translate("QmlCompiler","Invalid Script source value")); + + sourceUrl = output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); + + 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; + } + } + + } else if (!script->properties.isEmpty()) { + COMPILE_EXCEPTION(*script->properties.begin(), qApp->translate("QmlCompiler","Properties cannot be set on Script block")); + } else if (script->defaultProperty) { + 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, qApp->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(QLatin1String("\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()) { + obj->scriptBlocks.append(scriptCode); + obj->scriptBlocksFile.append(sourceUrl); + obj->scriptBlocksLineNumber.append(lineNumber); + } + + return true; +} + +bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, + const BindingContext &ctxt) +{ + ComponentCompileState oldComponentCompileState = compileState; + compileState = ComponentCompileState(); + compileState.root = obj; + + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + + compileState = oldComponentCompileState; + + 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(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context + + if (obj->defaultProperty) + COMPILE_CHECK(buildProperty(obj->defaultProperty, obj, ctxt)); + + 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()); + + if (prop->isEmpty()) + COMPILE_EXCEPTION(prop, qApp->translate("QmlCompiler","Empty property assignment")); + + 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, qApp->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; + } + } + + 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, qApp->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, qApp->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, qApp->translate("QmlCompiler","Non-existant attached object")); + } + + if (!prop->value) + COMPILE_EXCEPTION(prop, qApp->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()) { + int t = p.type(); + + if (t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } + + 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(), qApp->translate("QmlCompiler","Cannot assign to non-existant default property")); + } else { + COMPILE_EXCEPTION(prop, qApp->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, qApp->translate("QmlCompiler","Invalid use of namespace")); + + foreach (Property *prop, nsProp->value->properties) { + + if (!isAttachedPropertyName(prop->name)) + COMPILE_EXCEPTION(prop, qApp->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, qApp->translate("QmlCompiler","Non-existant attached object")); + + if (!prop->value) + COMPILE_EXCEPTION(prop, qApp->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 = QmlMetaPropertyPrivate::saveValueType(valueTypeProperty->index, prop->index); + store.assignValueSource.owner = 1; + } else { + store.assignValueSource.property = + QmlMetaPropertyPrivate::saveProperty(prop->index); + store.assignValueSource.owner = 0; + } + QmlType *valueType = QmlMetaType::qmlType(v->object->metatype); + 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 = QmlMetaPropertyPrivate::saveValueType(valueTypeProperty->index, prop->index); + store.assignValueInterceptor.owner = 1; + } else { + store.assignValueInterceptor.property = + QmlMetaPropertyPrivate::saveProperty(prop->index); + store.assignValueInterceptor.owner = 0; + } + QmlType *valueType = QmlMetaType::qmlType(v->object->metatype); + 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, qApp->translate("QmlCompiler","Invalid use of id property")); + + QmlParser::Value *idValue = prop->values.at(0); + QString val = idValue->primitive(); + + if (!isValidId(val)) + COMPILE_EXCEPTION(prop, qApp->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, qApp->translate("QmlCompiler","id conflicts with type name")); + if (ns) + COMPILE_EXCEPTION(idValue, qApp->translate("QmlCompiler","id conflicts with namespace prefix")); + + if (compileState.ids.contains(val)) + COMPILE_EXCEPTION(prop, qApp->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); +} + +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->type < (int)QVariant::UserType) { + QmlEnginePrivate *ep = + static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine)); + if (ep->valueTypes[prop->type]) { + COMPILE_CHECK(buildValueTypeProperty(ep->valueTypes[prop->type], + prop->value, obj, ctxt.incr())); + obj->addValueTypeProperty(prop); + } else { + COMPILE_EXCEPTION(prop, qApp->translate("QmlCompiler","Invalid 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, qApp->translate("QmlCompiler","Cannot nest non-QObject property \"%1\"").arg(QString::fromUtf8(prop->name))); + + 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, qApp->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, qApp->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 || prop->values.count() != 1) + COMPILE_EXCEPTION(prop, qApp->translate("QmlCompiler","Invalid property use")); + + 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, qApp->translate("QmlCompiler","Invalid property use")); + } 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, qApp->translate("QmlCompiler","Cannot assign object to list")); + } + } + + } else { + COMPILE_EXCEPTION(v, qApp->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, qApp->translate("QmlCompiler","Cannot assign object to list")); + } + } + + } else if (v->value.isScript()) { + if (assignedBinding) + COMPILE_EXCEPTION(v, qApp->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, qApp->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), qApp->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), qApp->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 (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 = QmlMetaType::qmlType(v->object->metatype)) { + 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, qApp->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()) { + + 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; +} + +// 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(obj, qApp->translate("QmlCompiler","Duplicate default property")); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION(obj, qApp->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, qApp->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, qApp->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, qApp->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)); + + 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, qApp->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, qApp->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++; + } + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + QByteArray sig(s.name + "("); + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj) sig.append(","); + sig.append("QVariant"); + } + sig.append(")"); + QMetaMethodBuilder b = builder.addSlot(sig); + b.setParameterNames(s.parameterNames); + + ((QmlVMEMetaData *)dynamicData.data())->methodCount++; + QmlVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, s.body.length(), 0 }; + + dynamicData.append((char *)&methodData, sizeof(methodData)); + } + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + QmlVMEMetaData::MethodData *data = + ((QmlVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)s.body.constData(), + (s.body.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 <private/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, qApp->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, qApp->translate("QmlCompiler","Invalid alias location")); + + QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + if (!node) + COMPILE_EXCEPTION(obj, qApp->translate("QmlCompiler","No property alias location")); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() != 1 && alias.count() != 2) + COMPILE_EXCEPTION(prop.defaultValue, qApp->translate("QmlCompiler","Invalid alias location")); + + if (!compileState.ids.contains(alias.at(0))) + COMPILE_EXCEPTION(prop.defaultValue, qApp->translate("QmlCompiler","Invalid alias location")); + + Object *idObject = compileState.ids[alias.at(0)]; + + QByteArray typeName; + + int propIdx = -1; + bool writable = false; + if (alias.count() == 2) { + propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + + if (-1 == propIdx) + COMPILE_EXCEPTION(prop.defaultValue, qApp->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(); + typeName += "*"; + } + + data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); + data.append((const char *)&propIdx, sizeof(propIdx)); + + 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); + 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, qApp->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); + + QmlInstruction store; + + QmlBasicScript bs; + if (ref.isBasicScript) + bs.load(ref.compiledData.constData() + sizeof(quint32)); + + if (bs.isSingleIdFetch()) { + int idIndex = bs.singleIdFetchIndex(); + QmlParser::Object *idObj = compileState.idIndexes.value(idIndex); + if (canCoerce(prop->type, idObj)) { + store.type = QmlInstruction::StoreIdOptBinding; + store.assignIdOptBinding.id = idIndex; + store.assignIdOptBinding.property = prop->index; + output->bytecode << store; + return; + } + } else if (bs.isSingleContextProperty()) { + int propIndex = bs.singleContextPropertyIndex(); + + QMetaProperty p = + ref.bindingContext.object->metaObject()->property(propIndex); + if ((p.notifySignalIndex() != -1 || p.isConstant()) && + canCoerce(prop->type, p.userType())) { + + store.type = QmlInstruction::StoreObjPropBinding; + store.assignObjPropBinding.property = prop->index; + store.assignObjPropBinding.contextIdx = propIndex; + store.assignObjPropBinding.context = ref.bindingContext.stack; + store.assignObjPropBinding.notifyIdx = p.notifySignalIndex(); + + output->bytecode << store; + return; + } + } + + 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 = + QmlMetaPropertyPrivate::saveValueType(valueTypeProperty->index, + prop->index); + } else { + store.assignBinding.property = + QmlMetaPropertyPrivate::saveProperty(prop->index); + } + + 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; +} + +bool QmlCompiler::completeComponentBuild() +{ + for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { + Object *aliasObject = compileState.aliasingObjects.at(ii); + COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + } + + QmlBasicScript::Expression expr; + expr.component = compileState.root; + expr.ids = compileState.ids; + + for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { + BindingReference &binding = *iter; + + QmlBasicScript bs; + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; + + bs.compile(expr); + quint32 type; + if (bs.isValid()) { + binding.compiledData = + QByteArray(bs.compileData(), bs.compileDataSize()); + type = QmlExpressionPrivate::BasicScriptEngineData; + binding.isBasicScript = true; + } else { + type = QmlExpressionPrivate::PreTransformedQtScriptData; + + // Pre-rewrite the expression + QString expression = binding.expression.asScript(); + QmlRewrite::RewriteBinding rewriteBinding; + expression = rewriteBinding(expression); + + quint32 length = expression.length(); + quint32 pc = output->programs.length(); + output->programs.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)); + binding.isBasicScript = false; + } + binding.compiledData.prepend(QByteArray((const char *)&type, + sizeof(quint32))); + } + + saveComponentState(); + + return true; +} + +/*! + 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..8a9ca9c --- /dev/null +++ b/src/declarative/qml/qmlcompiler_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlerror.h> +#include <private/qmlinstruction_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <private/qmlparser_p.h> +#include <private/qmlengine_p.h> +#include <private/qbitfield_p.h> +#include <private/qmlpropertycache_p.h> +#include <private/qmlintegercache_p.h> +#include <private/qmltypenamecache_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlComponent; +class QmlContext; + +class QScriptProgram; +class QmlCompiledData : public QmlRefCount +{ +public: + QmlCompiledData(); + virtual ~QmlCompiledData(); + + QByteArray 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; + QList<QString> primitives; + QList<float> floatData; + QList<int> intData; + QList<CustomTypeData> customTypeData; + QList<QByteArray> datas; + QList<QmlParser::Location> locations; + QList<QmlInstruction> bytecode; + QList<QScriptProgram *> programs; + QList<QmlPropertyCache *> propertyCaches; + QList<QmlIntegerCache *> contextCaches; + + void dumpInstructions(); +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 &); +}; + +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); + 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 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 *); + + struct BindingReference { + QmlParser::Variant expression; + QmlParser::Property *property; + QmlParser::Value *value; + bool isBasicScript; + 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; + + QHash<QmlParser::Value *, BindingReference> bindings; + QList<QmlParser::Object *> aliasingObjects; + QmlParser::Object *root; + }; + ComponentCompileState compileState; + + void saveComponentState(); + ComponentCompileState componentState(QmlParser::Object *); + QHash<QmlParser::Object *, ComponentCompileState> savedCompileStates; + + QList<QmlError> exceptions; + QmlCompiledData *output; + QmlEngine *engine; + 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..12fb120 --- /dev/null +++ b/src/declarative/qml/qmlcomponent.cpp @@ -0,0 +1,682 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "qmlcompiler_p.h" +#include "private/qmlcontext_p.h" +#include "private/qmlcompositetypedata_p.h" +#include "private/qmlengine_p.h" +#include "qmlvme_p.h" +#include "qml.h" +#include <QStack> +#include <private/qfxperf_p.h> +#include <QStringList> +#include <qmlengine.h> +#include <QFileInfo> +#include "qmlbinding.h" +#include <QtCore/qdebug.h> +#include <QApplication> + +#include "qmlscriptparser_p.h" + +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 {components}{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: print("Completed Running!") + Rectangle { + Component.onCompleted: print("Nested Completed Running!") + } + } + \endqml +*/ +QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,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); + + 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->typeData) { + d->typeData->remWaiter(d); + d->typeData->release(); + } + if (d->cc) + d->cc->release(); + + for(int ii = 0; ii < d->bindValues.count(); ++ii) + QmlEnginePrivate::clear(d->bindValues[ii]); + for(int ii = 0; ii < d->parserStatus.count(); ++ii) + QmlEnginePrivate::clear(d->parserStatus[ii]); +} + +/*! + Returns 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->errors.isEmpty()) + return Error; + else if (d->engine && d->cc) + return Ready; + else + return Null; +} + +/*! + Returns true if the component is in the Null state, false otherwise. + + Equivalent to status() == QmlComponent::Null. +*/ +bool QmlComponent::isNull() const +{ + return status() == Null; +} + +/*! + Returns true if the component is in the Ready state, false otherwise. + + Equivalent to status() == QmlComponent::Ready. +*/ +bool QmlComponent::isReady() const +{ + return status() == Ready; +} + +/*! + Returns true if the component is in the Error state, false otherwise. + + Equivalent to status() == QmlComponent::Error. +*/ +bool QmlComponent::isError() const +{ + return status() == Error; +} + +/*! + Returns true if the component is in the Loading state, false otherwise. + + Equivalent to status() == QmlComponent::Loading. +*/ +bool QmlComponent::isLoading() const +{ + return status() == Loading; +} + +qreal QmlComponent::progress() const +{ + Q_D(const QmlComponent); + return d->progress; +} + +/*! + \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)); +} + +/*! + Create a QmlComponent from the given QML \a data and give it the + specified \a parent and \a engine. \a url is used to provide a base path + for items resolved by this component, and may be an empty url if the + component contains no items to resolve. + + \sa setData() +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QByteArray &data, const QUrl &url, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + setData(data,url); +} + +/*! + \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) { + + 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); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(this); + if (ddata) + return ddata->context; + else + return 0; +} + +/*! + 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) { + 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->errors; + else + return QList<QmlError>(); +} + +/*! + Return 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) +{ +} + + +/*! + 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 (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; + } + + if (!QmlEnginePrivate::get(engine)->rootComponent) + QmlEnginePrivate::get(engine)->rootComponent = q; + + 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(); + + QmlVME vme; + QObject *rv = vme.run(ctxt, cc, start, count, bindings); + + if (vme.isError()) + errors = vme.errors(); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + if (ep->rootComponent == q) { + ep->rootComponent = 0; + + bindValues = ep->bindValues; + parserStatus = ep->parserStatus; + componentAttacheds = ep->componentAttacheds; + if (componentAttacheds) + componentAttacheds->prev = &componentAttacheds; + + ep->componentAttacheds = 0; + ep->bindValues.clear(); + ep->parserStatus.clear(); + completePending = true; + } + + if (rv) { + QFx_setParent_noEvent(ctxt, rv); + } else { + delete ctxt; + } + + if (rv && !contextPriv->isInternal && ep->isDebugging) + contextPriv->instances.append(rv); + return rv; +} + +/*! + 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 (completePending) { + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindInit> bi; +#endif + for (int ii = 0; ii < bindValues.count(); ++ii) { + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv = + 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 < parserStatus.count(); ++ii) { + QmlEnginePrivate::SimpleList<QmlParserStatus> ps = + parserStatus.at(ii); + + for (int jj = 0; jj < ps.count; ++jj) { + QmlParserStatus *status = ps.at(jj); + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } + } + QmlEnginePrivate::clear(ps); + } + + while (componentAttacheds) { + QmlComponentAttached *a = componentAttacheds; + if (a->next) a->next->prev = &componentAttacheds; + componentAttacheds = a->next; + a->prev = 0; a->next = 0; + emit a->completed(); + } + + bindValues.clear(); + parserStatus.clear(); + completePending = false; + } +} + +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; +} + +QmlComponentAttached *QmlComponent::qmlAttachedProperties(QObject *obj) +{ + QmlComponentAttached *a = new QmlComponentAttached(obj); + + QmlEngine *engine = qmlEngine(obj); + if (!engine || !QmlEnginePrivate::get(engine)->rootComponent) + 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..a72aa4e --- /dev/null +++ b/src/declarative/qml/qmlcomponent.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENT_H +#define QMLCOMPONENT_H + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlerror.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) + +public: + QmlComponent(QObject *parent = 0); + QmlComponent(QmlEngine *, QObject *parent=0); + QmlComponent(QmlEngine *, const QString &url, QObject *parent = 0); + QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0); + QmlComponent(QmlEngine *, const QByteArray &data, + const QUrl &baseUrl, 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; + + qreal progress() const; + + QUrl url() const; + + virtual QObject *create(QmlContext *context = 0); + virtual QObject *beginCreate(QmlContext *); + virtual void completeCreate(); + + void loadUrl(const QUrl &url); + void setData(const QByteArray &, const QUrl &baseUrl); + + 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..7eedfbd --- /dev/null +++ b/src/declarative/qml/qmlcomponent_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> +#include <private/qobject_p.h> +#include <private/qmlengine_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <private/qbitfield_p.h> +#include <QtDeclarative/qmlerror.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qml.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), completePending(false), componentAttacheds(0), engine(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); + + QList<QmlError> errors; + QUrl url; + qreal progress; + + int start; + int count; + QmlCompiledData *cc; + + QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues; + QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; + QmlComponentAttached *componentAttacheds; + + bool completePending; + + QmlEngine *engine; + + 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; + +signals: + void completed(); + +private: + friend class QmlComponentPrivate; +}; + +QT_END_NAMESPACE + +#endif // QMLCOMPONENT_P_H diff --git a/src/declarative/qml/qmlcomponentjs.cpp b/src/declarative/qml/qmlcomponentjs.cpp new file mode 100644 index 0000000..df3e834 --- /dev/null +++ b/src/declarative/qml/qmlcomponentjs.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcomponentjs_p.h" +#include "qmlcomponentjs_p_p.h" +#include "qmlengine_p.h" +#include "qmlcomponent.h" + +QT_BEGIN_NAMESPACE + +QmlComponentJS::QmlComponentJS(QmlEngine *engine, QObject *parent) + : QmlComponent(*(new QmlComponentJSPrivate), parent) +{ + Q_D(QmlComponentJS); + d->engine = engine; + connect(this, SIGNAL(statusChanged(QmlComponent::Status)), + this, SLOT(statusChange(QmlComponent::Status))); +} + +QmlComponentJS::QmlComponentJS(QmlEngine *engine, const QUrl &url, QObject *parent) + : QmlComponent(*(new QmlComponentJSPrivate), parent) +{ + Q_D(QmlComponentJS); + d->engine = engine; + loadUrl(url); + connect(this, SIGNAL(statusChanged(QmlComponent::Status)), + this, SLOT(statusChange(QmlComponent::Status))); +} + +void QmlComponentJS::setContext(QmlContext* c) +{ + Q_D(QmlComponentJS); + d->ctxt =c; +} +/*! + Create a script object instance from this component. Returns a null + script object if creation failed. It will create the instance in the + same context that it was created it. QmlComponentJS is only + meant to be created from with script - C++ developers should just use + QmlComponent directly. + + Similar to QmlComponent::create(), but creates an object suitable + for usage within scripts. +*/ +QScriptValue QmlComponentJS::createObject() +{ + Q_D(QmlComponentJS); + QObject* ret = create(d->ctxt); + return QmlEnginePrivate::qmlScriptObject(ret, d->engine); +} + +/*! + Return the list of errors that occured during the last compile or create + operation, as a single string. An empty string is returned if isError() + is not set. + + This function is similar to errors(), except more useful when called from + QML. C++ code should usually use errors(). + + \sa errors() +*/ +QString QmlComponentJS::errorsString() const +{ + Q_D(const QmlComponentJS); + QString ret; + if(!isError()) + return ret; + foreach(const QmlError &e, d->errors) { + ret += e.url().toString() + QLatin1String(":") + + QString::number(e.line()) + QLatin1String(" ") + + e.description() + QLatin1String("\n"); + } + return ret; +} + + +void QmlComponentJS::statusChange(QmlComponent::Status newStatus) +{ + Q_D(QmlComponentJS); + if(newStatus == d->prevStatus) + return; + if(newStatus == QmlComponent::Null || d->prevStatus == QmlComponent::Null) + emit isNullChanged(); + if(newStatus == QmlComponent::Ready || d->prevStatus == QmlComponent::Ready) + emit isReadyChanged(); + if(newStatus == QmlComponent::Loading || d->prevStatus == QmlComponent::Loading) + emit isLoadingChanged(); + if(newStatus == QmlComponent::Error || d->prevStatus == QmlComponent::Error) + emit isErrorChanged(); + d->prevStatus = newStatus; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcomponentjs_p.h b/src/declarative/qml/qmlcomponentjs_p.h new file mode 100644 index 0000000..3213929 --- /dev/null +++ b/src/declarative/qml/qmlcomponentjs_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENTJS_P_H +#define QMLCOMPONENTJS_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/qstring.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qmlerror.h> + +QT_BEGIN_NAMESPACE + +class QmlComponentJSPrivate; +class QmlEngine; +class QmlContext; +class Q_DECLARATIVE_EXPORT QmlComponentJS : public QmlComponent +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlComponentJS) + Q_PROPERTY(bool isNull READ isNull NOTIFY isNullChanged) + Q_PROPERTY(bool isReady READ isReady NOTIFY isReadyChanged) + Q_PROPERTY(bool isError READ isError NOTIFY isErrorChanged) + Q_PROPERTY(bool isLoading READ isLoading NOTIFY isLoadingChanged) + friend class QmlEngine; +public: + QmlComponentJS(QmlEngine *, const QUrl &url, QObject *parent = 0); + QmlComponentJS(QmlEngine *, QObject *parent=0); + + Q_INVOKABLE QScriptValue createObject(); + Q_INVOKABLE QString errorsString() const; + + void setContext(QmlContext* c); +Q_SIGNALS: + void isNullChanged(); + void isErrorChanged(); + void isReadyChanged(); + void isLoadingChanged(); +private Q_SLOTS: + void statusChange(QmlComponent::Status newStatus); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlComponentJS) + +#endif // QMLCOMPONENTJS_P_H diff --git a/src/declarative/qml/qmlcomponentjs_p_p.h b/src/declarative/qml/qmlcomponentjs_p_p.h new file mode 100644 index 0000000..47ce491 --- /dev/null +++ b/src/declarative/qml/qmlcomponentjs_p_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENTJS_P_P_H +#define QMLCOMPONENTJS_P_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 "qmlcomponentjs_p.h" +#include "qmlcomponent_p.h" + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlComponentJSPrivate : public QmlComponentPrivate +{ + Q_DECLARE_PUBLIC(QmlComponentJS) +public: + QmlComponentJSPrivate() : QmlComponentPrivate(), + prevStatus(QmlComponentJS::Null), ctxt(0) + { } + + QmlComponent::Status prevStatus; + QmlContext* ctxt; +}; + +QT_END_NAMESPACE + +#endif // QMLCOMPONENTJS_P_P_H diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h new file mode 100644 index 0000000..fa11137 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypedata_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qglobal.h> +#include <private/qmlengine_p.h> + +QT_BEGIN_NAMESPACE + +class QmlCompositeTypeResource; +class QmlCompositeTypeData : public QmlRefCount +{ +public: + QmlCompositeTypeData(); + virtual ~QmlCompositeTypeData(); + + enum Status { + Invalid, + Complete, + Error, + Waiting + }; + 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..3c76344 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -0,0 +1,590 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qmlcompositetypedata_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <private/qmlscriptparser_p.h> +#include <QtDeclarative/qmlengine.h> +#include <QtNetwork/qnetworkreply.h> +#include <private/qmlengine_p.h> +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtDeclarative/qmlcomponent.h> +#include <private/qmlcomponent_p.h> +#include <private/qmlcompiler_p.h> + +QT_BEGIN_NAMESPACE + +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()->errors = errors; + } + + } + + return component; +} + +QmlCompiledData * +QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) +{ + if (status == Complete && !compiledComponent) { + + compiledComponent = new QmlCompiledData; + compiledComponent->url = imports.baseUrl(); + compiledComponent->name = compiledComponent->url.toString().toUtf8(); + + 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.toString()); + + if (!unit) { + unit = new QmlCompositeTypeData; + unit->status = QmlCompositeTypeData::Waiting; + unit->imports.setBaseUrl(url); + components.insert(url.toString(), 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().toString()); + 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().toString()); + 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().toString()); + 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(); + } else { + foreach (QmlScriptParser::Import imp, unit->data.imports()) { + int dot = imp.version.indexOf(QLatin1Char('.')); + if (dot < 0) dot = imp.version.length(); + if (!QmlEnginePrivate::get(engine)->addToImport(&unit->imports, imp.uri, imp.qualifier, imp.version.left(dot).toInt(), imp.version.mid(dot+1).toInt(), imp.type)) { + QmlError error; + error.setUrl(url); + error.setDescription(tr("Import %1 unavailable").arg(imp.uri)); + unit->errors << error; + ok = false; + } + } + } + + 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) + return; + + int waiting = 0; + 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++; + } + } + 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(QLatin1String("Resource ") + r->url + + QLatin1String(" unavailable")); + unit->errors << error; + doComplete(unit); + return; + } else if (r->status == QmlCompositeTypeData::Waiting) { + waiting++; + } + } + + if (!waiting) { + unit->status = QmlCompositeTypeData::Complete; + doComplete(unit); + } +} + +// ### Check ref counting in here +void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) +{ + QList<QmlScriptParser::TypeReference*> types = unit->data.referencedTypes(); + + int waiting = 0; + 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)) { + // XXX could produce error message here. + } + + if (typeNamespace) { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Namespace %1 cannot be used as 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; + } + + 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.toString()); + + if (!urlUnit) { + urlUnit = new QmlCompositeTypeData; + urlUnit->status = QmlCompositeTypeData::Waiting; + urlUnit->imports.setBaseUrl(url); + components.insert(url.toString(), 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; + + case QmlCompositeTypeData::Complete: + break; + + case QmlCompositeTypeData::Waiting: + unit->addref(); + ref.unit->dependants << unit; + waiting++; + break; + } + + unit->types << ref; + } + + QList<QUrl> resourceList = unit->data.referencedResources(); + for (int ii = 0; ii < resourceList.count(); ++ii) { + QUrl url = unit->imports.baseUrl().resolved(resourceList.at(ii)); + + QmlCompositeTypeResource *resource = resources.value(url.toString()); + + if (!resource) { + resource = new QmlCompositeTypeResource; + resource->status = QmlCompositeTypeResource::Waiting; + resource->url = url.toString(); + resources.insert(resource->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(QLatin1String("Resource ") + resource->url + + QLatin1String(" unavailable")); + 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) { + unit->status = QmlCompositeTypeData::Waiting; + } else { + unit->status = QmlCompositeTypeData::Complete; + doComplete(unit); + } +} + +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..843a9cf --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qglobal.h> +#include <private/qmlscriptparser_p.h> +#include <private/qmlrefcount_p.h> +#include <QtDeclarative/qmlerror.h> +#include <QtDeclarative/qmlengine.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 *); + + QmlEngine *engine; + typedef QHash<QString, QmlCompositeTypeData *> Components; + Components components; + typedef QHash<QString, 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..31d4e1f --- /dev/null +++ b/src/declarative/qml/qmlcontext.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmlcontext.h> +#include <private/qmlcontext_p.h> +#include <private/qmlexpression_p.h> +#include <private/qmlengine_p.h> +#include <qmlengine.h> +#include <qscriptengine.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qdebug.h> +#include <private/qmlbindingoptimizations_p.h> +#include <QtDeclarative/qmlinfo.h> + +// 6-bits +#define MAXIMUM_DEFAULT_OBJECTS 63 + +QT_BEGIN_NAMESPACE + +QmlContextPrivate::QmlContextPrivate() +: parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), + highPriorityCount(0), imports(0), expressions(0), idValues(0), idValueCount(0) +{ +} + +void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, + const QString &fileName, int lineNumber) +{ + Q_Q(QmlContext); + + if (!engine) + return; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(enginePriv->contextClass->newContext(q, scopeObject)); + + QScriptValue scope = scriptEngine->newObject(); + scriptContext->setActivationObject(scope); + + QScriptValue val = scriptEngine->evaluate(script, fileName, lineNumber); + + if (scriptEngine->hasUncaughtException()) + QmlExpressionPrivate::printException(scriptEngine); + + scriptEngine->popContext(); + + scripts.append(scope); +} + +void QmlContextPrivate::dump() +{ + dump(0); +} + +void QmlContextPrivate::dump(int depth) +{ + QByteArray ba(depth * 4, ' '); + if (parent) + parent->d_func()->dump(depth + 1); +} + +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) + guard->bindings->reset(); + + 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); +} + +void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) +{ + if (defaultObjects.count() >= (MAXIMUM_DEFAULT_OBJECTS - 1)) { + qWarning("QmlContext: Cannot have more than %d default objects on " + "one bind context.", MAXIMUM_DEFAULT_OBJECTS - 1); + return; + } + + if (priority == HighPriority) { + defaultObjects.insert(highPriorityCount++, object); + } else { + defaultObjects.append(object); + } +} + + +/*! + \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 + + Each context may have up to 32 default objects, and 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; + } + + for (int ii = 0; ii < d->contextObjects.count(); ++ii) { + QObjectPrivate *p = QObjectPrivate::get(d->contextObjects.at(ii)); + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(p->declarativeData); + if(data) + data->context = 0; + } + d->contextObjects.clear(); + + delete [] d->idValues; + + if (d->propertyNames) + d->propertyNames->release(); + + if (d->imports) + d->imports->release(); +} + +void QmlContextPrivate::invalidateEngines() +{ + if (!engine) + return; + engine = 0; + for (QSet<QmlContext *>::ConstIterator iter = childContexts.begin(); + iter != childContexts.end(); + ++iter) { + (*iter)->d_func()->invalidateEngines(); + } +} + +/*! + 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->addDefaultObject(defaultObject, QmlContextPrivate::NormalPriority); +} + +/*! + 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 (QmlMetaType::isObject(value.userType())) { + QObject *o = QmlMetaType::toQObject(value); + 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); + } else { + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } + } +} + +void QmlContextPrivate::setIdProperty(const QString &name, 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 \b 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)); + } else { + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +/*! + Resolves the URL \a src relative to the URL of the + containing component. + + \sa QmlEngine::baseUrl(), setBaseUrl() +*/ +QUrl QmlContext::resolvedUrl(const QUrl &src) +{ + 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); + } + 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 +{ + Q_D(const QmlContext); + 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..03baafa --- /dev/null +++ b/src/declarative/qml/qmlcontext.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 &); + + 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 QmlBasicScript; + 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..9a77e94 --- /dev/null +++ b/src/declarative/qml/qmlcontext_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qmlcontext.h> +#include <private/qobject_p.h> +#include <private/qmldeclarativedata_p.h> +#include <QtCore/qhash.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qset.h> +#include <private/qguard_p.h> +#include <private/qmlengine_p.h> +#include <private/qmlintegercache_p.h> +#include <private/qmltypenamecache_p.h> + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlExpression; +class QmlEngine; +class QmlExpression; +class QmlExpressionPrivate; +class QmlAbstractExpression; +class QmlBinding_Id; + +class 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 QString &script, QObject *scope, + const QString &fileName = QString(), int lineNumber = 1); + + QUrl url; + + QmlTypeNameCache *imports; + + void init(); + + void dump(); + void dump(int depth); + + enum Priority { + HighPriority, + NormalPriority + }; + void addDefaultObject(QObject *, Priority); + + void invalidateEngines(); + QSet<QmlContext *> childContexts; + + QmlAbstractExpression *expressions; + + QObjectList contextObjects; + + struct ContextGuard : public QGuard<QObject> + { + ContextGuard() : priv(0), bindings(0) {} + QmlContextPrivate *priv; + QmlBinding_Id *bindings; + ContextGuard &operator=(QObject *obj) { + (QGuard<QObject>&)*this = obj; return *this; + } + void objectDestroyed(QObject *) { priv->destroyed(this); } + }; + ContextGuard *idValues; + int idValueCount; + void setIdProperty(const QString &, int, QObject *); + void setIdPropertyData(QmlIntegerCache *); + void destroyed(ContextGuard *); + + static QmlContextPrivate *get(QmlContext *context) { + return static_cast<QmlContextPrivate *>(QObjectPrivate::get(context)); + } + + // Only used for debugging + QList<QPointer<QObject> > instances; +}; + +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..4df23f0 --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcontextscriptclass_p.h" +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> +#include <private/qmltypenamescriptclass_p.h> + +QT_BEGIN_NAMESPACE + +struct ContextData : public QScriptDeclarativeClass::Object { + ContextData(QmlContext *c, QObject *o) : context(c), scopeObject(o) {} + QGuard<QmlContext> context; + QGuard<QObject> scopeObject; +}; + +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(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)); +} + +QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + return data->context; +} + +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)->context.data(); + QObject *scopeObject = ((ContextData *)object)->scopeObject.data(); + 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); + if (rv) { + lastScopeObject = scopeObject; + lastContext = bindContext; + return rv; + } + } + + for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext); + + if (rv) { + lastDefaultObject = ii; + lastContext = bindContext; + return rv; + } + } + + return 0; +} + +QScriptValue 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); + + if (lastScopeObject) { + + return ep->objectClass->property(lastScopeObject, name); + + } else if (lastData) { + + if (lastData->type) + return ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->type); + else + return 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 rv; + } else if(lastDefaultObject != -1) { + + // Default object property + return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + + } else { + + return lastFunction; + + } +} + +void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, + const QScriptValue &value) +{ + 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..95dff5b --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtScript/qscriptclass.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmltypenamecache_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlContextScriptClass : public QScriptDeclarativeClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + QScriptValue newContext(QmlContext *, QObject * = 0); + + QmlContext *contextFromValue(const QScriptValue &); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual QScriptValue 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..dbcbeb1 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 an XML parser for + building a particular type. + + The subclass must implement compile() and create(), and define + itself in the meta type system with one of the macros: + + \code + QML_DEFINE_CUSTOM_PARSER(Name, parserClass) + \endcode + + \code + QML_DEFINE_CUSTOM_PARSER_NS("XmlNamespaceUri", Name, parserClass) + \endcode +*/ + +/* + \fn QByteArray QmlCustomParser::compile(QXmlStreamReader& reader) + + Upon entry to this function, \a reader is positioned on a + QXmlStreamReader::StartElement with the name specified when the + class was defined with the QML_DEFINE_CUSTOM_PARSER macro. + + The custom parser must consume tokens from \a reader until the + EndElement matching the initial start element is reached, or until + error. + + Errors must be reported via the error() functions. + + The returned QByteArray contains data meaningful only to the + custom parser; the type engine will pass this same data to + create() when making an instance of the data. + + 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 QVariant QmlCustomParser::create(const QByteArray &data) + + This function returns a QVariant containing the value represented + by \a data, which is a block of data previously returned by a call + to compile(). + + If the compile is for a type, the variant should be a pointer to + the correctly-named QObject subclass (i.e. the one defined by + QML_DEFINE_TYPE for the same-named type as this custom parser is + defined for). +*/ + +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..eb3e579 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qbytearray.h> +#include <QtCore/qxmlstream.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmlmetatype.h> +#include <QtDeclarative/qmlerror.h> +#include <private/qmlparser_p.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_FROM, VERSION_MAJ_TO, NAME, TYPE, CUSTOMTYPE) \ + static int defineCustomType##NAME = qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MAJ_TO, #NAME, #TYPE, new CUSTOMTYPE); +#else +# define QML_DEFINE_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MAJ_TO, NAME, TYPE, CUSTOMTYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *,(VERSION_MAJ), (VERSION_MIN_FROM), (VERSION_MAJ_TO)>::instance(qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN_FROM, VERSION_MAJ_TO, #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..25023d3 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser_p_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qglobal.h> +#include "qmlcustomparser_p.h" +#include "qmlparser_p.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..f6ecc3d --- /dev/null +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qobject_p.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_NAMESPACE + +class QmlCompiledData; +class QmlAbstractBinding; +class QmlContext; +class QmlPropertyCache; +class QmlDeclarativeData : public QDeclarativeData +{ +public: + QmlDeclarativeData(QmlContext *context = 0); + + virtual void destroyed(QObject *); + + QmlContext *context; + QmlAbstractBinding *bindings; + + 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; + + static QmlDeclarativeData *get(const QObject *object, bool create = false) { + QObjectPrivate *priv = + QObjectPrivate::get(const_cast<QObject *>(object)); + if (priv && priv->declarativeData) { + return static_cast<QmlDeclarativeData *>(priv->declarativeData); + } else if (create && priv) { + priv->declarativeData = new QmlDeclarativeData; + return static_cast<QmlDeclarativeData *>(priv->declarativeData); + } else { + return 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..a0601d7 --- /dev/null +++ b/src/declarative/qml/qmldom.cpp @@ -0,0 +1,1770 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmldom.h" +#include "qmldom_p.h" +#include "private/qmlcompositetypedata_p.h" +#include "private/qmlcompiler_p.h" +#include "private/qmlengine_p.h" +#include <QtCore/QByteArray> +#include <QtCore/QDebug> +#include <QtCore/QString> +#include "qmlscriptparser_p.h" + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP) + +QmlDomDocumentPrivate::QmlDomDocumentPrivate() +: root(0) +{ +} + +QmlDomDocumentPrivate::QmlDomDocumentPrivate(const QmlDomDocumentPrivate &other) +: QSharedData(other), root(0) +{ + root = other.root; + if (root) root->addref(); +} + +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::loadError() 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; + 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) { + 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()) { + if (compilerDump()) { + qWarning() << "-AST------------------------------------------------------------------------------"; + td->data.tree()->dump(); + qWarning() << "----------------------------------------------------------------------------------"; + } + 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 QFxItem 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(const QmlDomPropertyPrivate &other) +: QSharedData(other), property(0) +{ + property = other.property; + if (property) property->addref(); +} + +QmlDomPropertyPrivate::~QmlDomPropertyPrivate() +{ + if (property) property->release(); +} + +QmlDomDynamicPropertyPrivate::QmlDomDynamicPropertyPrivate(): + valid(false) +{ +} + +QmlDomDynamicPropertyPrivate::QmlDomDynamicPropertyPrivate(const QmlDomDynamicPropertyPrivate &other) +: QSharedData(other), valid(other.valid) +{ + property = other.property; + if (valid && property.defaultValue) property.defaultValue->addref(); +} + +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; +} + +/*! + 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(); +} + +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("QDateTime"); + + 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; +} + +/*! + 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->property->addref(); + } + + return rp; +} + +/*! + 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), isVirtualComponent(false) +{ +} + +QmlDomObjectPrivate::QmlDomObjectPrivate(const QmlDomObjectPrivate &other) +: QSharedData(other), object(0), isVirtualComponent(false) +{ + object = other.object; + if (object) object->addref(); + isVirtualComponent = other.isVirtualComponent; +} + +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) +{ +} + +/*! + Construct a new QmlDomObject with the specified \a objectType. +*/ +QmlDomObject::QmlDomObject(const QByteArray &objectType) +: d(new QmlDomObjectPrivate) +{ + Q_UNUSED(objectType); + qWarning("QmlDomObject::QmlDomObject(const QByteArray &): Not implemented"); +} + +/*! + 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) + 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; + + 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->isVirtualComponent || + (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(const QmlDomBasicValuePrivate &other) +: QSharedData(other), value(0) +{ + value = other.value; + if (value) value->addref(); +} + +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; +} + + +QmlDomValuePrivate::QmlDomValuePrivate() +: property(0), value(0) +{ +} + +QmlDomValuePrivate::QmlDomValuePrivate(const QmlDomValuePrivate &other) +: QSharedData(other), property(0), value(0) +{ + property = other.property; + value = other.value; + if (property) property->addref(); + if (value) value->addref(); +} + +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 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::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 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 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->isVirtualComponent) { + rv.d->object = d->object; + rv.d->object->addref(); + } else 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(const QmlDomImportPrivate &other) +: QSharedData(other) +{ +} + +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..f344bb2 --- /dev/null +++ b/src/declarative/qml/qmldom.h @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDOM_H +#define QMLDOM_H + +#include <QtCore/qlist.h> +#include <QtCore/qshareddata.h> +#include <QtDeclarative/qmlerror.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 &); + + 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; + + bool isDefaultProperty() const; + + QmlDomProperty defaultValue() 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 QByteArray &); + 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; + 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 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, + 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 isObject() const; + bool isList() const; + + QmlDomValueLiteral toLiteral() const; + QmlDomValueBinding toBinding() const; + QmlDomValueValueSource toValueSource() 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..b15844a --- /dev/null +++ b/src/declarative/qml/qmldom_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QtGlobal> +#include "qmlparser_p.h" + +QT_BEGIN_NAMESPACE + +class QmlDomDocumentPrivate : public QSharedData +{ +public: + QmlDomDocumentPrivate(); + QmlDomDocumentPrivate(const QmlDomDocumentPrivate &); + ~QmlDomDocumentPrivate(); + + QList<QmlError> errors; + QList<QmlDomImport> imports; + QmlParser::Object *root; + QList<int> automaticSemicolonOffsets; +}; + +class QmlDomObjectPrivate : public QSharedData +{ +public: + QmlDomObjectPrivate(); + QmlDomObjectPrivate(const QmlDomObjectPrivate &); + ~QmlDomObjectPrivate(); + + typedef QList<QPair<QmlParser::Property *, QByteArray> > Properties; + Properties properties() const; + Properties properties(QmlParser::Property *) const; + + QmlParser::Object *object; + bool isVirtualComponent; +}; + +class QmlDomPropertyPrivate : public QSharedData +{ +public: + QmlDomPropertyPrivate(); + QmlDomPropertyPrivate(const QmlDomPropertyPrivate &); + ~QmlDomPropertyPrivate(); + + QByteArray propertyName; + QmlParser::Property *property; +}; + +class QmlDomDynamicPropertyPrivate : public QSharedData +{ +public: + QmlDomDynamicPropertyPrivate(); + QmlDomDynamicPropertyPrivate(const QmlDomDynamicPropertyPrivate &); + ~QmlDomDynamicPropertyPrivate(); + + bool valid; + QmlParser::Object::DynamicProperty property; +}; + +class QmlDomValuePrivate : public QSharedData +{ +public: + QmlDomValuePrivate(); + QmlDomValuePrivate(const QmlDomValuePrivate &); + ~QmlDomValuePrivate(); + + QmlParser::Property *property; + QmlParser::Value *value; +}; + +class QmlDomBasicValuePrivate : public QSharedData +{ +public: + QmlDomBasicValuePrivate(); + QmlDomBasicValuePrivate(const QmlDomBasicValuePrivate &); + ~QmlDomBasicValuePrivate(); + + QmlParser::Value *value; +}; + +class QmlDomImportPrivate : public QSharedData +{ +public: + QmlDomImportPrivate(); + QmlDomImportPrivate(const QmlDomImportPrivate &); + ~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..4f3b2ba --- /dev/null +++ b/src/declarative/qml/qmlengine.cpp @@ -0,0 +1,1510 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#undef QT3_SUPPORT // don't want it here - it just causes bugs (which is why we removed it) + +#include <QtCore/qmetaobject.h> +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> +#include <private/qobject_p.h> +#include <private/qmlcompiler_p.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlglobalscriptclass_p.h> + +#ifdef QT_SCRIPTTOOLS_LIB +#include <QScriptEngineDebugger> +#endif + +#include <QScriptClass> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QNetworkAccessManager> +#include <QDesktopServices> +#include <QTimer> +#include <QList> +#include <QPair> +#include <QDebug> +#include <QMetaObject> +#include "qml.h" +#include <private/qfxperf_p.h> +#include <QStack> +#include "private/qmlbasicscript_p.h" +#include "qmlengine.h" +#include "qmlcontext.h" +#include "qmlexpression.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 <qmlcomponent.h> +#include <private/qmlcomponentjs_p.h> +#include <private/qmlmetaproperty_p.h> +#include <private/qmlbinding_p.h> +#include <private/qmlvme_p.h> +#include <private/qmlenginedebug_p.h> +#include <private/qmlstringconverters_p.h> +#include <private/qmlxmlhttprequest_p.h> +#include <private/qmlsqldatabase_p.h> +#include <private/qmltypenamescriptclass_p.h> +#include <private/qmllistscriptclass_p.h> +#include <QtDeclarative/qmlscriptstring.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(qmlDebugger, QML_DEBUGGER) +DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) + +QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Object,QObject) + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + +QScriptValue desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e) +{ + if(!ctxt->argumentCount()) + return e->newVariant(QVariant(false)); + bool ret = QDesktopServices::openUrl(QUrl(ctxt->argument(0).toString())); + return e->newVariant(QVariant(ret)); +} + +static QString userLocalDataPath(const QString& app) +{ + return QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/") + app; +} + +QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) +: rootContext(0), currentExpression(0), + isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0), + nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), cleanup(0), scriptEngine(this), + componentAttacheds(0), rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) +{ + QScriptValue qtObject = + scriptEngine.newQMetaObject(StaticQtMetaObject::get()); + QScriptValue desktopObject = scriptEngine.newObject(); + desktopObject.setProperty(QLatin1String("openUrl"),scriptEngine.newFunction(desktopOpenUrl, 1)); + qtObject.setProperty(QLatin1String("DesktopServices"), desktopObject); + scriptEngine.globalObject().setProperty(QLatin1String("Qt"), qtObject); + + offlineStoragePath = userLocalDataPath(QLatin1String("QML/OfflineStorage")); + qt_add_qmlxmlhttprequest(&scriptEngine); + qt_add_qmlsqldatabase(&scriptEngine); + + //types + qtObject.setProperty(QLatin1String("rgba"), scriptEngine.newFunction(QmlEnginePrivate::rgba, 4)); + qtObject.setProperty(QLatin1String("hsla"), scriptEngine.newFunction(QmlEnginePrivate::hsla, 4)); + qtObject.setProperty(QLatin1String("rect"), scriptEngine.newFunction(QmlEnginePrivate::rect, 4)); + qtObject.setProperty(QLatin1String("point"), scriptEngine.newFunction(QmlEnginePrivate::point, 2)); + qtObject.setProperty(QLatin1String("size"), scriptEngine.newFunction(QmlEnginePrivate::size, 2)); + qtObject.setProperty(QLatin1String("vector3d"), scriptEngine.newFunction(QmlEnginePrivate::vector, 3)); + + //color helpers + qtObject.setProperty(QLatin1String("lighter"), scriptEngine.newFunction(QmlEnginePrivate::lighter, 1)); + qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); + qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + + //misc methods + qtObject.setProperty(QLatin1String("playSound"), scriptEngine.newFunction(QmlEnginePrivate::playSound, 1)); + + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), + scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); + + globalClass = new QmlGlobalScriptClass(&scriptEngine); +} + +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 networkAccessManager; + networkAccessManager = 0; + delete nodeListClass; + nodeListClass = 0; + delete namedNodeMapClass; + namedNodeMapClass = 0; + delete sqlQueryClass; + sqlQueryClass = 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"); + + scriptEngine.installTranslatorFunctions(); + 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); +#ifdef QT_SCRIPTTOOLS_LIB + if (qmlDebugger()){ + debugger = new QScriptEngineDebugger(q); + debugger->attachTo(&scriptEngine); + } +#endif + + if (QCoreApplication::instance()->thread() == q->thread() && + QmlEngineDebugServer::isDebuggingEnabled()) { + qmlEngineDebugServer(); + isDebugging = true; + QmlEngineDebugServer::addEngine(q); + + qmlEngineDebugServer()->waitForClients(); + } +} + +QmlEnginePrivate::CapturedProperty::CapturedProperty(const QmlMetaProperty &p) +: object(p.object()), coreIndex(p.coreIndex()), notifyIndex(p.property().notifySignalIndex()) +{ +} + +/*! + \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, "Text { text: \"Hello world!\" }"); + QFxItem *item = qobject_cast<QFxItem *>(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 common QNetworkAccessManager, \a network, used by all QML elements + instantiated by this engine. + + Any previously set manager is deleted and \a network is owned by the + QmlEngine. This method should only be called before any QmlComponents are + instantiated. +*/ +void QmlEngine::setNetworkAccessManager(QNetworkAccessManager *network) +{ + Q_D(QmlEngine); + delete d->networkAccessManager; + d->networkAccessManager = network; +} + +/*! + Returns the common QNetworkAccessManager used by all QML elements + instantiated by this engine. + + The default implements no caching, cookiejar, etc., just a default + QNetworkAccessManager. +*/ +QNetworkAccessManager *QmlEngine::networkAccessManager() const +{ + Q_D(const QmlEngine); + if (!d->networkAccessManager) + d->networkAccessManager = new QNetworkAccessManager; + return d->networkAccessManager; +} + +/*! + 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) +{ + QObjectPrivate *priv = QObjectPrivate::get(object); + + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(priv->declarativeData); + + if (data && data->context) { + qWarning("QmlEngine::setContextForObject(): Object already has a QmlContext"); + return; + } + + if (!data) { + priv->declarativeData = new QmlDeclarativeData(context); + } else { + data->context = context; + } + + context->d_func()->contextObjects.append(object); +} + +void qmlExecuteDeferred(QObject *object) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object); + + if (data && data->deferredComponent) { + QmlVME vme; + vme.runDeferred(object); + + data->deferredComponent->release(); + data->deferredComponent = 0; + } +} + +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); + + 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; +} + +QmlDeclarativeData::QmlDeclarativeData(QmlContext *ctxt) +: context(ctxt), bindings(0), bindingBitsSize(0), bindingBits(0), + outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), + deferredIdx(0), attachedProperties(0), propertyCache(0) +{ +} + +void QmlDeclarativeData::destroyed(QObject *object) +{ + if (deferredComponent) + deferredComponent->release(); + if (attachedProperties) + delete attachedProperties; + if (context) + static_cast<QmlContextPrivate *>(QObjectPrivate::get(context))->contextObjects.removeAll(object); + + QmlAbstractBinding *binding = bindings; + while (binding) { + QmlAbstractBinding *next = binding->m_nextBinding; + binding->m_prevBinding = 0; + binding->m_nextBinding = 0; + delete binding; + binding = next; + } + + if (bindingBits) + free(bindingBits); + + if (propertyCache) + propertyCache->release(); + + 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); +} + +/*! + This function is intended for use inside QML only. In C++ just create a + component object as usual. + + This function takes the URL of a QML file as its only argument. It returns + a component object which can be used to create and load that QML file. + + Example QmlJS is below, remember that QML files that might be loaded + over the network cannot be expected to be ready immediately. + \code + var component; + var sprite; + function finishCreation(){ + if(component.isReady()){ + sprite = component.createObject(); + if(sprite == 0){ + // Error Handling + }else{ + sprite.parent = page; + sprite.x = 200; + //... + } + }else if(component.isError()){ + // Error Handling + } + } + + component = createComponent("Sprite.qml"); + if(component.isReady()){ + finishCreation(); + }else{ + component.statusChanged.connect(finishCreation); + } + \endcode + + If you are certain the files will be local, you could simplify to + + \code + component = createComponent("Sprite.qml"); + sprite = component.createObject(); + if(sprite == 0){ + // Error Handling + print(component.errorsString()); + }else{ + sprite.parent = page; + sprite.x = 200; + //... + } + \endcode + + If you want to just create an arbitrary string of QML, instead of + loading a qml file, consider the createQmlObject() function. +*/ +QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, + QScriptEngine *engine) +{ + QmlComponentJS* c; + + QmlEnginePrivate *activeEnginePriv = + static_cast<QmlScriptEngine*>(engine)->p; + QmlEngine* activeEngine = activeEnginePriv->q_func(); + + QmlContext* context = activeEnginePriv->getContext(ctxt); + if(ctxt->argumentCount() != 1) { + c = new QmlComponentJS(activeEngine); + }else{ + QUrl url = QUrl(context->resolvedUrl(ctxt->argument(0).toString())); + if(!url.isValid()) + url = QUrl(ctxt->argument(0).toString()); + c = new QmlComponentJS(activeEngine, url, activeEngine); + } + c->setContext(context); + return engine->newQObject(c); +} + +/*! + Creates a new object from the specified string of QML. It requires a + second argument, which is the id of an existing QML object to use as + the new object's parent. If a third argument is provided, this is used + as the filepath that the qml came from. + + Example (where targetItem is the id of an existing QML item): + \code + newObject = createQmlObject('import Qt 4.6; Rectangle {color: "red"; width: 20; height: 20}', + targetItem, "dynamicSnippet1"); + \endcode + + This function is intended for use inside QML only. It is intended to behave + similarly to eval, but for creating QML elements. + + Returns the created object, or null if there is an error. In the case of an + error, details of the error are output using qWarning(). + + Note that this function returns immediately, and therefore may not work if + the QML loads new components. If you are trying to load a new component, + for example from a QML file, consider the createComponent() function + instead. 'New components' refers to external QML files that have not yet + been loaded, and so it is safe to use createQmlObject to load built-in + components. +*/ +QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine) +{ + QmlEnginePrivate *activeEnginePriv = + static_cast<QmlScriptEngine*>(engine)->p; + QmlEngine* activeEngine = activeEnginePriv->q_func(); + + if(ctxt->argumentCount() < 2) + return engine->nullValue(); + + QString qml = ctxt->argument(0).toString(); + QUrl url; + if(ctxt->argumentCount() > 2) + url = QUrl(ctxt->argument(2).toString()); + else + url = QUrl(QLatin1String("DynamicQML")); + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); + QmlContext *qmlCtxt = qmlContext(parentArg); + if (url.isEmpty()) { + url = qmlCtxt->resolvedUrl(QUrl(QLatin1String("<Unknown File>"))); + } else { + url = qmlCtxt->resolvedUrl(url); + } + + QmlComponent component(activeEngine, qml.toUtf8(), url); + if(component.isError()) { + QList<QmlError> errors = component.errors(); + qWarning() <<"QmlEngine::createQmlObject():"; + foreach (const QmlError &error, errors) + qWarning() << " " << error; + + return engine->nullValue(); + } + + QObject *obj = component.create(qmlCtxt); + + if(component.isError()) { + QList<QmlError> errors = component.errors(); + qWarning() <<"QmlEngine::createQmlObject():"; + foreach (const QmlError &error, errors) + qWarning() << " " << error; + + return engine->nullValue(); + } + + if(obj) { + obj->setParent(parentArg); + obj->setProperty("parent", QVariant::fromValue<QObject*>(parentArg)); + return qmlScriptObject(obj, activeEngine); + } + return engine->nullValue(); +} + +/*! + This function is intended for use inside QML only. In C++ just create a + QVector3D as usual. + + This function takes three numeric components and combines them into a + QVector3D value that can be used with any property that takes a + QVector3D argument. The following QML code: + + \code + transform: Rotation { + id: rotation + origin.x: Container.width / 2; + axis: vector(0, 1, 1) + } + \endcode + + is equivalent to: + + \code + transform: Rotation { + id: rotation + origin.x: Container.width / 2; + axis.x: 0; axis.y: 1; axis.z: 0 + } + \endcode +*/ +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) + 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; + return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromRgbF(r, g, b, a))); +} + +QScriptValue QmlEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3) + 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; + 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(); + 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.type() == QVariant::Color) + color = v.value<QColor>(); + else if (v.type() == 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.type() == QVariant::Color) + color = v.value<QColor>(); + else if (v.type() == 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(); +} + +/*! + This function allows tinting one color with another. + + The tint color should usually be mostly transparent, or you will not be able to see the underlying color. The below example provides a slight red tint by having the tint color be pure red which is only 1/16th opaque. + + \qml + Rectangle { x: 0; width: 80; height: 80; color: "lightsteelblue" } + Rectangle { x: 100; width: 80; height: 80; color: Qt.tint("lightsteelblue", "#10FF0000") } + \endqml + \image declarative-rect_tint.png + + Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color. +*/ +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.type() == QVariant::Color) + color = v.value<QColor>(); + else if (v.type() == 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.type() == QVariant::Color) + tintColor = v.value<QColor>(); + else if (v.type() == 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(); + + QScriptClass *sc = val.scriptClass(); + if (!sc) { + return val.toVariant(); + } else if (sc == valueTypeClass) { + return valueTypeClass->toVariant(val); + } else { + return QVariant(); + } +} + +QmlScriptClass::QmlScriptClass(QmlEngine *bindengine) +: QScriptClass(QmlEnginePrivate::getScriptEngine(bindengine)), + engine(bindengine) +{ +} + +QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) +{ + QmlEnginePrivate *ep = + static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine)); + + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == ep->objectClass) + return QVariant::fromValue(ep->objectClass->toQObject(val)); + else if (dc == ep->contextClass) + return QVariant(); + + QScriptClass *sc = val.scriptClass(); + if (!sc) { + return val.toVariant(); + } else if (sc == ep->valueTypeClass) { + return ep->valueTypeClass->toVariant(val); + } + + return QVariant(); +} + +// 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 urls; + QList<int> majversions; + QList<int> minversions; + QList<bool> isLibrary; + QList<bool> isBuiltin; + + 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 = urls.at(i).toUtf8(); + qt += "/"; + qt += type; + QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin); + if (vmajor) *vmajor = vmaj; + if (vminor) *vminor = vmin; + if (t) { + if (type_return) + *type_return = t; + return true; + } + } else { + QUrl url = QUrl(urls.at(i) + QLatin1String("/") + QString::fromUtf8(type) + QLatin1String(".qml")); + if (vmaj || vmin) { + // Check version file - XXX cache these in QmlEngine! + QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); + if (qmldir.open(QIODevice::ReadOnly)) { + do { + QByteArray lineba = qmldir.readLine(); + if (lineba.at(0) == '#') + continue; + int space1 = lineba.indexOf(' '); + if (qstrncmp(lineba,type,space1)==0) { + // eg. 1.2-5 + QString line = QString::fromUtf8(lineba); + space1 = line.indexOf(QLatin1Char(' ')); // refind in Unicode + int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; + QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-2:space2-space1-1); + int dot = mapversions.indexOf(QLatin1Char('.')); + int dash = mapversions.indexOf(QLatin1Char('-')); + int mapvmaj = mapversions.left(dot).toInt(); + if (mapvmaj==vmaj) { + int mapvmin_from = (dash <= 0 ? mapversions.mid(dot+1) : mapversions.mid(dot+1,dash-dot-1)).toInt(); + int mapvmin_to = dash <= 0 ? mapvmin_from : mapversions.mid(dash+1).toInt(); + if (vmin >= mapvmin_from && vmin <= mapvmin_to) { + QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-2); + if (url_return) + *url_return = url.resolved(mapfile.toString()); + return true; + } + } + } + } while (!qmldir.atEnd()); + } + } 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; + } +}; + +class QmlImportsPrivate { +public: + QmlImportsPrivate() : ref(1) + { + } + + ~QmlImportsPrivate() + { + foreach (QmlEnginePrivate::ImportedNamespace* s, set.values()) + delete s; + } + + bool add(const QUrl& base, 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; + } + } else { + url = base.resolved(QUrl(url)).toString(); + } + s->urls.prepend(url); + s->majversions.prepend(vmaj); + s->minversions.prepend(vmin); + s->isLibrary.prepend(importType == QmlScriptParser::Import::Library); + s->isBuiltin.prepend(isbuiltin); + 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) { + while (!s) { + s = set.value(QString::fromUtf8(type.left(slash))); + int nslash = type.indexOf('/',slash+1); + if (nslash > 0) + slash = nslash; + else + break; + } + } 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]+QLatin1String("/")).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 class 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 <QtDeclarative/qmlmetatype.h> +#include <private/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.urls.count(); ++ii) { + if (!set.isBuiltin.at(ii)) + continue; + + QByteArray base = set.urls.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->majorVersion() == major && type->minMinorVersion() <= minor && + type->maxMinorVersion() >= 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. +*/ +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. + + QFxWebView and the SQL databases created with openDatabase() + are stored here. + + The default is QML/OfflineStorage/ in the platform-standard + user application data directory. +*/ +void QmlEngine::setOfflineStoragePath(const QString& dir) +{ + Q_D(QmlEngine); + d->offlineStoragePath = dir; +} + +QString QmlEngine::offlineStoragePath() const +{ + Q_D(const QmlEngine); + return d->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& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const +{ + bool ok = imports->d->add(imports->d->base,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); +} + +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..b4233e4 --- /dev/null +++ b/src/declarative/qml/qmlengine.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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 setNetworkAccessManager(QNetworkAccessManager *); + 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 *); + +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..29621c0 --- /dev/null +++ b/src/declarative/qml/qmlengine_p.h @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <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 <private/qobject_p.h> +#include <private/qmlclassfactory_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <private/qpodvector_p.h> +#include <QtDeclarative/qml.h> +#include <private/qmlbasicscript_p.h> +#include <private/qmlvaluetype_p.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlexpression.h> +#include <QtScript/qscriptengine.h> +#include <private/qmlmetaproperty_p.h> +#include <private/qmlpropertycache_p.h> +#include <private/qmlobjectscriptclass_p.h> +#include <private/qmlcontextscriptclass_p.h> +#include <private/qmlvaluetypescriptclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlEngine; +class QmlContextPrivate; +class QmlExpression; +class QmlBasicScriptNodeCache; +class QmlContextScriptClass; +class QmlObjectScriptClass; +class QmlTypeNameScriptClass; +class QmlValueTypeScriptClass; +class QScriptEngineDebugger; +class QNetworkReply; +class QNetworkAccessManager; +class QmlAbstractBinding; +class QScriptDeclarativeClass; +class QmlTypeNameScriptClass; +class QmlTypeNameCache; +class QmlComponentAttached; +class QmlListScriptClass; +class QmlCleanup; + +class 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) {} + CapturedProperty(const QmlMetaProperty &); + + QObject *object; + int coreIndex; + int notifyIndex; + }; + QPODVector<CapturedProperty> capturedProperties; + + QmlContext *rootContext; + QmlExpression *currentExpression; + bool isDebugging; +#ifdef QT_SCRIPTTOOLS_LIB + QScriptEngineDebugger *debugger; +#endif + + struct ImportedNamespace; + QmlContextScriptClass *contextClass; + QmlObjectScriptClass *objectClass; + QmlValueTypeScriptClass *valueTypeClass; + QmlTypeNameScriptClass *typeNameClass; + QmlListScriptClass *listClass; + // Global script class + QScriptClass *globalClass; + // Used by DOM Core 3 API + QScriptClass *nodeListClass; + QScriptClass *namedNodeMapClass; + // Used by SQL database API + QScriptClass *sqlQueryClass; + + // Registered cleanup handlers + QmlCleanup *cleanup; + + struct QmlScriptEngine : public QScriptEngine + { + QmlScriptEngine(QmlEnginePrivate *priv) + : p(priv) {} + QmlEnginePrivate *p; + }; + QmlScriptEngine scriptEngine; + + 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; + + QmlComponent *rootComponent; + mutable QNetworkAccessManager *networkAccessManager; + + 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& 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; + 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 &); + + 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 playSound(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; } + QmlContext *getContext(QScriptContext *); +}; + + +class QmlScriptClass : public QScriptClass +{ +public: + QmlScriptClass(QmlEngine *); + + static QVariant toVariant(QmlEngine *, const QScriptValue &); +protected: + QmlEngine *engine; +}; + +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..7178e6c --- /dev/null +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlenginedebug_p.h" +#include "qmlboundsignal_p.h" +#include <QtCore/qdebug.h> +#include <QtCore/qmetaobject.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlmetatype.h> +#include <qmlmetaproperty.h> +#include <qmlbinding.h> +#include "qmlcontext_p.h" +#include "qmlwatcher_p.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,QByteArray,QVariant)), + this, SLOT(propertyChanged(int,int,QByteArray,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 = prop.name(); + rv.hasNotifySignal = prop.hasNotifySignal(); + QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding(); + if (binding) + rv.binding = binding->expression(); + + if (prop.type() < QVariant::UserType) { + rv.type = QmlObjectProperty::Basic; + rv.value = prop.read(obj); + } 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; +} + +void QmlEngineDebugServer::buildObjectDump(QDataStream &message, + QObject *object, bool recur) +{ + message << objectData(object); + message << object->metaObject()->propertyCount(); + + for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) + message << propertyData(object, ii); + + QObjectList children = object->children(); + message << children.count() << recur; + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + if (recur) + buildObjectDump(message, child, recur); + else + message << objectData(child); + } +} + +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)); + } +} + +QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) +{ + if (value.type() < QVariant::UserType) + return value; + + if (!value.toString().isEmpty()) + return value.toString(); + + QVariant v; + if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { + QObject *o = QmlMetaType::toQObject(value); + if (o) { + QString objectName = o->objectName(); + if (objectName.isEmpty()) + objectName = QLatin1String("<unnamed>"); + v = QString::fromUtf8(o->metaObject()->className()) + + QLatin1String(": ") + objectName; + } + } + + if (v.isNull()) + v = QString::fromUtf8(value.typeName()); + + return v; +} + +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.objectType = object->metaObject()->className(); + rv.objectId = QmlDebugService::idForObject(object); + rv.contextId = QmlDebugService::idForObject(qmlContext(object)); + + 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 << objectId << 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 = serializableVariant(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 QByteArray &property, const QVariant &value) +{ + QByteArray reply; + QVariant v = serializableVariant(value); + QDataStream rs(&reply, QIODevice::WriteOnly); + + rs << QByteArray("UPDATE_WATCH") << id << objectId << property << v; + + 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..075a711 --- /dev/null +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qmldebugservice.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 }; + 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 QByteArray &property, const QVariant &value); + +private: + void buildObjectList(QDataStream &, QmlContext *); + void buildObjectDump(QDataStream &, QObject *, bool); + QmlObjectData objectData(QObject *); + QmlObjectProperty propertyData(QObject *, int); + QVariant serializableVariant(const QVariant &value); + + 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..514fe44 --- /dev/null +++ b/src/declarative/qml/qmlerror.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(new QmlErrorPrivate) +{ +} + +/*! + Create a copy of \a other. +*/ +QmlError::QmlError(const QmlError &other) +: d(new QmlErrorPrivate) +{ + *this = other; +} + +/*! + Assign \a other to this error object. +*/ +QmlError &QmlError::operator=(const QmlError &other) +{ + 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 the url for the file that caused this error. +*/ +QUrl QmlError::url() const +{ + return d->url; +} + +/*! + Set the \a url for the file that caused this error. +*/ +void QmlError::setUrl(const QUrl &url) +{ + d->url = url; +} + +/*! + Return the error description. +*/ +QString QmlError::description() const +{ + return d->description; +} + +/*! + Set the error \a description. +*/ +void QmlError::setDescription(const QString &description) +{ + d->description = description; +} + +/*! + Return the error line number. +*/ +int QmlError::line() const +{ + return d->line; +} + +/*! + Set the error \a line number. +*/ +void QmlError::setLine(int line) +{ + d->line = line; +} + +/*! + Return the error column number. +*/ +int QmlError::column() const +{ + return d->column; +} + +/*! + Set the error \a column number. +*/ +void QmlError::setColumn(int column) +{ + d->column = column; +} + +/*! + Return the error as a human readable string. +*/ +QString QmlError::toString() const +{ + QString rv; + rv = url().toString() + QLatin1String(":") + QString::number(line()); + if(column() != -1) + rv += QLatin1String(":") + 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..c1a8720 --- /dev/null +++ b/src/declarative/qml/qmlerror.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(); + + 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..3f531a3 --- /dev/null +++ b/src/declarative/qml/qmlexpression.cpp @@ -0,0 +1,686 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 "QtCore/qdebug.h" +#include "qmlcompiler_p.h" + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +QmlExpressionData::QmlExpressionData() +: expressionFunctionValid(false), expressionRewritten(false), me(0), + trackChange(true), 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 QUrl &url, int lineNumber) +{ + data->fileName = url.toString(); + data->line = lineNumber; + + quint32 *exprData = (quint32 *)expr; + Q_ASSERT(*exprData == BasicScriptEngineData || + *exprData == PreTransformedQtScriptData); + if (*exprData == BasicScriptEngineData) { + data->sse.load((const char *)(exprData + 1), rc); + } else { + QmlCompiledData *dd = (QmlCompiledData *)rc; + + data->expressionRewritten = true; + data->expression = QString::fromRawData((QChar *)(exprData + 3), exprData[2]); + + int progIdx = *(exprData + 1); + QmlEngine *engine = ctxt->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_WIN32) //XXX Why doesn't this work? + if (!dd->programs.at(progIdx)) { + dd->programs[progIdx] = + new QScriptProgram(scriptEngine->compile(data->expression, data->fileName, data->line)); + } +#endif + + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ep->contextClass->newContext(ctxt, me)); + +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_WIN32) + data->expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); +#else + data->expressionFunction = scriptEngine->evaluate(data->expression); +#endif + + data->expressionFunctionValid = true; + scriptEngine->popContext(); + } + + data->QmlAbstractExpression::setContext(ctxt); + data->me = me; +} + +/*! + \class QmlExpression + \brief The QmlExpression class evaluates ECMAScript 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 QUrl &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 ECMAScript 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); + if (d->data->sse.isValid()) + return QString::fromUtf8(d->data->sse.expression()); + else + 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(); + + d->data->sse.clear(); +} + +QVariant QmlExpressionPrivate::evalSSE() +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueSSE> perfsse; +#endif + + QVariant rv = data->sse.run(data->context(), data->me); + + return rv; +} + +void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) +{ + 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>"); + } + + qWarning().nospace() << qPrintable(fileName) << ":" << lineNumber << ": " + << qPrintable(exception.toString()); + } +} + +QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueQt> perfqt; +#endif + + QmlContextPrivate *ctxtPriv = data->context()->d_func(); + QmlEngine *engine = data->context()->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + if (secondaryScope) + ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, + secondaryScope); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + if (!data->expressionFunctionValid) { + + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ep->contextClass->newContext(data->context(), data->me)); + + if (data->expressionRewritten) { + data->expressionFunction = scriptEngine->evaluate(data->expression, + data->fileName, data->line); + } else { + QmlRewrite::RewriteBinding rewriteBinding; + + const QString code = rewriteBinding(data->expression); + data->expressionFunction = scriptEngine->evaluate(code, data->fileName, data->line); + } + + scriptEngine->popContext(); + data->expressionFunctionValid = true; + } + + QScriptValue svalue = data->expressionFunction.call(); + + if (isUndefined) + *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); + + if (scriptEngine->hasUncaughtException()) { + printException(scriptEngine); + scriptEngine->clearExceptions(); + return QVariant(); + } + + if (secondaryScope) + ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); + + 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() || (!data->sse.isValid() && data->expression.isEmpty())) + return rv; + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValue> perf; +#endif + + QmlEnginePrivate *ep = QmlEnginePrivate::get(q->engine()); + + QmlExpression *lastCurrentExpression = ep->currentExpression; + QPODVector<QmlEnginePrivate::CapturedProperty> lastCapturedProperties; + ep->capturedProperties.copyAndClear(lastCapturedProperties); + + ep->currentExpression = q; + + // This object might be deleted during the eval + QmlExpressionData *localData = data; + localData->addref(); + + if (data->sse.isValid()) { + rv = evalSSE(); + } else { + rv = evalQtScript(secondaryScope, isUndefined); + } + + ep->currentExpression = lastCurrentExpression; + + // 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. +*/ +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(). +*/ +QUrl QmlExpression::sourceFile() const +{ + Q_D(const QmlExpression); + return QUrl(d->data->fileName); +} + +/*! + 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 fileName. This information + is used by the script engine. +*/ +void QmlExpression::setSourceLocation(const QUrl &fileName, int line) +{ + Q_D(QmlExpression); + d->data->fileName = fileName.toString(); + 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; +} + +/*! \internal */ +void QmlExpression::__q_notify() +{ + valueChanged(); +} + +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()) { + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); + } + } + + 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 + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); + } + /* 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) { + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, + q, notifyIdx); + } + } + + 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. +*/ + +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; + } +} + +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..96694d6 --- /dev/null +++ b/src/declarative/qml/qmlexpression.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLEXPRESSION_H +#define QMLEXPRESSION_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 QmlBasicScript; +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); + + QUrl sourceFile() const; + int lineNumber() const; + void setSourceLocation(const QUrl &fileName, int line); + + QObject *scopeObject() const; + +public Q_SLOTS: + QVariant value(bool *isUndefined = 0); + +Q_SIGNALS: + virtual void valueChanged(); + +protected: + QmlExpression(QmlContext *, const QString &, QObject *, + QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, const QUrl &, + 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..3ec8d1c --- /dev/null +++ b/src/declarative/qml/qmlexpression_p.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 "qmlbasicscript_p.h" +#include "qmlexpression.h" +#include "qmlengine_p.h" +#include <private/qguard_p.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_NAMESPACE + +class QmlAbstractExpression +{ +public: + QmlAbstractExpression(); + virtual ~QmlAbstractExpression(); + + bool isValid() const; + + QmlContext *context() const; + void setContext(QmlContext *); + +private: + friend class QmlContext; + QmlContext *m_context; + QmlAbstractExpression **m_prevExpression; + QmlAbstractExpression *m_nextExpression; +}; + +class QmlExpressionData : public QmlAbstractExpression, public QmlRefCount +{ +public: + QmlExpressionData(); + ~QmlExpressionData(); + + QmlExpressionPrivate *q; + + QString expression; + bool expressionFunctionValid:1; + bool expressionRewritten:1; + QScriptValue expressionFunction; + + QmlBasicScript sse; + QObject *me; + bool trackChange; + + QString fileName; + int line; + + struct SignalGuard : public QGuard<QObject> { + SignalGuard() : isDuplicate(false), notifyIndex(-1) {} + + SignalGuard &operator=(QObject *obj) { + QGuard<QObject>::operator=(obj); + return *this; + } + SignalGuard &operator=(const SignalGuard &o) { + QGuard<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(); + + enum CompiledDataType { + BasicScriptEngineData = 1, + PreTransformedQtScriptData = 2 + }; + + void init(QmlContext *, const QString &, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *, const QUrl &, int); + + QmlExpressionData *data; + + QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); + QVariant evalSSE(); + 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 void printException(QScriptEngine *); +}; + +QT_END_NAMESPACE + +#endif // QMLEXPRESSION_P_H diff --git a/src/declarative/qml/qmlglobalscriptclass.cpp b/src/declarative/qml/qmlglobalscriptclass.cpp new file mode 100644 index 0000000..0ade5ee --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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) +{ + return HandlesReadAccess | HandlesWriteAccess; +} + +QScriptValue +QmlGlobalScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + return engine()->undefinedValue(); +} + +void QmlGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1String("\""); + engine()->currentContext()->throwError(error); +} + +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..1b58f1e --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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); + +private: + QScriptValue globalObject; +}; + +QT_END_NAMESPACE + +#endif // QMLGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlinfo.cpp b/src/declarative/qml/qmlinfo.cpp new file mode 100644 index 0000000..119641f --- /dev/null +++ b/src/declarative/qml/qmlinfo.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlinfo.h" +#include <private/qmldeclarativedata_p.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtGui/qapplication.h> + +QT_BEGIN_NAMESPACE + +/*! + \fn void qmlInfo(const QString& message, QObject *object) + + \brief Prints warnings messages that include the file and line number for QML types. + + When QML types display warning messages, it improves tracibility + 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(tr("component property is a write-once property"), object); + \endcode + + prints + + \code + QML ComponentInstance (unknown location): component property is a write-once property + \endcode +*/ + +void qmlInfo(const QString& msg, QObject* object) +{ + QString pos = QLatin1String("QML"); + if (object) { + pos += QLatin1Char(' '); + pos += QLatin1String(object->metaObject()->className()); + } + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object); + pos += QLatin1String(" ("); + if (ddata) { + if (ddata->outerContext) { + pos += ddata->outerContext->baseUrl().toString(); + } else { + pos += qApp->translate("QmlInfo","unknown"); + } + pos += QLatin1String(":"); + pos += QString::number(ddata->lineNumber); + pos += QLatin1String(":"); + pos += QString::number(ddata->columnNumber); + } else { + pos += qApp->translate("QmlInfo","unknown location"); + } + pos += QLatin1String(") "); + qWarning((pos + msg).toLocal8Bit()); // XXX allow other processing? +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinfo.h b/src/declarative/qml/qmlinfo.h new file mode 100644 index 0000000..f2d17fe --- /dev/null +++ b/src/declarative/qml/qmlinfo.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINFO_H +#define QMLINFO_H + +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +Q_DECLARATIVE_EXPORT void qmlInfo(const QString& msg, QObject *me=0); + +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..a465445 --- /dev/null +++ b/src/declarative/qml/qmlinstruction.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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() << idx << "\t" << line << "\t" << "INIT"; + break; + case QmlInstruction::CreateObject: + qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; + break; + case QmlInstruction::SetId: + qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t\t" << primitives.at(instr->setId.value); + break; + case QmlInstruction::SetDefault: + qWarning() << idx << "\t" << line << "\t" << "SET_DEFAULT"; + break; + case QmlInstruction::CreateComponent: + qWarning() << idx << "\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; + break; + case QmlInstruction::StoreMetaObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t"; + break; + case QmlInstruction::StoreFloat: + qWarning() << idx << "\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; + break; + case QmlInstruction::StoreDouble: + qWarning() << idx << "\t" << line << "\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; + break; + case QmlInstruction::StoreInteger: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; + case QmlInstruction::StoreBool: + qWarning() << idx << "\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; + case QmlInstruction::StoreString: + qWarning() << idx << "\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() << idx << "\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() << idx << "\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t" << QString::number(instr->storeColor.value, 16); + break; + case QmlInstruction::StoreDate: + qWarning() << idx << "\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value; + break; + case QmlInstruction::StoreTime: + qWarning() << idx << "\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex; + break; + case QmlInstruction::StoreDateTime: + qWarning() << idx << "\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex; + break; + case QmlInstruction::StorePoint: + qWarning() << idx << "\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StorePointF: + qWarning() << idx << "\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSize: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSizeF: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreRect: + qWarning() << idx << "\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreRectF: + qWarning() << idx << "\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreVector3D: + qWarning() << idx << "\t" << line << "\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.valueIndex; + break; + case QmlInstruction::StoreVariant: + qWarning() << idx << "\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() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreVariantObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreInterface: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreSignal: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); + break; + case QmlInstruction::AssignSignalObject: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); + break; + case QmlInstruction::AssignCustomType: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; + case QmlInstruction::StoreBinding: + qWarning() << idx << "\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context; + break; + case QmlInstruction::StoreValueSource: + qWarning() << idx << "\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; + break; + case QmlInstruction::StoreValueInterceptor: + qWarning() << idx << "\t" << line << "\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue; + break; + case QmlInstruction::BeginObject: + qWarning() << idx << "\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue; + break; + case QmlInstruction::StoreObjectQmlList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QMLLIST"; + break; + case QmlInstruction::StoreObjectQList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; + case QmlInstruction::AssignObjectList: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT_LIST\t"; + break; + case QmlInstruction::FetchAttached: + qWarning() << idx << "\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id; + break; + case QmlInstruction::FetchQmlList: + qWarning() << idx << "\t" << line << "\t" << "FETCH_QMLLIST\t\t" << instr->fetchQmlList.property << "\t" << instr->fetchQmlList.type; + break; + case QmlInstruction::FetchQList: + qWarning() << idx << "\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property; + break; + case QmlInstruction::FetchObject: + qWarning() << idx << "\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property; + break; + case QmlInstruction::FetchValueType: + qWarning() << idx << "\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; + break; + case QmlInstruction::PopFetchedObject: + qWarning() << idx << "\t" << line << "\t" << "POP"; + break; + case QmlInstruction::PopQList: + qWarning() << idx << "\t" << line << "\t" << "POP_QLIST"; + break; + case QmlInstruction::PopValueType: + qWarning() << idx << "\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; + break; + case QmlInstruction::Defer: + qWarning() << idx << "\t" << line << "\t" << "DEFER" << "\t\t" << instr->defer.deferCount; + break; + default: + qWarning() << idx << "\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..dc18b05 --- /dev/null +++ b/src/declarative/qml/qmlinstruction_p.h @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qfxglobal.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 */ + StoreIdOptBinding, /* assignIdOptBinding */ + StoreObjPropBinding, /* assignObjPropBinding */ + 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; + } 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; //### merge with above + struct { + 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; + int fileName; + int lineNumber; + } 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..06955c7 --- /dev/null +++ b/src/declarative/qml/qmlintegercache.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlintegercache_p.h" +#include <private/qmlengine_p.h> +#include <QtDeclarative/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; +} + +QmlIntegerCache *QmlIntegerCache::createForEnums(QmlType *type, QmlEngine *engine) +{ + Q_ASSERT(type); + Q_ASSERT(engine); + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + const QMetaObject *mo = type->metaObject(); + + for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + QString name = QString::fromUtf8(enumerator.key(jj)); + int value = enumerator.value(jj); + + if (!name.at(0).isUpper()) + continue; + + if (cache->stringCache.contains(name)) + continue; + + cache->add(name, value); + } + } + + return cache; +} + +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..6e9fadd --- /dev/null +++ b/src/declarative/qml/qmlintegercache_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qmlrefcount_p.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlcleanup_p.h> +#include <QtCore/qhash.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; + + static QmlIntegerCache *createForEnums(QmlType *, QmlEngine *); + +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..80c3138 --- /dev/null +++ b/src/declarative/qml/qmllist.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLLIST_H +#define QMLLIST_H + +#include <QtDeclarative/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..09bde8c --- /dev/null +++ b/src/declarative/qml/qmllistscriptclass.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmllistscriptclass_p.h" +#include <private/qmlengine_p.h> + +QT_BEGIN_NAMESPACE + +struct ListData : public QScriptDeclarativeClass::Object { + QGuard<QObject> object; + int propertyIdx; + QmlListScriptClass::ListType type; +}; + +QmlListScriptClass::QmlListScriptClass(QmlEngine *e) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(e)), engine(e) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + m_lengthId = createPersistentIdentifier(QLatin1String("length")); +} + +QmlListScriptClass::~QmlListScriptClass() +{ +} + +QScriptValue QmlListScriptClass::newList(QObject *object, int propId, ListType type) +{ + 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; + + return newObject(scriptEngine, this, data); +} + +QScriptClass::QueryFlags +QmlListScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags 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; + } +} + +QScriptValue 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 scriptEngine->undefinedValue(); + + void *list = 0; + void *args[] = { &list, 0 }; + QMetaObject::metacall(data->object, QMetaObject::ReadProperty, + data->propertyIdx, args); + + if (!list) + return scriptEngine->undefinedValue(); + + if (data->type == QListPtr) { + const QList<QObject *> &qlist = *((QList<QObject *>*)list); + + if (name == m_lengthId.identifier) + return qlist.count(); + else if (lastIndex < qlist.count()) + return enginePriv->objectClass->newQObject(qlist.at(lastIndex)); + else + return scriptEngine->undefinedValue(); + + } else { + Q_ASSERT(data->type == QmlListPtr); + const QmlList<QObject *> &qmllist = *((QmlList<QObject *>*)list); + + int count = qmllist.count(); + + if (name == m_lengthId.identifier) + return count; + else if (lastIndex < count) + return enginePriv->objectClass->newQObject(qmllist.at(lastIndex)); + else + return scriptEngine->undefinedValue(); + } +} + +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..7592098 --- /dev/null +++ b/src/declarative/qml/qmllistscriptclass_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlListScriptClass : public QScriptDeclarativeClass +{ +public: + QmlListScriptClass(QmlEngine *); + ~QmlListScriptClass(); + + enum ListType { QListPtr, QmlListPtr }; + QScriptValue newList(QObject *, int, ListType); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual QScriptValue property(Object *, const Identifier &); + +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..edec988 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -0,0 +1,1254 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetaproperty.h" +#include "qmlmetaproperty_p.h" +#include "qmlcompositetypedata_p.h" +#include <qml.h> +#include <private/qfxperf_p.h> +#include <QStringList> +#include "qmlbinding.h" +#include <qmlcontext.h> +#include "qmlboundsignal_p.h" +#include <math.h> +#include <QtCore/qdebug.h> +#include <QtDeclarative/qmlengine.h> +#include <private/qmlengine_p.h> +#include <private/qmldeclarativedata_p.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; + + object = obj; + QMetaProperty p = QmlMetaType::defaultProperty(obj); + core.load(p); + if (core.isValid()) + isDefaultProperty = true; +} + +/*! + \internal + + Creates a QmlMetaProperty for the property at index \a idx of \a obj. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ + Q_ASSERT(obj); + + d->q = this; + d->context = ctxt; + d->object = obj; + d->core.load(obj->metaObject()->property(idx)); +} + +/*! + 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); +} + +/*! + \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); +} + +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 + //### needs to be done in a better way + QmlCompositeTypeData *typeData = + enginePrivate->typeManager.get(context->baseUrl()); + + if (typeData) { + QmlType *t = 0; + enginePrivate->resolveType(typeData->imports, name.toUtf8(), &t, 0, 0, 0, 0); + if (t && t->attachedPropertiesFunction()) { + attachedFunc = t->index(); + } + typeData->release(); + } + 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 *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) + cache = enginePrivate?enginePrivate->cache(obj):0; + + if (cache) { + QmlPropertyCache::Data *data = cache->property(name); + + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) + core = *data; + + } else { + // No cache available + QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); + core.load(p); + } +} + +/*! + 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->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->valueTypeCoreIdx == other.d->valueTypeCoreIdx && + d->valueTypePropType == other.d->valueTypePropType && + 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 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->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->valueTypeCoreIdx = other.d->valueTypeCoreIdx; + d->valueTypePropType = other.d->valueTypePropType; + + 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 (category == List || category == QmlList) + return true; + else if (type() & SignalProperty) + return true; + else if (d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).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 QmlMetaProperty refers to a valid property, otherwise + false. +*/ +bool QmlMetaProperty::isValid() const +{ + return type() != Invalid; +} + +/*! + Returns all of \a obj's Qt properties. +*/ +QStringList QmlMetaProperty::properties(QObject *obj) +{ + // ### What is this used for? + if (!obj) + return QStringList(); + + QStringList rv; + const QMetaObject *mo = obj->metaObject(); + for (int ii = 0; ii < mo->propertyCount(); ++ii) { + QMetaProperty prop = mo->property(ii); + rv << QString::fromUtf8(prop.name()); + } + + return rv; +} + +/*! + Return the name of this QML property. +*/ +QString QmlMetaProperty::name() const +{ + if (type() & ValueTypeProperty) { + QString rv = d->core.name + QLatin1String("."); + + 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->valueTypeCoreIdx).name()); + + if (!ep) delete valueType; + + return rv; + } else { + return d->core.name; + } +} + +/*! + 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. +*/ +QmlAbstractBinding * +QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding, QmlMetaProperty::WriteFlags flags) const +{ + if (!isProperty() || (type() & Attached) || !d->object) + 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)) + 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) { + + const QObjectList &children = object()->children(); + + for (int ii = 0; ii < children.count(); ++ii) { + QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); + if (sig && sig->index() == d->core.coreIndex) + return sig->expression()->expression(); + } + + } else if (type() & Property) { + + 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(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.type() == QVariant::String +#ifdef QT3_SUPPORT + || v.type() == QVariant::CString +#endif + ) { + if (prop.isFlagType()) + v = QVariant(menum.keysToValue(value.toByteArray())); + else + v = QVariant(menum.keyToValue(value.toByteArray())); + } else if (v.type() != QVariant::Int && v.type() != 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 = valueTypeCoreIdx; + data.propType = 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.type() == QVariant::Double) { + double integral; + double fractional = modf(value.toDouble(), &integral); + if (qFuzzyCompare(fractional, (double)0.0)) + 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->baseUrl().resolved(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 { + return false; + } + } + + return true; +} + +/*! + Set the property value to \a value. +*/ +bool QmlMetaProperty::write(const QVariant &value) const +{ + return write(value, 0); +} + +bool QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const +{ + if (d->object && type() & Property && d->core.isValid()) + 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->valueTypeCoreIdx; +} + +Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes); + +/*! + Returns the property information serialized into a single integer. + QmlMetaProperty uses the bottom 24 bits only. +*/ +quint32 QmlMetaProperty::save() const +{ + quint32 rv = 0; + if (type() & Attached) { + rv = d->attachedFunc; + } else if (type() != Invalid) { + rv = d->core.coreIndex; + } + + Q_ASSERT(rv <= 0x7FF); + Q_ASSERT(type() <= 0x3F); + Q_ASSERT(d->valueTypeCoreIdx <= 0x7F); + + rv |= (type() << 18); + + if (type() & ValueTypeProperty) + rv |= (d->valueTypeCoreIdx << 11); + + return rv; +} + +quint32 QmlMetaPropertyPrivate::saveValueType(int core, int valueType) +{ + Q_ASSERT(core <= 0x7FF); + Q_ASSERT(valueType <= 0x7F); + quint32 rv = 0; + rv = (QmlMetaProperty::ValueTypeProperty | QmlMetaProperty::Property) << 18; + rv |= core; + rv |= valueType << 11; + return rv; +} + +quint32 QmlMetaPropertyPrivate::saveProperty(int core) +{ + Q_ASSERT(core <= 0x7FF); + quint32 rv = 0; + rv = (QmlMetaProperty::Property) << 18; + rv |= core; + return rv; +} + +/*! + Restore a QmlMetaProperty from a previously saved \a id. + \a obj must be the same object as used in the previous call + to QmlMetaProperty::save(). Only the bottom 24-bits are + used, the high bits can be set to any value. +*/ +void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) +{ + QmlEnginePrivate *enginePrivate = 0; + if (ctxt && ctxt->engine()) + enginePrivate = QmlEnginePrivate::get(ctxt->engine()); + + d->object = obj; + d->context = ctxt; + + id &= 0xFFFFFF; + uint type = id >> 18; + id &= 0xFFFF; + + if (type & Attached) { + d->attachedFunc = id; + } else if (type & ValueTypeProperty) { + int coreIdx = id & 0x7FF; + int valueTypeIdx = id >> 11; + + QMetaProperty p(obj->metaObject()->property(coreIdx)); + Q_ASSERT(p.type() < QVariant::UserType); + + QmlValueType *valueType = qmlValueTypes()->valueTypes[p.type()]; + + QMetaProperty p2(valueType->metaObject()->property(valueTypeIdx)); + + d->core.load(p); + d->valueTypeCoreIdx = valueTypeIdx; + d->valueTypePropType = p2.userType(); + } else if (type & Property) { + + QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; + + if (cache) { + QmlPropertyCache::Data *data = cache->property(id); + if (data) d->core = *data; + } else { + QMetaProperty p(obj->metaObject()->property(id)); + d->core.load(p); + } + + } else if (type & SignalProperty) { + + QMetaMethod method = obj->metaObject()->method(id); + d->core.load(method); + } else { + *this = QmlMetaProperty(); + } +} + +/*! + \internal + + Creates a QmlMetaProperty for the property \a name of \a obj. Unlike + the QmlMetaProperty(QObject*, QString) constructor, this static function + will correctly handle dot properties. +*/ +QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, + const QString &name) +{ + QStringList path = name.split(QLatin1Char('.')); + + QObject *object = obj; + + for (int jj = 0; jj < path.count() - 1; ++jj) { + const QString &pathName = path.at(jj); + QmlMetaProperty prop(object, pathName); + + if (jj == path.count() - 2 && + prop.propertyType() < (int)QVariant::UserType && + qmlValueTypes()->valueTypes[prop.propertyType()]) { + // We're now at a value type property + 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->valueTypeCoreIdx = idx; + p.d->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); + 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..4a2b864 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETAPROPERTY_H +#define QMLMETAPROPERTY_H + +#include <QtDeclarative/qfxglobal.h> +#include <QtCore/QMetaProperty> + +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(QObject *, int, QmlContext * = 0); + ~QmlMetaProperty(); + + static QStringList properties(QObject *); + 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 hasChangedNotifier() const; + bool needsChangedNotifier() const; + bool connectNotifier(QObject *dest, const char *slot) const; + bool connectNotifier(QObject *dest, int method) const; + + quint32 save() const; + void restore(quint32, QObject *, QmlContext * = 0); + + 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 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 &); + + int coreIndex() const; + int valueTypeCoreIndex() const; +private: + friend class QmlEnginePrivate; + 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..368ca30 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qobject_p.h> +#include <private/qmlpropertycache_p.h> + +QT_BEGIN_NAMESPACE + +class QmlContext; +class QmlMetaPropertyPrivate +{ +public: + QmlMetaPropertyPrivate() + : q(0), context(0), object(0), isDefaultProperty(false), valueTypeCoreIdx(-1), + valueTypePropType(0), attachedFunc(-1) {} + + QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) + : q(0), context(other.context), object(other.object), + isDefaultProperty(other.isDefaultProperty), core(other.core), + valueTypeCoreIdx(other.valueTypeCoreIdx), + valueTypePropType(other.valueTypePropType), attachedFunc(other.attachedFunc) {} + + QmlMetaProperty *q; + QmlContext *context; + QGuard<QObject> object; + + bool isDefaultProperty; + QmlPropertyCache::Data core; + + // Describes the "virtual" value-type sub-property. + 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 + + // 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 quint32 saveValueType(int, int); + static quint32 saveProperty(int); + + 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..1ab7aff --- /dev/null +++ b/src/declarative/qml/qmlmetatype.cpp @@ -0,0 +1,1399 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetatype.h" +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbitarray.h> +#include <QtCore/qreadwritelock.h> +#include <private/qmlproxymetaobject_p.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 <ctype.h> +#include <QtCore/qcryptographichash.h> +#include <private/qmlcustomparser_p.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_from; + int m_version_min_to; + 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; + mutable QByteArray m_hash; +}; + +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_from = 0; + d->m_version_min_to = 0; +} + +QmlType::QmlType(int type, int listType, int qmlListType, + QmlPrivate::Func opFunc, const char *qmlName, + int version_maj, int version_min_from, int version_min_to, + 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_from = version_min_from; + d->m_version_min_to = version_min_to; + 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::minMinorVersion() const +{ + return d->m_version_min_from; +} + +int QmlType::maxMinorVersion() const +{ + return d->m_version_min_to; +} + +bool QmlType::availableInVersion(int vmajor, int vminor) const +{ + return vmajor == d->m_version_maj && vminor >= d->m_version_min_from && vminor <= d->m_version_min_to; +} + +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(); + } + + // Calculate hash + QByteArray hashData; + + const QMetaObject *myMetaObject = m_metaObjects.isEmpty()?m_baseMetaObject:m_metaObjects.first().metaObject; + + for (int ii = 0; ii < myMetaObject->propertyCount(); ++ii) { + QMetaProperty prop = myMetaObject->property(ii); + hashData.append(prop.type()); + hashData.append("|"); + hashData.append(prop.name()); + hashData.append("|"); + } + + for (int ii = 0; ii < myMetaObject->methodCount(); ++ii) { + QMetaMethod method = myMetaObject->method(ii); + hashData.append(method.signature()); + hashData.append("|"); + } + + m_hash = QCryptographicHash::hash(hashData, QCryptographicHash::Md5); + + 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; +} + +QByteArray QmlType::hash() const +{ + d->init(); + + return d->m_hash; +} + +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_from, int version_min_to, 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; + name.replace('.','/'); + + QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, + func, name, version_maj, version_min_from, version_min_to, 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::isObject(const QMetaObject *mo) +{ + // ### Huh? + while(mo) { + if (mo == &QObject::staticMetaObject) + return true; + mo = mo->superClass(); + } + return false; +} + +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) +{ + 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 0; +} + +/*! + 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> + +/*! + 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; + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = *static_cast<const NS(QCursor)*>(copy); + return true; + 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 (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; + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = NS(QCursor)(); + return true; + 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 (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..42c278c --- /dev/null +++ b/src/declarative/qml/qmlmetatype.h @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETATYPE_H +#define QMLMETATYPE_H + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <QtCore/qbitarray.h> +#include <QtDeclarative/qmlprivate.h> +#include <QtDeclarative/qmlparserstatus.h> +#include <QtDeclarative/qmlpropertyvaluesource.h> +#include <QtDeclarative/qmlpropertyvalueinterceptor.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_from, int vmin_to, 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 isObject(const QMetaObject *); + 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 minMinorVersion() const; + int maxMinorVersion() const; + bool availableInVersion(int vmajor, int vminor) const; + + QByteArray hash() 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 class QmlMetaTypeData; + QmlType(int, int, int, QmlPrivate::Func, const char *, int); + QmlType(int, int, int, QmlPrivate::Func, const char *, int, 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, 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_from, int version_min_to, 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_from, version_min_to, 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, 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_from, int version_min_to, 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_from, version_min_to, 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_from, int version_min_to, 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_from, version_min_to, 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/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp new file mode 100644 index 0000000..a6edd3b --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlobjectscriptclass_p.h" +#include <private/qmlengine_p.h> +#include <private/qguard_p.h> +#include <private/qmlcontext_p.h> +#include <private/qmldeclarativedata_p.h> +#include <private/qmltypenamescriptclass_p.h> +#include <private/qmllistscriptclass_p.h> +#include <QtDeclarative/qmlbinding.h> +#include <QtCore/qtimer.h> + +QT_BEGIN_NAMESPACE + +struct ObjectData : public QScriptDeclarativeClass::Object { + ObjectData(QObject *o, int t) : object(o), type(t) {} + QGuard<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) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), 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) +{ + 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); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(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) { + lastData = cache->property(name); + } else { + local = QmlPropertyCache::create(obj->metaObject(), toString(name)); + if (local.isValid()) + lastData = &local; + } + + if (lastData) { + QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; + if (lastData->flags & QmlPropertyCache::Data::IsWritable) + rv |= QScriptClass::HandlesWriteAccess; + return rv; + } + + 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; + } + } + } + + return 0; +} + +QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + if (name == m_destroyId.identifier) + return m_destroy; + else if (name == m_toStringId.identifier) + return m_toString; + + Q_ASSERT(obj); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (lastTNData) { + + if (lastTNData->type) + return enginePriv->typeNameClass->newObject(obj, lastTNData->type); + else + return enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace); + + } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + if (!(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 enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType); + } + + if (lastData->flags & QmlPropertyCache::Data::IsQList) { + return enginePriv->listClass->newList(obj, lastData->coreIndex, + QmlListScriptClass::QListPtr); + } else if (lastData->flags & QmlPropertyCache::Data::IsQmlList) { + return enginePriv->listClass->newList(obj, lastData->coreIndex, + QmlListScriptClass::QmlListPtr); + } if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + + return newQObject(rv, lastData->propType); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + return 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); + + 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); + } + + // ### Can well known types be optimized? + QVariant v = QmlScriptClass::toVariant(engine, value); + delete QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0); + QmlMetaPropertyPrivate::write(obj, *lastData, v, evalContext); +} + +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 += QLatin1String("\""); + } + + ret += QLatin1String(")"); + }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(); +} + +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..7fb727e --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtScript/qscriptclass.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlpropertycache_p.h> +#include <private/qmltypenamecache_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QScriptContext; +class QScriptEngine; +class QmlContext; +class QmlObjectScriptClass : public QScriptDeclarativeClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar); + QObject *toQObject(const QScriptValue &) const; + int objectType(const QScriptValue &) const; + + enum QueryMode { IncludeAttachedProperties, SkipAttachedProperties }; + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags, + QmlContext *evalContext); + QScriptValue property(QObject *, const Identifier &); + void setProperty(QObject *, const Identifier &name, const QScriptValue &, + QmlContext *evalContext = 0); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + virtual QObject *toQObject(Object *, bool *ok = 0); + +private: + 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; +}; + +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..f9e3c50 --- /dev/null +++ b/src/declarative/qml/qmlparser.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlparser_p.h" +#include <QStack> +#include <qmlpropertyvaluesource.h> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <private/qmlvme_p.h> +#include <private/qfxperf_p.h> +#include <qml.h> +#include "private/qmlcomponent_p.h" +#include <qmlcomponent.h> +#include "private/qmetaobjectbuilder_p.h" +#include <private/qmlvmemetaobject_p.h> +#include <private/qmlcompiler_p.h> +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +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) +{ +} + +void QmlParser::Object::dump(int indent) const +{ + QByteArray ba(indent * 4, ' '); + if (type != -1) { + qWarning() << ba.constData() << "Object:" << typeName; + } else { + qWarning() << ba.constData() << "Object: fetched"; + } + + for (QHash<QByteArray, Property *>::ConstIterator iter = properties.begin(); + iter != properties.end(); + ++iter) { + qWarning() << ba.constData() << " Property" << iter.key(); + (*iter)->dump(indent + 1); + } + + if (defaultProperty) { + qWarning() << ba.constData() << " Default property"; + defaultProperty->dump(indent + 1); + } +} + +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(); +} + +void QmlParser::Property::dump(int indent) const +{ + QByteArray ba(indent * 4, ' '); + for (int ii = 0; ii < values.count(); ++ii) + values.at(ii)->dump(indent); + if (value) + value->dump(indent); +} + +QmlParser::Value::Value() +: type(Unknown), object(0) +{ +} + +QmlParser::Value::~Value() +{ + if (object) object->release(); +} + +void QmlParser::Value::dump(int indent) const +{ + QByteArray type; + switch(this->type) { + default: + case Value::Unknown: + type = "Unknown"; + break; + case Value::Literal: + type = "Literal"; + break; + case Value::PropertyBinding: + type = "PropertyBinding"; + break; + case Value::ValueSource: + type = "ValueSource"; + break; + case Value::ValueInterceptor: + type = "ValueInterceptor"; + break; + case Value::CreatedObject: + type = "CreatedObject"; + break; + case Value::SignalObject: + type = "SignalObject"; + break; + case Value::SignalExpression: + type = "SignalExpression"; + break; + case Value::Id: + type = "Id"; + break; + } + + QByteArray primType; + switch(this->value.type()) { + default: + case Variant::Invalid: + primType = "Invalid"; + break; + case Variant::Boolean: + primType = "Boolean"; + break; + case Variant::Number: + primType = "Number"; + break; + case Variant::String: + primType = "String"; + break; + case Variant::Script: + primType = "Script"; + break; + } + + QByteArray ba(indent * 4, ' '); + if (object) { + qWarning() << ba.constData() << "Value (" << type << "):"; + object->dump(indent + 1); + } else { + qWarning() << ba.constData() << "Value (" << type << "):" << primType.constData() << primitive(); + } +} + +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; +} + +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..f0867ea --- /dev/null +++ b/src/declarative/qml/qmlparser_p.h @@ -0,0 +1,356 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/qstring.h> +#include <QtDeclarative/qml.h> +#include <private/qmlrefcount_p.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 + QStringList scriptBlocks; + QStringList scriptBlocksFile; + QList<int> scriptBlocksLineNumber; + + // 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; + + void dump(int = 0) const; + }; + + 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 asBoolean() const; + QString asString() const; + double asNumber() const; + QString asScript() const; + QmlJS::AST::Node *asAST() 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; + + void dump(int = 0) const; + }; + + 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; + + void dump(int = 0) const; + }; +} + +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..0d262ca --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..88ed865 --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..21b19e8 --- /dev/null +++ b/src/declarative/qml/qmlprivate.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..3e1a7e0 --- /dev/null +++ b/src/declarative/qml/qmlprivate.h @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(); + } + }; + +#if defined(Q_CC_MSVC) + template <typename T> + class has_attachedPropertiesMember + { + public: + __if_exists(T::qmlAttachedProperties) { + static bool const value = true; + } + __if_not_exists(T::qmlAttachedProperties) { + static bool const value = false; + } + }; +#elif defined(Q_OS_SYMBIAN) + template <typename T> + struct has_attachedPropertiesMember + { + static bool const value = QmlTypeInfo<T>::hasAttachedProperties; + }; +#else + template <typename T> + class has_attachedPropertiesMember + { + typedef int yes_type; + typedef char no_type; + template <int> + struct Selector {}; + + template <typename S> + static yes_type test(Selector<sizeof(&S::qmlAttachedProperties)>*); + + template <typename S> + static no_type test(...); + + public: + static bool const value = sizeof(test<T>(0)) == sizeof(yes_type); + }; +#endif + + 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 VMIN1, int VMIN2> + 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: + *((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..3ede341 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertycache_p.h" +#include <private/qmlengine_p.h> +#include <QtDeclarative/qmlbinding.h> + +QT_BEGIN_NAMESPACE + +void QmlPropertyCache::Data::load(const QMetaProperty &p) +{ + propType = p.userType(); + if (propType == QVariant::LastType) + propType = qMetaTypeId<QVariant>(); + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + name = QString::fromUtf8(p.name()); + + if (p.isConstant()) + flags |= Data::IsConstant; + if (p.isWritable()) + flags |= Data::IsWritable; + + if (propType == qMetaTypeId<QmlBinding *>()) { + flags |= Data::IsQmlBinding; + } else if (p.isEnumType()) { + flags |= Data::IsEnumType; + } else { + QmlMetaType::TypeCategory cat = 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) +{ + name = QString::fromUtf8(m.signature()); + int parenIdx = name.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + name = name.left(parenIdx); + + coreIndex = m.methodIndex(); + flags |= Data::IsFunction; +} + + +QmlPropertyCache::QmlPropertyCache(QmlEngine *engine) +: QmlCleanup(engine) +{ +} + +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); + 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; +} + +// ### 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); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### The properties/methods should probably be spliced on a per-metaobject basis + int propCount = metaObject->propertyCount(); + + cache->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); + + cache->indexCache[ii] = data; + + if (cache->stringCache.contains(propName)) + continue; + + cache->stringCache.insert(propName, data); + cache->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); + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (cache->stringCache.contains(methodName)) + continue; + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); + + data->load(m); + + cache->stringCache.insert(methodName, data); + cache->identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } + + return cache; +} + +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); +} + +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..6c3142a --- /dev/null +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qmlrefcount_p.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlcleanup_p.h> +#include <QtCore/qvector.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 { + // Can apply to all properties, except IsFunction + IsConstant = 0x00000001, + IsWritable = 0x00000002, + + // These are mutually exclusive + IsFunction = 0x00000004, + IsQObjectDerived = 0x00000008, + IsEnumType = 0x00000010, + IsQmlList = 0x00000020, + IsQList = 0x00000040, + IsQmlBinding = 0x00000080 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + bool isValid() const { return coreIndex != -1; } + + Flags flags; + int propType; + int coreIndex; + int notifyIndex; + QString name; + + void load(const QMetaProperty &); + void load(const QMetaMethod &); + }; + +#if 0 + struct 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 + }; +#endif + + 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; + +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; + + 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 && + name == other.name; +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +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..9a9aba8 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvalueinterceptor.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..678c12c --- /dev/null +++ b/src/declarative/qml/qmlpropertyvalueinterceptor.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..3317289 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..384d2f9 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..0baea31 --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..736bd91 --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QMetaObject> +#include <QtCore/QObject> +#include <private/qmetaobjectbuilder_p.h> +#include <private/qobject_p.h> +#include <QtDeclarative/qml.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..6c409e1 --- /dev/null +++ b/src/declarative/qml/qmlrefcount.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..a87d596 --- /dev/null +++ b/src/declarative/qml/qmlrefcount_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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..43b2529 --- /dev/null +++ b/src/declarative/qml/qmlrewrite.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlrewrite_p.h" +#include <QtDeclarative/qfxglobal.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP); + +namespace QmlRewrite { + +QString RewriteBinding::operator()(const QString &code) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + 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 *ast) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::DoWhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::WhileStatement *ast) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::WhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForStatement *ast) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForStatement *ast) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::LocalForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForEachStatement *ast) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForEachStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForEachStatement *ast) +{ + ++_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..59057d5 --- /dev/null +++ b/src/declarative/qml/qmlrewrite_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(const QString &code); + +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..307d72f --- /dev/null +++ b/src/declarative/qml/qmlscript.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This is just a dummy file to include the documentation + +/*! + \qmlclass Script QmlScript + \brief The Script element adds JavaScript snippets. + \ingroup group_utility + + QmlScript is used to add convenient JavaScript "glue" methods to + your Qt Declarative application or component. While you can have any JavaScript code + within a QmlScript, it is best to limit yourself to defining functions. + + \qml + Script { + function debugMyComponent() { + print(text.text); + print(otherinterestingitem.property); + } + } + MouseRegion { onClicked: debugMyComponent() } + \endqml + + \note QmlScript executes JavaScript as soon as it is specified. + When defining a component, this may be before the execution context is + fully specified. As a result some properties or items may not be + accessible. By limiting your JavaScript to defining functions that are + only executed later once the context is fully defined, this problem is + avoided. +*/ + +/*! + \qmlproperty string Script::script + \default + JavaScript code to execute. +*/ + +/*! + \qmlproperty url Script::source + + Setting this property causes the Script element to read JavaScript code from + the file specified. +*/ diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp new file mode 100644 index 0000000..fb84651 --- /dev/null +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -0,0 +1,941 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QStack> +#include <QCoreApplication> +#include <QtDebug> + +#include <private/qfxperf_p.h> + +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 + state.object->getDefaultProperty()->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)) { + AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(stmt->expression); + if (string) { + // We need to add this as a resource + _parser->_refUrls << QUrl(string->value->asString()); + } + } + } + } + + } + + 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; + 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 + QFxPerfTimer<QFxPerf::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..b25d6bf --- /dev/null +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QList> +#include <QtCore/QUrl> +#include <QtDeclarative/qmlerror.h> +#include "qmlparser_p.h" + +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..8a6afcc --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 {print(1921)} - itself +would be passed to the property and it could choose how to handle it. + +\code +MyType { + script: print(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..c6067ce --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..9e39ffc --- /dev/null +++ b/src/declarative/qml/qmlsqldatabase.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qobject.h> +#include <QtDeclarative/qmlengine.h> +#include <private/qmlengine_p.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 <private/qmlrefcount_p.h> +#include <private/qmlengine_p.h> +#include <QtCore/qstack.h> +#include <QtCore/qcryptographichash.h> +#include "qmlsqldatabase_p.h" +#include <QtCore/qsettings.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QSqlDatabase) +Q_DECLARE_METATYPE(QSqlQuery) + +class QmlSqlQueryScriptClassPropertyIterator; + +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 &object, + const QScriptString &name, + QueryFlags flags, uint *id) + { + if (flags & HandlesReadAccess) { + if (name == str_length) { + return HandlesReadAccess; + } else if (name == str_forwardOnly) { + return flags; + } else { + bool ok; + qint32 pos = name.toString().toInt(&ok); + if (pos < 0 || !ok) + return 0; + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + *id = pos; + if (*id < (uint)query.size()) + return HandlesReadAccess; + } + } + if (flags & HandlesWriteAccess) + if (name == str_forwardOnly) + return flags; + return 0; + } + + QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint id) + { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + if (name == str_length) { + int s = query.size(); + if (s<0) { + // Inefficient. + query.last(); + return query.at()+1; + } else { + return s; + } + } else if (name == str_forwardOnly) { + return query.isForwardOnly(); + } else { + if ((uint)query.at() == id || query.seek(id)) { // 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())); // XXX only strings + } + return row; + } + } + 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; + } + + QScriptClassPropertyIterator *newIterator(const QScriptValue &object); + +private: + QScriptString str_length; + QScriptString str_forwardOnly; +}; + +class QmlSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator +{ +public: + QmlSqlQueryScriptClassPropertyIterator(const QScriptValue &object) + : QScriptClassPropertyIterator(object) + { + toFront(); + } + + ~QmlSqlQueryScriptClassPropertyIterator() + { + } + + bool hasNext() const + { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object().data()); + return query.at() == m_index || query.seek(m_index); // Qt 4.6 doesn't optimize seek(at()) + } + + void next() + { + m_last = m_index; + ++m_index; + } + + bool hasPrevious() const + { + return (m_index > 0); + } + + void previous() + { + --m_index; + m_last = m_index; + } + + void toFront() + { + m_index = 0; + m_last = -1; + } + + void toBack() + { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object().data()); + m_index = query.size(); + m_last = -1; + } + + QScriptString name() const + { + return object().engine()->toStringHandle(QString::number(m_last)); + } + + uint id() const + { + return m_last; + } + +private: + int m_index; + int m_last; +}; + +QScriptClassPropertyIterator *QmlSqlQueryScriptClass::newIterator(const QScriptValue &object) +{ + return new QmlSqlQueryScriptClassPropertyIterator(object); +} + + + +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(QScriptContext *context, QScriptEngine *engine) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QString sql = context->argument(0).toString(); + QScriptValue values = context->argument(1); + QScriptValue cb = context->argument(2); + QScriptValue cberr = context->argument(3); + QSqlQuery query(db); + bool err = false; + if (query.prepare(sql)) { + if (values.isArray()) { + for (QScriptValueIterator it(values); it.hasNext();) { + it.next(); + query.addBindValue(it.value().toVariant()); + } + } else { + query.bindValue(0,values.toVariant()); + } + if (query.exec()) { + QScriptValue rs = engine->newObject(); + if (!QmlEnginePrivate::get(engine)->sqlQueryClass) + QmlEnginePrivate::get(engine)->sqlQueryClass= new QmlSqlQueryScriptClass(engine); + QScriptValue rows = engine->newObject(QmlEnginePrivate::get(engine)->sqlQueryClass); + rows.setData(engine->newVariant(qVariantFromValue(query))); + rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration); + rs.setProperty(QLatin1String("rows"),rows); + rs.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected()); + rs.setProperty(QLatin1String("insertId"),query.lastInsertId().toString()); // XXX only string + cb.call(QScriptValue(), QScriptValueList() << context->thisObject() << rs); + } else { + err = true; + } + } else { + err = true; + } + if (err) { + QScriptValue error = engine->newObject(); + error.setProperty(QLatin1String("message"), query.lastError().text()); + cberr.call(QScriptValue(), QScriptValueList() << context->thisObject() << error); + } + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + if (context->argumentCount() < 1) + return engine->undefinedValue(); + QScriptValue cb = context->argument(0); + if (!cb.isFunction()) + return engine->undefinedValue(); + + // Call synchronously... - XXX could do asynch with threads + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,4)); + QScriptValue tx = engine->newVariant(instance,qVariantFromValue(db)); + + db.transaction(); + cb.call(QScriptValue(), QScriptValueList() << tx); + if (engine->hasUncaughtException()) { + db.rollback(); + QScriptValue cb = context->argument(1); + if (cb.isFunction()) + cb.call(); + } else { + db.commit(); + QScriptValue cb = context->argument(2); + if (cb.isFunction()) + cb.call(); + } + return engine->undefinedValue(); +} + + +/* + Currently documented in doc/src/declarastive/globalobject.qdoc +*/ +static QScriptValue qmlsqldatabase_open(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(); + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(dbname.toUtf8()); + md5.addData(dbversion.toUtf8()); + QString dbid(QLatin1String(md5.result().toHex())); + + // Uses SQLLITE (like HTML5), but any could be used. + + if (QSqlDatabase::connectionNames().contains(dbid)) { + database = QSqlDatabase::database(dbid); + } else { + database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); + } + if (!database.isOpen()) { + QString basename = QmlEnginePrivate::get(engine)->offlineStoragePath + QLatin1String("/Databases/"); + QDir().mkpath(basename); + basename += dbid; + database.setDatabaseName(basename+QLatin1String(".sqlite")); + QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); + ini.setValue(QLatin1String("Name"), dbname); + ini.setValue(QLatin1String("Version"), dbversion); + ini.setValue(QLatin1String("Description"), dbdescription); + ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize); + ini.setValue(QLatin1String("DbType"), QLatin1String("QSQLITE")); + database.open(); + } + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,3)); + return engine->newVariant(instance,qVariantFromValue(database)); +} + +void qt_add_qmlsqldatabase(QScriptEngine *engine) +{ + QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open, 4); + engine->globalObject().setProperty(QLatin1String("openDatabase"), openDatabase); +} + +/* +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..f76a2fd --- /dev/null +++ b/src/declarative/qml/qmlsqldatabase_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..34025c5 --- /dev/null +++ b/src/declarative/qml/qmlstringconverters.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#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 "qmlstringconverters_p.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); + bool b = boolFromString(s, &ok); + if (ok) return QVariant(b); + QVector3D v = vector3DFromString(s, &ok); + if (ok) return qVariantFromValue(v); + + return QVariant(s); +} + +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; + } +} + +//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); +} + +bool QmlStringConverters::boolFromString(const QString &str, bool *ok) +{ + if (str.isEmpty() || str == QLatin1String("false") || str == QLatin1String("0")) { + if (ok) + *ok = true; + return false; + } else if (str == QLatin1String("true") || str == QLatin1String("1")) { + if (ok) + *ok = true; + return true; + } + + if (ok) + *ok = false; + return true; +} + +//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..ab7448c --- /dev/null +++ b/src/declarative/qml/qmlstringconverters_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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> +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 &); + QColor Q_DECLARATIVE_EXPORT colorFromString(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); + bool Q_DECLARATIVE_EXPORT boolFromString(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..d706c63 --- /dev/null +++ b/src/declarative/qml/qmltypenamecache.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmltypenamecache_p.h" +#include <private/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..ec1e79d --- /dev/null +++ b/src/declarative/qml/qmltypenamecache_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <private/qmlrefcount_p.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlcleanup_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..7a14432 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmltypenamescriptclass_p.h" +#include <private/qmlengine_p.h> +#include <private/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) +: QScriptDeclarativeClass(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; +} + +QScriptValue QmlTypeNameScriptClass::property(Object *obj, const Identifier &name) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + if (type) { + return newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode); + } else if (object) { + return ep->objectClass->property(object, name); + } else { + return QScriptValue(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..d8112d2 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtScript/qscriptclass.h> +#include <private/qscriptdeclarativeclass_p.h> +#include <private/qmlengine_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlType; +class QmlTypeNameCache; +class QmlTypeNameScriptClass : public QScriptDeclarativeClass +{ +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 QScriptValue 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..84c9ecb --- /dev/null +++ b/src/declarative/qml/qmlvaluetype.cpp @@ -0,0 +1,569 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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); +} + +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); +} + +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; + } + font.setPointSizeF(size); +} + +int QmlFontValueType::pixelSize() const +{ + return font.pixelSize(); +} + +void QmlFontValueType::setPixelSize(int size) +{ + font.setPixelSize(size); + hasPixelSize = true; +} + +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..d3adf1e --- /dev/null +++ b/src/declarative/qml/qmlvaluetype_p.h @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/qobject.h> +#include <QtCore/qrect.h> +#include <QtCore/qvariant.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qfont.h> +#include <QmlMetaProperty> + +QT_BEGIN_NAMESPACE + +class 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 QmlValueTypeFactory +{ +public: + QmlValueTypeFactory(); + ~QmlValueTypeFactory(); + static QmlValueType *valueType(int); + + QmlValueType *valueTypes[QVariant::UserType - 1]; + QmlValueType *operator[](int idx) const { return valueTypes[idx]; } +}; + +class 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 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 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 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 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 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 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 QmlFontValueType : public QmlValueType +{ + Q_OBJECT + Q_PROPERTY(QString family READ family WRITE setFamily) + Q_PROPERTY(bool bold READ bold WRITE setBold) + Q_PROPERTY(bool italic READ italic WRITE setItalic) + Q_PROPERTY(bool underline READ underline WRITE setUnderline) + Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize) + Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize) +public: + 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); + + bool italic() const; + void setItalic(bool b); + + bool underline() const; + void setUnderline(bool b); + + qreal pointSize() const; + void setPointSize(qreal size); + + int pixelSize() const; + void setPixelSize(int size); + +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..6a7bdeb --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvaluetypescriptclass_p.h" +#include <private/qmlengine_p.h> + +QT_BEGIN_NAMESPACE + +struct QmlValueTypeReference { + QmlValueType *type; + QGuard<QObject> object; + int property; +}; +Q_DECLARE_METATYPE(QmlValueTypeReference); + +QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine) +: QScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) +{ +} + +QmlValueTypeScriptClass::~QmlValueTypeScriptClass() +{ +} + +QScriptValue QmlValueTypeScriptClass::newObject(QObject *object, int coreIndex, QmlValueType *type) +{ + QmlValueTypeReference ref = { type, object, coreIndex }; + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + return scriptEngine->newObject(this, scriptEngine->newVariant(qVariantFromValue(ref))); +} + +QmlValueTypeScriptClass::QueryFlags +QmlValueTypeScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(flags); + QmlValueTypeReference ref = + qvariant_cast<QmlValueTypeReference>(object.data().toVariant()); + + if (!ref.object) + return 0; + + QByteArray propName = name.toString().toUtf8(); + + int idx = ref.type->metaObject()->indexOfProperty(propName.constData()); + if (idx == -1) + return 0; + *id = idx; + + QMetaProperty prop = ref.object->metaObject()->property(idx); + + QmlValueTypeScriptClass::QueryFlags rv = + QmlValueTypeScriptClass::HandlesReadAccess; + if (prop.isWritable()) + rv |= QmlValueTypeScriptClass::HandlesWriteAccess; + + return rv; +} + +QScriptValue QmlValueTypeScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + Q_UNUSED(name); + QmlValueTypeReference ref = + qvariant_cast<QmlValueTypeReference>(object.data().toVariant()); + + if (!ref.object) + return QScriptValue(); + + ref.type->read(ref.object, ref.property); + + QMetaProperty p = ref.type->metaObject()->property(id); + QVariant rv = p.read(ref.type); + + return static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv); +} + +void QmlValueTypeScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value) +{ + Q_UNUSED(name); + QmlValueTypeReference ref = + qvariant_cast<QmlValueTypeReference>(object.data().toVariant()); + + if (!ref.object) + return; + + QVariant v = QmlScriptClass::toVariant(engine, value); + + ref.type->read(ref.object, ref.property); + QMetaProperty p = ref.type->metaObject()->property(id); + p.write(ref.type, v); + ref.type->write(ref.object, ref.property, 0); +} + +QVariant QmlValueTypeScriptClass::toVariant(const QScriptValue &val) +{ + QmlValueTypeReference ref = + qvariant_cast<QmlValueTypeReference>(val.data().toVariant()); + + if (!ref.object) + return QVariant(); + + QMetaProperty p = ref.object->metaObject()->property(ref.property); + return p.read(ref.object); +} + +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..d656a22 --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtScript/qscriptclass.h> +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlValueType; +class QmlValueTypeScriptClass : public QScriptClass +{ +public: + QmlValueTypeScriptClass(QmlEngine *); + ~QmlValueTypeScriptClass(); + + QScriptValue newObject(QObject *object, int coreIndex, QmlValueType *); + + 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); + + QVariant toVariant(const QScriptValue &); +private: + QmlEngine *engine; +}; + +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..802a78f --- /dev/null +++ b/src/declarative/qml/qmlvme.cpp @@ -0,0 +1,905 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvme_p.h" +#include "qmlcompiler_p.h" +#include <private/qfxperf_p.h> +#include <private/qmlboundsignal_p.h> +#include <private/qmlstringconverters_p.h> +#include "private/qmetaobjectbuilder_p.h" +#include "private/qmldeclarativedata_p.h" +#include <qml.h> +#include <private/qmlcustomparser_p.h> +#include <QStack> +#include <QWidget> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <qmlengine.h> +#include <qmlcontext.h> +#include <qmlcomponent.h> +#include <qmlbinding.h> +#include <private/qmlengine_p.h> +#include <private/qmlcomponent_p.h> +#include "private/qmlvmemetaobject_p.h" +#include <QtCore/qdebug.h> +#include <QtCore/qvarlengtharray.h> +#include <QtGui/qapplication.h> +#include <private/qmlbinding_p.h> +#include <private/qmlcontext_p.h> +#include <private/qmlbindingoptimizations_p.h> +#include <QtDeclarative/qmlscriptstring.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) +{ + QStack<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; + QStack<QObject *> stack; + stack.push(object); + + run(stack, ctxt, comp, start, count, QBitField()); +} + +QBitField bindingSkipList; +QObject *QmlVME::run(QStack<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; + + + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bindValues; + QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus; + + QStack<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) { + QmlInstruction &instr = comp->bytecode[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)); + } + 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(qApp->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 { + o->setParent(parent); + } + } + stack.push(o); + } + break; + + case QmlInstruction::SetId: + { + QObject *target = stack.top(); +// ctxt->setContextProperty(primitives.at(instr.setId.value), target); + cp->setIdProperty(primitives.at(instr.setId.value), 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(); + QUrl u(primitives.at(instr.storeUrl.value)); + void *a[] = { &u, 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(qApp->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(qApp->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(qApp->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(qApp->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->url, instr.line); + bs->setExpression(expr); + } + break; + + case QmlInstruction::StoreScript: + { + QObject *target = stack.top(); + cp->addScript(primitives.at(instr.storeScript.value), target, + primitives.at(instr.storeScript.fileName), + instr.storeScript.lineNumber); + } + 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; + mp.restore(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->url, instr.line, 0); + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->setTarget(mp); + bind->addToObject(target); + } + break; + + case QmlInstruction::StoreIdOptBinding: + { + int coreIndex = instr.assignIdOptBinding.property; + if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) + break; + + QObject *target = stack.top(); + + QmlBinding_Id *bind = + new QmlBinding_Id(target, instr.assignIdOptBinding.property, + ctxt, instr.assignIdOptBinding.id); + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->addToObject(target); + } + break; + + case QmlInstruction::StoreObjPropBinding: + { + int coreIndex = instr.assignObjPropBinding.property; + if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) + break; + + QObject *target = stack.top(); + QObject *context = + stack.at(stack.count() - 1 - instr.assignObjPropBinding.context); + + QmlBinding_ObjProperty *bind = + new QmlBinding_ObjProperty(target, instr.assignObjPropBinding.property, context, instr.assignObjPropBinding.contextIdx, instr.assignObjPropBinding.notifyIdx); + + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->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; + prop.restore(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; + prop.restore(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(qApp->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(qApp->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(qApp->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(qApp->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(qApp->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(qApp->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..38ba06f --- /dev/null +++ b/src/declarative/qml/qmlvme_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtCore/QString> +#include <QtCore/QStack> +#include <QtDeclarative/qmlerror.h> +#include <private/qbitfield_p.h> + +QT_BEGIN_NAMESPACE + +class QObject; +class QmlInstruction; +class QmlCompiledData; +class QmlCompiledData; +class QmlContext; + +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(QStack<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..a627bf9 --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvmemetaobject_p.h" +#include <qml.h> +#include <private/qmlrefcount_p.h> +#include <QColor> +#include <QDate> +#include <QtCore/qlist.h> +#include <QtCore/qdebug.h> +#include <qmlexpression.h> +#include <private/qmlcontext_p.h> + +QT_BEGIN_NAMESPACE + +QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, + const QMetaObject *other, + const QmlVMEMetaData *meta, + QmlRefCount *rc) +: object(obj), ref(rc), ctxt(qmlContext(obj)), metaData(meta), parent(0) +{ + if (ref) + ref->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() +{ + if (ref) + ref->release(); + if (parent) + delete parent; + qDeleteAll(listProperties); + delete [] data; +} + +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; + QVariant::Type type = QVariant::Invalid; + if (id >= propOffset) { + id -= propOffset; + if (id < metaData->propertyCount) { + type = data[id].type(); + } + } else { + type = property(id).type(); + } + + 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)); + 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) { + + if (!ctxt) return -1; + QmlVMEMetaData::AliasData *d = metaData->aliasData() + id; + QmlContextPrivate *ctxtPriv = + (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + QObject *target = ctxtPriv->idValues[d->contextIdx].data(); + if (!target) { + if (d->propertyIdx == -1) + *reinterpret_cast<QObject **>(a[0]) = 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) { + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); + + if (0 == (metaData->methodData() + id)->parameterCount) { + QmlExpression expr(ctxt, code, object); + expr.setTrackChange(false); + expr.value(); + } else { + QmlContext newCtxt(ctxt); + QMetaMethod m = method(_id); + QList<QByteArray> names = m.parameterNames(); + for (int ii = 0; ii < names.count(); ++ii) + newCtxt.setContextProperty(names.at(ii), *(QVariant *)a[ii + 1]); + QmlExpression expr(&newCtxt, code, object); + expr.setTrackChange(false); + expr.value(); + } + } + return -1; + } + } + + if (parent) + return parent->metaCall(c, _id, a); + else + return object->qt_metacall(c, _id, a); +} + +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)); +} + + +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..74b6d09 --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtDeclarative/qml.h> +#include <QtCore/QMetaObject> +#include <QtCore/QBitArray> +#include <QtCore/QPair> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +struct QmlVMEMetaData +{ + short propertyCount; + short aliasCount; + short signalCount; + short methodCount; + + struct AliasData { + int contextIdx; + int propertyIdx; + }; + + struct PropertyData { + int propertyType; + }; + + struct MethodData { + int parameterCount; + int bodyOffset; + int bodyLength; + int _dummy; + }; + + 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 *, const QMetaObject *, const QmlVMEMetaData *data, + QmlRefCount * = 0); + ~QmlVMEMetaObject(); + + void registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QObject *object; + QmlRefCount *ref; + QGuard<QmlContext> ctxt; + + const QmlVMEMetaData *metaData; + int propOffset; + int methodOffset; + + QVariant *data; + QBitArray aConnected; + QBitArray aInterceptors; + QHash<int, QPair<int, QmlPropertyValueInterceptor*> > interceptors; + + 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..ca99472 --- /dev/null +++ b/src/declarative/qml/qmlwatcher.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> +#include <QtDeclarative/qmlexpression.h> +#include <QtDeclarative/qmldebugservice.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qml.h> + +#include "qmlwatcher_p.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, QByteArray(m_property.name()), 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..99cae88 --- /dev/null +++ b/src/declarative/qml/qmlwatcher_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 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 QByteArray &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/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp new file mode 100644 index 0000000..5117a00 --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -0,0 +1,1463 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qobject.h> +#include <QtDeclarative/qmlengine.h> +#include <private/qmlengine_p.h> +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptengine.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtCore/qxmlstream.h> +#include <private/qmlrefcount_p.h> +#include <private/qmlengine_p.h> +#include <QtCore/qstack.h> +#include "qmlxmlhttprequest_p.h" + +#include <QtCore/qdebug.h> + +// ### Find real values +#define INVALID_STATE_ERR ((QScriptContext::Error)15) + +#define D(arg) (arg)->release() +#define A(arg) (arg)->addref() + +namespace { + +class NodeImpl : public QmlRefCount +{ +public: + NodeImpl() : type(Element), parent(0) {} + virtual ~NodeImpl() { + if (parent) D(parent); + for (int ii = 0; ii < children.count(); ++ii) + D(children.at(ii)); + for (int ii = 0; ii < attributes.count(); ++ii) + D(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; + + NodeImpl *parent; + + QList<NodeImpl *> children; + QList<NodeImpl *> attributes; +}; + +class DocumentImpl : public QmlRefCount +{ +public: + DocumentImpl() : root(0) {} + virtual ~DocumentImpl() { + if (root) D(root); + } + + QString version; + QString encoding; + bool isStandalone; + + NodeImpl *root; +}; + +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 &operator=(const NamedNodeMap &); + ~NamedNodeMap(); + bool isNull(); + + NodeImpl *d; + QList<NodeImpl *> *list; +}; + +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); + static QScriptValue item(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *); + + NodeList(); + NodeList(const NodeList &); + NodeList &operator=(const NodeList &); + ~NodeList(); + bool isNull(); + + NodeImpl *d; +}; + +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 &operator=(const Node &); + ~Node(); + bool isNull() const; + + NodeImpl *d; +}; + +class Element : public Node +{ +public: + 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); + + Document(); + Document(const Document &); + Document &operator=(const Document &); + ~Document(); + bool isNull() const; + + DocumentImpl *d; +private: + Document(DocumentImpl *); +}; + +}; + +Q_DECLARE_METATYPE(Node); +Q_DECLARE_METATYPE(NodeList); +Q_DECLARE_METATYPE(NamedNodeMap); +Q_DECLARE_METATYPE(Document); + +QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + 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(); + + 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: + case NodeImpl::Comment: + case NodeImpl::Document: + case NodeImpl::DocumentFragment: + case NodeImpl::DocumentType: + case NodeImpl::Entity: + case NodeImpl::EntityReference: + case NodeImpl::Notation: + case NodeImpl::CDATA: + instance.setPrototype(CDATA::prototype(engine)); + break; + case NodeImpl::ProcessingInstruction: + instance.setPrototype(Node::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 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(); + + // ### implement + return QScriptValue(false); +} + +QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + // ### implement + return QScriptValue(QString()); +} + +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->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->namespaceUri = reader.namespaceUri().toString(); + node->name = reader.name().toString(); + if (nodeStack.isEmpty()) { + document->root = node; + } else { + node->parent = nodeStack.top(); + A(node->parent); + node->parent->children.append(node); + } + nodeStack.append(node); + + foreach (const QXmlStreamAttribute &a, reader.attributes()) { + NodeImpl *attr = new NodeImpl; + attr->type = NodeImpl::Attr; + attr->namespaceUri = a.namespaceUri().toString(); + attr->name = a.name().toString(); + attr->data = a.value().toString(); + node->attributes.append(attr); + } + } + break; + case QXmlStreamReader::EndElement: + nodeStack.pop(); + break; + case QXmlStreamReader::Characters: + { + NodeImpl *node = new NodeImpl; + node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text; + node->parent = nodeStack.top(); + A(node->parent); + 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)); + return engine->newVariant(instance, qVariantFromValue(Document(document))); +} + +Node::Node() +: d(0) +{ +} + +Node::Node(const Node &o) +: d(o.d) +{ + if (d) A(d); +} + +Node &Node::operator=(const Node &o) +{ + if (o.d) A(o.d); + if (d) D(d); + d = o.d; + return *this; +} + +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 (!QmlEnginePrivate::get(engine)->namedNodeMapClass) + QmlEnginePrivate::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine); + + instance.setScriptClass(QmlEnginePrivate::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::operator=(const NamedNodeMap &o) +{ + if (o.d) A(o.d); + if (d) D(d); + d = o.d; + list = o.list; + return *this; +} + +NamedNodeMap::~NamedNodeMap() +{ + if (d) D(d); +} + +bool NamedNodeMap::isNull() +{ + return d == 0; +} + +QScriptValue NodeList::item(QScriptContext *context, QScriptEngine *engine) +{ + NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data()); + if (list.isNull() || context->argumentCount() != 1) + return engine->undefinedValue(); + + qint32 index = context->argument(0).toInt32(); + + if (index >= list.d->children.count()) + return engine->undefinedValue(); // ### Exception + else + return Node::create(engine, list.d->children.at(index)); +} + +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); + proto.setProperty(QLatin1String("item"), engine->newFunction(item, 1), QScriptValue::ReadOnly); + + 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 (!QmlEnginePrivate::get(engine)->nodeListClass) + QmlEnginePrivate::get(engine)->nodeListClass= new NodeListClass(engine); + + instance.setScriptClass(QmlEnginePrivate::get(engine)->nodeListClass); + + return instance; +} + +NodeList::NodeList() +: d(0) +{ +} + +NodeList::NodeList(const NodeList &o) +: d(o.d) +{ + if (d) A(d); +} + +NodeList &NodeList::operator=(const NodeList &o) +{ + if (o.d) A(o.d); + if (d) D(d); + d = o.d; + return *this; +} + +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; + + bool ok = false; + uint index = name.toString().toUInt(&ok); + if (!ok) + return 0; + + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data()); + if (map.isNull() || (uint)map.list->count() <= index) + return 0; // ### I think we're meant to raise an exception + + *id = index; + return HandlesReadAccess; +} + +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)); +} + +Document::Document() +: d(0) +{ +} + +Document::Document(DocumentImpl *data) +: d(data) +{ +} + +Document::Document(const Document &o) +: Node(o), d(o.d) +{ + if (d) A(d); +} + +Document &Document::operator=(const Document &o) +{ + if (o.d) A(o.d); + if (d) D(d); + d = o.d; + return *this; +} + +Document::~Document() +{ + if (d) D(d); +} + +bool Document::isNull() const +{ + return d == 0; +} + +QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine) +{ + Document document = qscriptvalue_cast<Document>(context->thisObject()); + if (document.isNull()) return engine->undefinedValue(); + + if (!document.d->root) return engine->nullValue(); + + return Node::create(engine, document.d->root); +} + +QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine) +{ + Document document = qscriptvalue_cast<Document>(context->thisObject()); + if (document.isNull()) return engine->undefinedValue(); + + if (context->argumentCount()) + document.d->isStandalone = context->argument(0).toBool(); + + return QScriptValue(document.d->isStandalone); +} + +QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine) +{ + Document document = qscriptvalue_cast<Document>(context->thisObject()); + if (document.isNull()) return engine->undefinedValue(); + + if (context->argumentCount()) + document.d->version = context->argument(0).toString(); + + return QScriptValue(document.d->version); +} + +QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine) +{ + Document document = qscriptvalue_cast<Document>(context->thisObject()); + if (document.isNull()) return engine->undefinedValue(); + + if (context->argumentCount()) + document.d->encoding = context->argument(0).toString(); + + return QScriptValue(document.d->encoding); +} + +class QmlXMLHttpRequest : public QObject +{ +Q_OBJECT +public: + enum State { Unsent = 0, + Opened = 1, HeadersReceived = 2, + Loading = 3, Done = 4 }; + + QmlXMLHttpRequest(QmlEngine *engine); + virtual ~QmlXMLHttpRequest(); + + QScriptValue callback() const; + void setCallback(const QScriptValue &); + + bool sendFlag() const; + bool errorFlag() const; + quint32 readyState() const; + int replyStatus() const; + QString replyStatusText() const; + + void open(const QString &, const QUrl &); + void addHeader(const QString &, const QString &); + QString header(const QString &name); + QString headers(); + void send(const QByteArray &); + void abort(); + + QString responseBody() const; +private slots: + void downloadProgress(qint64); + void error(QNetworkReply::NetworkError); + void finished(); + +private: + QmlEngine *m_engine; + + State m_state; + bool m_errorFlag; + bool m_sendFlag; + QString m_method; + QUrl m_url; + QByteArray m_responseEntityBody; + + typedef QPair<QByteArray, QByteArray> HeaderPair; + typedef QList<HeaderPair> HeadersList; + HeadersList m_headersList; + void fillHeadersList(); + + void dispatchCallback(); + QScriptValue m_callback; + + int m_status; + QString m_statusText; + QNetworkRequest m_request; + QNetworkReply *m_network; + void destroyNetwork(); +}; + +QmlXMLHttpRequest::QmlXMLHttpRequest(QmlEngine *engine) +: m_engine(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false), + m_network(0) +{ + Q_ASSERT(m_engine); +} + +QmlXMLHttpRequest::~QmlXMLHttpRequest() +{ + destroyNetwork(); +} + +QScriptValue QmlXMLHttpRequest::callback() const +{ + return m_callback; +} + +void QmlXMLHttpRequest::setCallback(const QScriptValue &c) +{ + m_callback = c; +} + +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; +} + +void QmlXMLHttpRequest::open(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; + dispatchCallback(); +} + +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.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, m_network->rawHeader(header)); + m_headersList << pair; + } +} + +void QmlXMLHttpRequest::send(const QByteArray &data) +{ + m_errorFlag = false; + m_sendFlag = true; + + dispatchCallback(); + + m_request.setUrl(m_url); + + if (m_method == QLatin1String("GET")) + m_network = m_engine->networkAccessManager()->get(m_request); + else if (m_method == QLatin1String("HEAD")) + m_network = m_engine->networkAccessManager()->head(m_request); + else if(m_method == QLatin1String("POST")) + m_network = m_engine->networkAccessManager()->post(m_request, data); + else if(m_method == QLatin1String("PUT")) + m_network = m_engine->networkAccessManager()->put(m_request, 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())); +} + +void QmlXMLHttpRequest::abort() +{ + 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; + dispatchCallback(); + } + + m_state = Unsent; +} + +void QmlXMLHttpRequest::downloadProgress(qint64 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 (); + dispatchCallback(); + } + + bool wasEmpty = m_responseEntityBody.isEmpty(); + m_responseEntityBody.append(m_network->readAll()); + if (wasEmpty && !m_responseEntityBody.isEmpty()) { + m_state = Loading; + dispatchCallback(); + } +} + +void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error) +{ + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + m_responseEntityBody = QByteArray(); + m_errorFlag = true; + m_request = QNetworkRequest(); + + destroyNetwork(); + + m_state = Done; + dispatchCallback(); +} + +void QmlXMLHttpRequest::finished() +{ + // ### We need to transparently redirect as dictated by the spec + + 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 (); + dispatchCallback(); + } + m_responseEntityBody.append(m_network->readAll()); + destroyNetwork(); + if (m_state < Loading) { + m_state = Loading; + dispatchCallback(); + } + m_state = Done; + dispatchCallback(); +} + + +QString QmlXMLHttpRequest::responseBody() const +{ + return QString::fromUtf8(m_responseEntityBody); +} + +void QmlXMLHttpRequest::dispatchCallback() +{ + m_callback.call(); +} + +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) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() < 2 || context->argumentCount() > 5) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("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")) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Unsupported method")); + + + // Argument 1 - URL + QUrl url(context->argument(1).toString()); // ### Need to resolve correctly + + if (url.isRelative()) { + QmlContext *ctxt = QmlEnginePrivate::get(engine)->currentExpression?QmlEnginePrivate::get(engine)->currentExpression->context():0; + if (ctxt) + url = ctxt->resolvedUrl(url); + else + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Relative URLs not supported")); + } + + // Argument 2 - async (optional) + if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Synchronous call 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); + + request->open(method, url); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() != 2) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + + + if (request->readyState() != QmlXMLHttpRequest::Opened || + request->sendFlag()) + return context->throwError(INVALID_STATE_ERR, QLatin1String("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 *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() != QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + if (request->sendFlag()) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + QByteArray data; + if (context->argumentCount() > 0) + data = context->argument(0).toString().toUtf8(); + + request->send(data); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + request->abort(); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() != 1) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done && + request->readyState() != QmlXMLHttpRequest::HeadersReceived) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + QString headerName = context->argument(0).toString(); + + return QScriptValue(request->header(headerName)); +} + +static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount() != 0) + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); + + if (request->readyState() != QmlXMLHttpRequest::Loading && + request->readyState() != QmlXMLHttpRequest::Done && + request->readyState() != QmlXMLHttpRequest::HeadersReceived) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + return QScriptValue(request->headers()); +} + +// XMLHttpRequest properties +static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + return QScriptValue(request->readyState()); +} + +static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatus()); +} + +static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (request->readyState() == QmlXMLHttpRequest::Unsent || + request->readyState() == QmlXMLHttpRequest::Opened) + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatusText()); +} + +static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("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) return context->throwError(QScriptContext::ReferenceError, QLatin1String("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) +{ + QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); + + if (context->argumentCount()) + request->setCallback(context->argument(0)); + + return request->callback(); +} + +// Constructor +static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine) +{ + if (context->isCalledAsConstructor()) { + context->thisObject().setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), 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); + + // 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); +} + +#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..2142bc6 --- /dev/null +++ b/src/declarative/qml/qmlxmlhttprequest_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..77f7425 --- /dev/null +++ b/src/declarative/qml/qpodvector_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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> + +QT_BEGIN_NAMESPACE + +template<class T> +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 += 1024; + 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 insertBlank(int idx, int count) { + int newSize = m_count + count; + if (newSize >= m_capacity) { + m_capacity = (newSize + 1023) & 0xFFFFFC00; + m_data = (T *)realloc(m_data, m_capacity * sizeof(T)); + } + + 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; + } + + int count() const { + return m_count; + } + + void copyAndClear(QPODVector<T> &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> &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..1248a1c --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..550741b --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter.pri @@ -0,0 +1,11 @@ + +INCLUDEPATH += $$PWD +DEPENDPATH += $$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..ae59226 --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REWRITER_H +#define REWRITER_H + +#include <QtCore/QList> +#include <QtCore/QString> + +#include "textwriter_p.h" +#include "qmljsastvisitor_p.h" + +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..1ec0675 --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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..5894e6c --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTWRITER_H +#define TEXTWRITER_H + +#include <QtCore/QString> +#include <QtCore/QList> +#include <QtGui/QTextCursor> + +#include "qmljsglobal_p.h" + +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 |