diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/script | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'src/script')
117 files changed, 47542 insertions, 0 deletions
diff --git a/src/script/instruction.table b/src/script/instruction.table new file mode 100644 index 0000000..389db18 --- /dev/null +++ b/src/script/instruction.table @@ -0,0 +1,87 @@ +Q_SCRIPT_DEFINE_OPERATOR(Add) +Q_SCRIPT_DEFINE_OPERATOR(Assign) +Q_SCRIPT_DEFINE_OPERATOR(BitAnd) +Q_SCRIPT_DEFINE_OPERATOR(BitOr) +Q_SCRIPT_DEFINE_OPERATOR(BitXor) +Q_SCRIPT_DEFINE_OPERATOR(BitNot) +Q_SCRIPT_DEFINE_OPERATOR(Branch) +Q_SCRIPT_DEFINE_OPERATOR(BranchTrue) +Q_SCRIPT_DEFINE_OPERATOR(BranchFalse) +Q_SCRIPT_DEFINE_OPERATOR(Call) +Q_SCRIPT_DEFINE_OPERATOR(DeclareLocal) +Q_SCRIPT_DEFINE_OPERATOR(Decr) +Q_SCRIPT_DEFINE_OPERATOR(Delete) +Q_SCRIPT_DEFINE_OPERATOR(Div) +Q_SCRIPT_DEFINE_OPERATOR(Duplicate) +Q_SCRIPT_DEFINE_OPERATOR(EnterWith) +Q_SCRIPT_DEFINE_OPERATOR(Equal) +Q_SCRIPT_DEFINE_OPERATOR(Fetch) +Q_SCRIPT_DEFINE_OPERATOR(FetchField) +Q_SCRIPT_DEFINE_OPERATOR(LazyArguments) +Q_SCRIPT_DEFINE_OPERATOR(GreatOrEqual) +Q_SCRIPT_DEFINE_OPERATOR(GreatThan) +Q_SCRIPT_DEFINE_OPERATOR(HasNextElement) +Q_SCRIPT_DEFINE_OPERATOR(In) +Q_SCRIPT_DEFINE_OPERATOR(Incr) +Q_SCRIPT_DEFINE_OPERATOR(InplaceAdd) +Q_SCRIPT_DEFINE_OPERATOR(InplaceAnd) +Q_SCRIPT_DEFINE_OPERATOR(InplaceDiv) +Q_SCRIPT_DEFINE_OPERATOR(InplaceLeftShift) +Q_SCRIPT_DEFINE_OPERATOR(InplaceMod) +Q_SCRIPT_DEFINE_OPERATOR(InplaceMul) +Q_SCRIPT_DEFINE_OPERATOR(InplaceOr) +Q_SCRIPT_DEFINE_OPERATOR(InplaceRightShift) +Q_SCRIPT_DEFINE_OPERATOR(InplaceSub) +Q_SCRIPT_DEFINE_OPERATOR(InplaceURightShift) +Q_SCRIPT_DEFINE_OPERATOR(InstanceOf) +Q_SCRIPT_DEFINE_OPERATOR(LeaveWith) +Q_SCRIPT_DEFINE_OPERATOR(LeftShift) +Q_SCRIPT_DEFINE_OPERATOR(LessOrEqual) +Q_SCRIPT_DEFINE_OPERATOR(LessThan) +Q_SCRIPT_DEFINE_OPERATOR(LoadFalse) +Q_SCRIPT_DEFINE_OPERATOR(LoadString) +Q_SCRIPT_DEFINE_OPERATOR(LoadNumber) +Q_SCRIPT_DEFINE_OPERATOR(LoadThis) +Q_SCRIPT_DEFINE_OPERATOR(LoadActivation) +Q_SCRIPT_DEFINE_OPERATOR(LoadNull) +Q_SCRIPT_DEFINE_OPERATOR(LoadTrue) +Q_SCRIPT_DEFINE_OPERATOR(LoadUndefined) +Q_SCRIPT_DEFINE_OPERATOR(Mod) +Q_SCRIPT_DEFINE_OPERATOR(Mul) +Q_SCRIPT_DEFINE_OPERATOR(New) +Q_SCRIPT_DEFINE_OPERATOR(NewArray) +Q_SCRIPT_DEFINE_OPERATOR(NewClosure) +Q_SCRIPT_DEFINE_OPERATOR(NewEnumeration) +Q_SCRIPT_DEFINE_OPERATOR(NewObject) +Q_SCRIPT_DEFINE_OPERATOR(NewRegExp) +Q_SCRIPT_DEFINE_OPERATOR(NextElement) +Q_SCRIPT_DEFINE_OPERATOR(Nop) +Q_SCRIPT_DEFINE_OPERATOR(Not) +Q_SCRIPT_DEFINE_OPERATOR(NotEqual) +Q_SCRIPT_DEFINE_OPERATOR(Pop) +Q_SCRIPT_DEFINE_OPERATOR(PostDecr) +Q_SCRIPT_DEFINE_OPERATOR(PostIncr) +Q_SCRIPT_DEFINE_OPERATOR(PutField) +Q_SCRIPT_DEFINE_OPERATOR(Receive) +Q_SCRIPT_DEFINE_OPERATOR(Resolve) +Q_SCRIPT_DEFINE_OPERATOR(Ret) +Q_SCRIPT_DEFINE_OPERATOR(RightShift) +Q_SCRIPT_DEFINE_OPERATOR(StrictEqual) +Q_SCRIPT_DEFINE_OPERATOR(StrictNotEqual) +Q_SCRIPT_DEFINE_OPERATOR(Sub) +Q_SCRIPT_DEFINE_OPERATOR(Swap) +Q_SCRIPT_DEFINE_OPERATOR(ToFirstElement) +Q_SCRIPT_DEFINE_OPERATOR(Throw) +Q_SCRIPT_DEFINE_OPERATOR(TypeOf) +Q_SCRIPT_DEFINE_OPERATOR(UnaryMinus) +Q_SCRIPT_DEFINE_OPERATOR(UnaryPlus) +Q_SCRIPT_DEFINE_OPERATOR(URightShift) +Q_SCRIPT_DEFINE_OPERATOR(InplaceXor) +Q_SCRIPT_DEFINE_OPERATOR(Line) +Q_SCRIPT_DEFINE_OPERATOR(Sync) +Q_SCRIPT_DEFINE_OPERATOR(Halt) +Q_SCRIPT_DEFINE_OPERATOR(BeginCatch) +Q_SCRIPT_DEFINE_OPERATOR(EndCatch) +Q_SCRIPT_DEFINE_OPERATOR(MakeReference) +Q_SCRIPT_DEFINE_OPERATOR(NewString) +Q_SCRIPT_DEFINE_OPERATOR(Debugger) diff --git a/src/script/qscript.g b/src/script/qscript.g new file mode 100644 index 0000000..8bf0ce6 --- /dev/null +++ b/src/script/qscript.g @@ -0,0 +1,2123 @@ +---------------------------------------------------------------------------- +-- +-- 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$ +-- +-- 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 QScriptGrammar +%decl qscriptparser_p.h +%impl qscriptparser.cpp +%expect 3 +%expect-rr 1 + +%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_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" + +%start Program + +/. +/**************************************************************************** +** +** 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> + +#ifndef QT_NO_SCRIPT + +#include <string.h> + +#include "qscriptengine.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptlexer_p.h" +#include "qscriptast_p.h" +#include "qscriptnodepool_p.h" + +#define Q_SCRIPT_UPDATE_POSITION(node, startloc, endloc) do { \ + node->startLine = startloc.startLine; \ + node->startColumn = startloc.startColumn; \ + node->endLine = endloc.endLine; \ + node->endColumn = endloc.endColumn; \ +} while (0) + +./ + +/: +/**************************************************************************** +** +** 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 qscript.g. +// Changes will be lost. +// + +#ifndef QSCRIPTPARSER_P_H +#define QSCRIPTPARSER_P_H + +#include "qscriptgrammar_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptastfwd_p.h" + +QT_BEGIN_NAMESPACE + +class QString; +class QScriptEnginePrivate; +class QScriptNameIdImpl; + +class QScriptParser: protected $table +{ +public: + union Value { + int ival; + double dval; + QScriptNameIdImpl *sval; + QScript::AST::ArgumentList *ArgumentList; + QScript::AST::CaseBlock *CaseBlock; + QScript::AST::CaseClause *CaseClause; + QScript::AST::CaseClauses *CaseClauses; + QScript::AST::Catch *Catch; + QScript::AST::DefaultClause *DefaultClause; + QScript::AST::ElementList *ElementList; + QScript::AST::Elision *Elision; + QScript::AST::ExpressionNode *Expression; + QScript::AST::Finally *Finally; + QScript::AST::FormalParameterList *FormalParameterList; + QScript::AST::FunctionBody *FunctionBody; + QScript::AST::FunctionDeclaration *FunctionDeclaration; + QScript::AST::Node *Node; + QScript::AST::PropertyName *PropertyName; + QScript::AST::PropertyNameAndValueList *PropertyNameAndValueList; + QScript::AST::SourceElement *SourceElement; + QScript::AST::SourceElements *SourceElements; + QScript::AST::Statement *Statement; + QScript::AST::StatementList *StatementList; + QScript::AST::VariableDeclaration *VariableDeclaration; + QScript::AST::VariableDeclarationList *VariableDeclarationList; + }; + + struct Location { + int startLine; + int startColumn; + int endLine; + int endColumn; + }; + +public: + QScriptParser(); + ~QScriptParser(); + + bool parse(QScriptEnginePrivate *driver); + + inline QString errorMessage() const + { return error_message; } + inline int errorLineNumber() const + { return error_lineno; } + inline int errorColumnNumber() const + { return error_column; } + +protected: + inline void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline Location &loc(int index) + { return location_stack [tos + index - 2]; } + +protected: + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + Location *location_stack; + QString error_message; + int error_lineno; + int error_column; +}; + +inline void QScriptParser::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<Location*> (qRealloc(location_stack, stack_size * sizeof(Location))); +} + +:/ + + +/. + +#include "qscriptparser_p.h" + +// +// This file is automatically generated from qscript.g. +// Changes will be lost. +// + +QT_BEGIN_NAMESPACE + +inline static bool automatic(QScriptEnginePrivate *driver, int token) +{ + return token == $table::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +QScriptParser::QScriptParser(): + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + error_lineno(0), + error_column(0) +{ +} + +QScriptParser::~QScriptParser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline QScriptParser::Location location(QScript::Lexer *lexer) +{ + QScriptParser::Location loc; + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + loc.endLine = lexer->endLineNo(); + loc.endColumn = lexer->endColumnNo(); + return loc; +} + +bool QScriptParser::parse(QScriptEnginePrivate *driver) +{ + const int INITIAL_STATE = 0; + QScript::Lexer *lexer = driver->lexer(); + + int yytoken = -1; + int saved_yytoken = -1; + + reallocateStack(); + + tos = 0; + state_stack[++tos] = INITIAL_STATE; + + while (true) + { + const int state = state_stack [tos]; + if (yytoken == -1 && - TERMINAL_COUNT != action_index [state]) + { + if (saved_yytoken == -1) + { + yytoken = lexer->lex(); + location_stack [tos] = location(lexer); + } + else + { + yytoken = saved_yytoken; + saved_yytoken = -1; + } + } + + int act = t_action (state, yytoken); + + if (act == ACCEPT_STATE) + return true; + + else if (act > 0) + { + if (++tos == stack_size) + reallocateStack(); + + sym_stack [tos].dval = lexer->dval (); + state_stack [tos] = act; + location_stack [tos] = location(lexer); + yytoken = -1; + } + + else if (act < 0) + { + int r = - act - 1; + + tos -= rhs [r]; + act = state_stack [tos++]; + + switch (r) { +./ + +PrimaryExpression: T_THIS ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ThisExpression> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_IDENTIFIER ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_NULL ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NullExpression> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_TRUE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TrueLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_FALSE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FalseLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_STRING_LITERAL ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StringLiteral> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_DIVIDE_ ; +/: +#define Q_SCRIPT_REGEXPLITERAL_RULE1 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(QScript::Lexer::NoPrefix); + if (!rx) { + error_message = lexer->errorMessage(); + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + return false; + } + sym(1).Node = QScript::makeAstNode<QScript::AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_DIVIDE_EQ ; +/: +#define Q_SCRIPT_REGEXPLITERAL_RULE2 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(QScript::Lexer::EqualPrefix); + if (!rx) { + error_message = lexer->errorMessage(); + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + return false; + } + sym(1).Node = QScript::makeAstNode<QScript::AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PrimaryExpression: T_LBRACKET ElisionOpt T_RBRACKET ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA ElisionOpt T_RBRACKET ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +-- PrimaryExpression: T_LBRACE T_RBRACE ; +-- /. +-- case $rule_number: { +-- sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool()); +-- Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +-- } break; +-- ./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; +/. +case $rule_number: { + if (sym(2).Node) + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); + else + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +PrimaryExpression: T_LPAREN Expression T_RPAREN ; +/. +case $rule_number: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ElementList: ElisionOpt AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ElementList> (driver->nodePool(), sym(1).Elision, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +ElementList: ElementList T_COMMA ElisionOpt AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision, sym(4).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +Elision: T_COMMA ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Elision> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +Elision: Elision T_COMMA ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Elision> (driver->nodePool(), sym(1).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +ElisionOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ElisionOpt: Elision ; +/. +case $rule_number: { + sym(1).Elision = sym(1).Elision->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyName, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +PropertyName: T_IDENTIFIER ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PropertyName: T_STRING_LITERAL ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PropertyName: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +PropertyName: ReservedIdentifier ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} 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: T_IDENTIFIER ; +PropertyIdentifier: ReservedIdentifier ; + +MemberExpression: PrimaryExpression ; +MemberExpression: FunctionExpression ; + +MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +MemberExpression: MemberExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +MemberExpression: T_NEW MemberExpression Arguments ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(3).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +NewExpression: MemberExpression ; + +NewExpression: T_NEW NewExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NewExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +CallExpression: MemberExpression Arguments ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(2).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +CallExpression: CallExpression Arguments ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(2).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +CallExpression: CallExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +Arguments: T_LPAREN T_RPAREN ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +Arguments: T_LPAREN ArgumentList T_RPAREN ; +/. +case $rule_number: { + sym(1).Node = sym(2).ArgumentList->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ArgumentList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArgumentList> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +ArgumentList: ArgumentList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LeftHandSideExpression: NewExpression ; +LeftHandSideExpression: CallExpression ; +PostfixExpression: LeftHandSideExpression ; + +PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: PostfixExpression ; + +UnaryExpression: T_DELETE UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_VOID UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_TYPEOF UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_PLUS_PLUS UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_MINUS_MINUS UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_PLUS UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_MINUS UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_TILDE UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +UnaryExpression: T_NOT UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NotExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +MultiplicativeExpression: UnaryExpression ; + +MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mul, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Div, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mod, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +AdditiveExpression: MultiplicativeExpression ; + +AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Add, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Sub, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ShiftExpression: AdditiveExpression ; + +ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::LShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::RShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::URShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: ShiftExpression ; + +RelationalExpression: RelationalExpression T_LT ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: RelationalExpression T_GT ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: RelationalExpression T_LE ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: RelationalExpression T_GE ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpression: RelationalExpression T_IN ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::In, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpressionNotIn: ShiftExpression ; + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpression: RelationalExpression ; + +EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpressionNotIn: RelationalExpressionNotIn ; + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseANDExpression: EqualityExpression ; + +BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseANDExpressionNotIn: EqualityExpressionNotIn ; + +BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseXORExpression: BitwiseANDExpression ; + +BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ; + +BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseORExpression: BitwiseXORExpression ; + +BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ; + +BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LogicalANDExpression: BitwiseORExpression ; + +LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ; + +LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LogicalORExpression: LogicalANDExpression ; + +LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LogicalORExpressionNotIn: LogicalANDExpressionNotIn ; + +LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ConditionalExpression: LogicalORExpression ; + +ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ConditionalExpressionNotIn: LogicalORExpressionNotIn ; + +ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +AssignmentExpression: ConditionalExpression ; + +AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +AssignmentExpressionNotIn: ConditionalExpressionNotIn ; + +AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} 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: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ExpressionOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ExpressionOpt: Expression ; + +ExpressionNotIn: AssignmentExpressionNotIn ; + +ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} 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: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Block> (driver->nodePool(), sym(2).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +StatementList: Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementList> (driver->nodePool(), sym(1).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +StatementList: StatementList Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} 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: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableStatement> (driver->nodePool(), sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} 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 = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +VariableDeclaration: T_IDENTIFIER InitialiserOpt ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +VariableDeclarationNotIn: T_IDENTIFIER InitialiserNotInOpt ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +Initialiser: T_EQ AssignmentExpression ; +/. +case $rule_number: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +InitialiserOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserOpt: Initialiser ; + +InitialiserNotIn: T_EQ AssignmentExpressionNotIn ; +/. +case $rule_number: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +InitialiserNotInOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserNotInOpt: InitialiserNotIn ; + +EmptyStatement: T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::EmptyStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ExpressionStatement: Expression T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} 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: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; +./ + +IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ForStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(9)); +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LocalForStatement> (driver->nodePool(), sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(10)); +} break; +./ + +IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LocalForEachStatement> (driver->nodePool(), sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; +./ + +ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ContinueStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +ContinueStatement: T_CONTINUE T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BreakStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +BreakStatement: T_BREAK T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BreakStatement> (driver->nodePool(), sym(2).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +CaseClauses: CaseClause ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +CaseClauses: CaseClauses CaseClause ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +CaseClausesOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +CaseClausesOpt: CaseClauses ; +/. +case $rule_number: { + sym(1).Node = sym(1).CaseClauses->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +CaseClause: T_CASE Expression T_COLON StatementListOpt ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +DefaultClause: T_DEFAULT T_COLON StatementListOpt ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +LabelledStatement: T_IDENTIFIER T_COLON Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ThrowStatement: T_THROW Expression T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +TryStatement: T_TRY Block Catch ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +TryStatement: T_TRY Block Finally ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +TryStatement: T_TRY Block Catch Finally ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; +./ + +Catch: T_CATCH T_LPAREN T_IDENTIFIER T_RPAREN Block ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; +./ + +Finally: T_FINALLY Block ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Finally> (driver->nodePool(), sym(2).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +DebuggerStatement: T_DEBUGGER T_SEMICOLON ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DebuggerStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +FunctionDeclaration: T_FUNCTION T_IDENTIFIER T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; +./ + +FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; +./ + +FormalParameterList: T_IDENTIFIER ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +FormalParameterList: FormalParameterList T_COMMA T_IDENTIFIER ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; +./ + +FormalParameterListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FormalParameterListOpt: FormalParameterList ; +/. +case $rule_number: { + sym(1).Node = sym(1).FormalParameterList->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +FunctionBodyOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FunctionBodyOpt: FunctionBody ; + +FunctionBody: SourceElements ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +Program: SourceElements ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); + driver->changeAbstractSyntaxTree(sym(1).Node); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +SourceElements: SourceElement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +SourceElements: SourceElements SourceElement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; +./ + +SourceElement: Statement ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +SourceElement: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; +./ + +IdentifierOpt: ; +/. +case $rule_number: { + sym(1).sval = 0; +} break; +./ + +IdentifierOpt: T_IDENTIFIER ; + +PropertyNameAndValueListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +PropertyNameAndValueListOpt: PropertyNameAndValueList ; + +/. + } // switch + + state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); + + if (rhs[r] > 1) { + location_stack[tos - 1].endLine = location_stack[tos + rhs[r] - 2].endLine; + location_stack[tos - 1].endColumn = location_stack[tos + rhs[r] - 2].endColumn; + location_stack[tos] = location_stack[tos + rhs[r] - 1]; + } + } + + else + { + if (saved_yytoken == -1 && automatic (driver, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0) + { + saved_yytoken = yytoken; + yytoken = T_SEMICOLON; + continue; + } + + else if ((state == INITIAL_STATE) && (yytoken == 0)) { + // accept empty input + yytoken = T_SEMICOLON; + continue; + } + + int ers = state; + int shifts = 0; + int reduces = 0; + int expected_tokens [3]; + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) + { + int k = t_action (ers, tk); + + if (! k) + continue; + else if (k < 0) + ++reduces; + else if (spell [tk]) + { + if (shifts < 3) + expected_tokens [shifts] = tk; + ++shifts; + } + } + + error_message.clear (); + if (shifts && shifts < 3) + { + bool first = true; + + for (int s = 0; s < shifts; ++s) + { + if (first) + error_message += QLatin1String ("Expected "); + else + error_message += QLatin1String (", "); + + first = false; + error_message += QLatin1String("`"); + error_message += QLatin1String (spell [expected_tokens [s]]); + error_message += QLatin1String("'"); + } + } + + if (error_message.isEmpty()) + error_message = lexer->errorMessage(); + + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + + return false; + } + } + + return false; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +./ +/: +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTPARSER_P_H +:/ diff --git a/src/script/qscriptable.cpp b/src/script/qscriptable.cpp new file mode 100644 index 0000000..a6401d6 --- /dev/null +++ b/src/script/qscriptable.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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 QT_NO_QOBJECT + +#include "qscriptable.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptable_p.h" + +#include "qscriptengine.h" +#include "qscriptcontext.h" +#include "qscriptvalue.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptable + + \brief The QScriptable class provides access to the Qt Script environment from Qt C++ member functions. + + \ingroup script + \mainclass + + With QScriptEngine::newQObject(), you can expose the signals and + slots and properties of any QObject (or subclass) to script + code. QScriptable augments this functionality by giving your C++ + members access to the Qt Script environment they are invoked in; + conceptually, it is similar to QObject::sender(). + + By subclassing QScriptable, you get the following functions in your + class: thisObject(), argumentCount(), argument(), context() and + engine(). With these functions, you have full access to the Qt + Script environment from the slots and property access functions of + your class, when they are invoked from script code. + + For example, you can throw a Qt Script exception from a slot; + manipulate the `this' object associated with the function call; + inspect the arguments stored in the QScriptContext to know the + "real" arguments passed to the function from script code; and call + script functions from your slot. + + A typical use case of QScriptable is to implement prototype objects + for custom C++ types. You define the scriptable interface of your + custom type in a QScriptable subclass using properties and slots; + then you wrap an instance of your class using + QScriptEngine::newQObject(), and finally pass the result to + QScriptEngine::setDefaultPrototype(). See the \l{Default Prototypes Example} + to see how this can be done. + + The following is what subclassing QScriptable typically looks + like: + + \snippet doc/src/snippets/code/src_script_qscriptable.cpp 0 + + The only difference from regular QObject subclassing is that you + also inherit from QScriptable. + + In the implementation of your slots, you can then use the functions + inherited from QScriptable: + + \snippet doc/src/snippets/code/src_script_qscriptable.cpp 1 + + \sa {Default Prototypes Example}, QScriptEngine::newFunction() +*/ + +/*! + \internal +*/ +QScriptable::QScriptable() + : d_ptr(new QScriptablePrivate()) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QScriptable::~QScriptable() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Returns a pointer to the QScriptEngine associated with the current + Qt function call, or 0 if the Qt function was not invoked from + script code. +*/ +QScriptEngine *QScriptable::engine() const +{ + Q_D(const QScriptable); + return d->engine; +} + +/*! + Returns a pointer to the QScriptContext associated with the current + Qt function call, or 0 if the Qt function was not invoked from + script code. +*/ +QScriptContext *QScriptable::context() const +{ + if (QScriptEngine *e = engine()) + return e->currentContext(); + + return 0; +} + +/*! + Returns the `this' object associated with the current Qt function + call, or an invalid QScriptValue if the Qt function was not invoked + from script code. +*/ + +QScriptValue QScriptable::thisObject() const +{ + if (QScriptContext *c = context()) + return c->thisObject(); + + return QScriptValue(); +} + +/*! + Returns the number of arguments passed to the function in this + invocation, or -1 if the Qt function was not invoked from script + code. + + \sa argument() +*/ +int QScriptable::argumentCount() const +{ + if (QScriptContext *c = context()) + return c->argumentCount(); + + return -1; +} + +/*! + Returns the function argument at the given \a index, or an invalid + QScriptValue if the Qt function was not invoked from script code. + + \sa argumentCount() +*/ +QScriptValue QScriptable::argument(int index) const +{ + if (QScriptContext *c = context()) + return c->argument(index); + + return QScriptValue(); +} + +#endif // QT_NO_SCRIPT +#endif // QT_NO_QOBJECT + +QT_END_NAMESPACE diff --git a/src/script/qscriptable.h b/src/script/qscriptable.h new file mode 100644 index 0000000..f990db2 --- /dev/null +++ b/src/script/qscriptable.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 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 QSCRIPTABLE_H +#define QSCRIPTABLE_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +#ifndef QT_NO_QOBJECT + +class QScriptEngine; +class QScriptContext; +class QScriptValue; + +class QScriptablePrivate; + +class Q_SCRIPT_EXPORT QScriptable +{ +public: + QScriptable(); + ~QScriptable(); + + QScriptEngine *engine() const; + QScriptContext *context() const; + QScriptValue thisObject() const; + int argumentCount() const; + QScriptValue argument(int index) const; + +private: + QScriptablePrivate *d_ptr; + + Q_DISABLE_COPY(QScriptable) + Q_DECLARE_PRIVATE(QScriptable) +}; + +#endif // QT_NO_QOBJECT + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTABLE_H diff --git a/src/script/qscriptable_p.h b/src/script/qscriptable_p.h new file mode 100644 index 0000000..2343fc4 --- /dev/null +++ b/src/script/qscriptable_p.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 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 QSCRIPTABLE_P_H +#define QSCRIPTABLE_P_H + +#include <QtCore/qobjectdefs.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. +// + +#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_SCRIPT) + +QT_BEGIN_NAMESPACE + +class QScriptEngine; + +class QScriptablePrivate +{ + Q_DECLARE_PUBLIC(QScriptable) +public: + inline QScriptablePrivate() + : engine(0) + { } + + static inline QScriptablePrivate *get(QScriptable *q) + { return q->d_func(); } + + QScriptEngine *engine; + + QScriptable *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_QOBJECT && QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptarray_p.h b/src/script/qscriptarray_p.h new file mode 100644 index 0000000..0079b30 --- /dev/null +++ b/src/script/qscriptarray_p.h @@ -0,0 +1,428 @@ +/**************************************************************************** +** +** 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 QSCRIPTARRAY_P_H +#define QSCRIPTARRAY_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/QMap> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/QVector> + +#include "qscriptvalueimplfwd_p.h" +#include "qscriptenginefwd_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + +class Array +{ +public: + inline Array(QScriptEnginePrivate *engine); + inline Array(const Array &other); + inline ~Array(); + + inline Array &operator = (const Array &other); + + inline bool isEmpty() const; + inline uint size() const; + inline uint count() const; + inline QScriptValueImpl at(uint index) const; + inline void assign(uint index, const QScriptValueImpl &v); + inline void clear(); + inline void mark(int generation); + inline void resize(uint size); + inline void concat(const Array &other); + inline QScriptValueImpl pop(); + inline void sort(const QScriptValueImpl &comparefn); + inline void splice(qsreal start, qsreal deleteCount, + const QVector<QScriptValueImpl> &items, + Array &other); + inline QList<uint> keys() const; + +private: + enum Mode { + VectorMode, + MapMode + }; + + QScriptEnginePrivate *m_engine; + Mode m_mode; + int m_instances; + + union { + QMap<uint, QScriptValueImpl> *to_map; + QVector<QScriptValueImpl> *to_vector; + }; +}; + +class ArrayElementLessThan +{ +public: + inline ArrayElementLessThan(const QScriptValueImpl &comparefn) + : m_comparefn(comparefn) {} + + inline bool operator()(const QScriptValueImpl &v1, const QScriptValueImpl &v2) const + { + if (!v1.isValid() || v1.isUndefined()) + return false; + if (!v2.isValid() || v2.isUndefined()) + return true; + if (!m_comparefn.isUndefined()) { + ArrayElementLessThan *that = const_cast<ArrayElementLessThan*>(this); + QScriptValueImpl result = that->m_comparefn.call(QScriptValueImpl(), + QScriptValueImplList() << v1 << v2); + return result.toNumber() <= 0; + } + return v1.toString() < v2.toString(); + } + +private: + QScriptValueImpl m_comparefn; +}; + +} // namespace QScript + +inline QScript::Array::Array(QScriptEnginePrivate *engine): + m_engine(engine), + m_mode(VectorMode), + m_instances(0) +{ + to_vector = new QVector<QScriptValueImpl>(); +} + +inline QScript::Array::Array(const Array &other): + m_engine(other.m_engine), + m_mode(other.m_mode), + m_instances(other.m_instances) +{ + if (m_mode == VectorMode) + to_vector = new QVector<QScriptValueImpl> (*other.to_vector); + else + to_map = new QMap<uint, QScriptValueImpl> (*other.to_map); +} + +inline QScript::Array::~Array() +{ + if (m_mode == VectorMode) + delete to_vector; + else + delete to_map; +} + +inline QScript::Array &QScript::Array::operator = (const Array &other) +{ + m_engine = other.m_engine; + m_instances = other.m_instances; + if (m_mode != other.m_mode) { + if (m_mode == VectorMode) + delete to_vector; + else + delete to_map; + m_mode = other.m_mode; + + if (m_mode == VectorMode) + to_vector = new QVector<QScriptValueImpl> (*other.to_vector); + else + to_map = new QMap<uint, QScriptValueImpl> (*other.to_map); + } + + if (m_mode == VectorMode) + *to_vector = *other.to_vector; + else + *to_map = *other.to_map; + + return *this; +} + +inline bool QScript::Array::isEmpty() const +{ + if (m_mode == VectorMode) + return to_vector->isEmpty(); + + return to_map->isEmpty(); +} + +inline uint QScript::Array::size() const +{ + if (m_mode == VectorMode) + return to_vector->size(); + + if (to_map->isEmpty()) + return 0; + + return (--to_map->constEnd()).key(); +} + +inline uint QScript::Array::count() const +{ + return size(); +} + +inline QScriptValueImpl QScript::Array::at(uint index) const +{ + if (m_mode == VectorMode) { + if (index < uint(to_vector->size())) + return to_vector->at(index); + return QScriptValueImpl(); + } else { + return to_map->value(index, QScriptValueImpl()); + } +} + +inline void QScript::Array::assign(uint index, const QScriptValueImpl &v) +{ + if (index >= size()) { + resize(index + 1); + if (v.isValid() && m_engine) + m_engine->adjustBytesAllocated(sizeof(QScriptValueImpl) * (size() - index)); + } + + const QScriptValueImpl &oldv = at(index); + if (oldv.isValid() && (oldv.isObject() || oldv.isString())) + --m_instances; + + if (v.isValid() && (v.isObject() || v.isString())) + ++m_instances; + + if (m_mode == VectorMode) { + to_vector->replace(index, v); + } else { + if (!v.isValid()) + to_map->remove(index); + else + to_map->insert(index, v); + } +} + +inline void QScript::Array::clear() +{ + m_instances = 0; + + if (m_mode == VectorMode) + to_vector->clear(); + + else + to_map->clear(); +} + +inline void QScript::Array::mark(int generation) +{ + if (! m_instances) + return; + + if (m_mode == VectorMode) { + for (int i = 0; i < to_vector->size(); ++i) + to_vector->at(i).mark(generation); + } else { + QMap<uint, QScriptValueImpl>::const_iterator it = to_map->constBegin(); + for (; it != to_map->constEnd(); ++it) + it.value().mark(generation); + } +} + +inline void QScript::Array::resize(uint s) +{ + const uint oldSize = size(); + if (oldSize == s) + return; + + const uint N = 10 * 1024; + + if (m_mode == VectorMode) { + if (s < N) { + to_vector->resize (s); + } else { + // switch to MapMode + QMap<uint, QScriptValueImpl> *m = new QMap<uint, QScriptValueImpl>(); + for (uint i = 0; i < oldSize; ++i) { + if (to_vector->at(i).isValid()) + m->insert(i, to_vector->at(i)); + } + m->insert(s, QScriptValueImpl()); + delete to_vector; + to_map = m; + m_mode = MapMode; + } + } + + else { + if (s < N) { + // switch to VectorMode + QVector<QScriptValueImpl> *v = new QVector<QScriptValueImpl> (s); + QMap<uint, QScriptValueImpl>::const_iterator it = to_map->constBegin(); + for ( ; (it != to_map->constEnd()) && (it.key() < s); ++it) + (*v) [it.key()] = it.value(); + delete to_map; + to_vector = v; + m_mode = VectorMode; + } else { + if (!to_map->isEmpty()) { + QMap<uint, QScriptValueImpl>::iterator it = --to_map->end(); + if (oldSize > s) { + // shrink + while ((it != to_map->end()) && (it.key() >= s)) { + it = to_map->erase(it); + --it; + } + } else { + if ((it.key() == oldSize) && !it.value().isValid()) + to_map->erase(it); + } + } + to_map->insert(s, QScriptValueImpl()); + } + } +} + +inline void QScript::Array::concat(const QScript::Array &other) +{ + uint k = size(); + resize (k + other.size()); + for (uint i = 0; i < other.size(); ++i) { + QScriptValueImpl v = other.at(i); + if (! v.isValid()) + continue; + + assign(k + i, v); + } +} + +inline QScriptValueImpl QScript::Array::pop() +{ + if (isEmpty()) + return QScriptValueImpl(); + + QScriptValueImpl v; + + if (m_mode == VectorMode) + v = to_vector->last(); + else + v = *--to_map->end(); + + resize(size() - 1); + + return v; +} + +inline void QScript::Array::sort(const QScriptValueImpl &comparefn) +{ + ArrayElementLessThan lessThan(comparefn); + if (m_mode == VectorMode) { + qSort(to_vector->begin(), to_vector->end(), lessThan); + } else { + QList<uint> keys = to_map->keys(); + QList<QScriptValueImpl> values = to_map->values(); + qStableSort(values.begin(), values.end(), lessThan); + const uint len = keys.size(); + for (uint i = 0; i < len; ++i) + to_map->insert(keys.at(i), values.at(i)); + } +} + +inline void QScript::Array::splice(qsreal start, qsreal deleteCount, + const QVector<QScriptValueImpl> &items, + Array &other) +{ + const qsreal len = size(); + if (start < 0) + start = qMax(len + start, qsreal(0)); + else if (start > len) + start = len; + deleteCount = qMax(qMin(deleteCount, len - start), qsreal(0)); + + const uint st = uint(start); + const uint dc = uint(deleteCount); + other.resize(dc); + + const uint itemsSize = uint(items.size()); + + if (m_mode == VectorMode) { + for (uint i = 0; i < dc; ++i) + other.assign(i, to_vector->at(st + i)); + if (itemsSize > dc) + to_vector->insert(st, itemsSize - dc, QScriptValueImpl()); + else if (itemsSize < dc) + to_vector->remove(st, dc - itemsSize); + for (uint i = 0; i < itemsSize; ++i) + to_vector->replace(st + i, items.at(i)); + } else { + for (uint i = 0; i < dc; ++i) + other.assign(i, to_map->take(st + i)); + uint del = itemsSize - dc; + if (del != 0) { + for (uint i = st; i < uint(len); ++i) { + if (to_map->contains(i)) + to_map->insert(i + del, to_map->take(i)); + } + resize(uint(len) + del); + } + for (uint i = 0; i < itemsSize; ++i) + to_map->insert(st + i, items.at(i)); + } +} + +inline QList<uint> QScript::Array::keys() const +{ + if (m_mode == VectorMode) + return QList<uint>(); + else + return to_map->keys(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTARRAY_P_H diff --git a/src/script/qscriptasm.cpp b/src/script/qscriptasm.cpp new file mode 100644 index 0000000..d898a38 --- /dev/null +++ b/src/script/qscriptasm.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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/QTextStream> + +#ifndef QT_NO_SCRIPT + +#include "qscriptasm_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +const char *QScriptInstruction::opcode[] = { +#define STR(a) #a +#define Q_SCRIPT_DEFINE_OPERATOR(op) STR(i##op) , +#include "instruction.table" +#undef Q_SCRIPT_DEFINE_OPERATOR +#undef STR +}; + +void QScriptInstruction::print(QTextStream &out) const +{ + out << opcode[op]; + + if (! operand[0].isValid()) + return; + + out << '(' << operand[0].toString(); + + if (operand[1].isValid()) + out << ", " << operand[1].toString(); + + out << ')'; +} + +namespace QScript { + +Code::Code(): + optimized(false), + firstInstruction(0), + lastInstruction(0), + astPool(0) +{ +} + +Code::~Code() +{ + delete[] firstInstruction; +} + +void Code::init(const CompilationUnit &compilation, NodePool *pool) +{ + optimized = false; + const QVector<QScriptInstruction> ilist = compilation.instructions(); + firstInstruction = new QScriptInstruction[ilist.count()]; + lastInstruction = firstInstruction + ilist.count(); + qCopy(ilist.begin(), ilist.end(), firstInstruction); + exceptionHandlers = compilation.exceptionHandlers(); + astPool = pool; +} + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptasm_p.h b/src/script/qscriptasm_p.h new file mode 100644 index 0000000..3f0058d --- /dev/null +++ b/src/script/qscriptasm_p.h @@ -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 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 QSCRIPTASM_P_H +#define QSCRIPTASM_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> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qvector.h> + +#include "qscriptvalueimplfwd_p.h" + +QT_BEGIN_NAMESPACE + +class QTextStream; + +class QScriptInstruction +{ +public: + enum Operator { +#define Q_SCRIPT_DEFINE_OPERATOR(op) OP_##op, +#include "instruction.table" +#undef Q_SCRIPT_DEFINE_OPERATOR + OP_Dummy + }; + +public: + Operator op; + QScriptValueImpl operand[2]; +#if defined(Q_SCRIPT_DIRECT_CODE) + void *code; +#endif + + void print(QTextStream &out) const; + + static const char *opcode[]; +}; + +namespace QScript { + +class NodePool; + +class ExceptionHandlerDescriptor +{ +public: + ExceptionHandlerDescriptor() + : m_startInstruction(0), + m_endInstruction(0), + m_handlerInstruction(0) {} + + ExceptionHandlerDescriptor( + int startInstruction, + int endInstruction, + int handlerInstruction) + : m_startInstruction(startInstruction), + m_endInstruction(endInstruction), + m_handlerInstruction(handlerInstruction) {} + + inline int startInstruction() const { return m_startInstruction; } + inline int endInstruction() const { return m_endInstruction; } + inline int handlerInstruction() const { return m_handlerInstruction; } + +private: + int m_startInstruction; + int m_endInstruction; + int m_handlerInstruction; +}; + +class CompilationUnit +{ +public: + CompilationUnit(): m_valid(true), + m_errorLineNumber(-1) {} + + bool isValid() const { return m_valid; } + + void setError(const QString &message, int lineNumber) + { + m_errorMessage = message; + m_errorLineNumber = lineNumber; + m_valid = false; + } + + QString errorMessage() const + { return m_errorMessage; } + int errorLineNumber() const + { return m_errorLineNumber; } + + QVector<QScriptInstruction> instructions() const + { return m_instructions; } + void setInstructions(const QVector<QScriptInstruction> &instructions) + { m_instructions = instructions; } + + QVector<ExceptionHandlerDescriptor> exceptionHandlers() const + { return m_exceptionHandlers; } + void setExceptionHandlers(const QVector<ExceptionHandlerDescriptor> &exceptionHandlers) + { m_exceptionHandlers = exceptionHandlers; } + +private: + bool m_valid; + QString m_errorMessage; + int m_errorLineNumber; + QVector<QScriptInstruction> m_instructions; + QVector<ExceptionHandlerDescriptor> m_exceptionHandlers; +}; + +class Code +{ +public: + Code(); + ~Code(); + + void init(const CompilationUnit &compilation, NodePool *astPool); + +public: // attributes + bool optimized; + QScriptInstruction *firstInstruction; + QScriptInstruction *lastInstruction; + QVector<ExceptionHandlerDescriptor> exceptionHandlers; + NodePool *astPool; + +private: + Q_DISABLE_COPY(Code) +}; + + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTASM_P_H diff --git a/src/script/qscriptast.cpp b/src/script/qscriptast.cpp new file mode 100644 index 0000000..defbd28 --- /dev/null +++ b/src/script/qscriptast.cpp @@ -0,0 +1,789 @@ +/**************************************************************************** +** +** 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 "qscriptast_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace AST { + +ExpressionNode *Node::expressionCast() +{ + return 0; +} + +BinaryExpression *Node::binaryExpressionCast() +{ + return 0; +} + +Statement *Node::statementCast() +{ + return 0; +} + +ExpressionNode *ExpressionNode::expressionCast() +{ + return this; +} + +BinaryExpression *BinaryExpression::binaryExpressionCast() +{ + return this; +} + +Statement *Statement::statementCast() +{ + return 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)) { + acceptChild(elements, visitor); + acceptChild(elision, visitor); + } + + visitor->endVisit(this); +} + +void ObjectLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(properties, visitor); + } + + visitor->endVisit(this); +} + +void ElementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + ElementList *it = this; + do { + acceptChild(it->elision, visitor); + acceptChild(it->expression, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void Elision::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + // ### + } + + visitor->endVisit(this); +} + +void PropertyNameAndValueList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + PropertyNameAndValueList *it = this; + do { + acceptChild(it->name, visitor); + acceptChild(it->value, visitor); + it = it->next; + } while (it); + } + + 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)) { + acceptChild(base, visitor); + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void FieldMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(base, visitor); + } + + visitor->endVisit(this); +} + +void NewMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(base, visitor); + acceptChild(arguments, visitor); + } + + visitor->endVisit(this); +} + +void NewExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void CallExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(base, visitor); + acceptChild(arguments, visitor); + } + + visitor->endVisit(this); +} + +void ArgumentList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + ArgumentList *it = this; + do { + acceptChild(it->expression, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void PostIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(base, visitor); + } + + visitor->endVisit(this); +} + +void PostDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(base, visitor); + } + + visitor->endVisit(this); +} + +void DeleteExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void VoidExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void TypeOfExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryPlusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryMinusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void TildeExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void NotExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void BinaryExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(left, visitor); + acceptChild(right, visitor); + } + + visitor->endVisit(this); +} + +void ConditionalExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(ok, visitor); + acceptChild(ko, visitor); + } + + visitor->endVisit(this); +} + +void Expression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(left, visitor); + acceptChild(right, visitor); + } + + visitor->endVisit(this); +} + +void Block::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statements, visitor); + } + + visitor->endVisit(this); +} + +void StatementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + StatementList *it = this; + do { + acceptChild(it->statement, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void VariableStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(declarations, visitor); + } + + visitor->endVisit(this); +} + +void VariableDeclarationList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + VariableDeclarationList *it = this; + do { + acceptChild(it->declaration, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void VariableDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(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)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void IfStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(ok, visitor); + acceptChild(ko, visitor); + } + + visitor->endVisit(this); +} + +void DoWhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void WhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(initialiser, visitor); + acceptChild(condition, visitor); + acceptChild(expression, visitor); + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(declarations, visitor); + acceptChild(condition, visitor); + acceptChild(expression, visitor); + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(initialiser, visitor); + acceptChild(expression, visitor); + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(declaration, visitor); + acceptChild(expression, visitor); + acceptChild(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)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void WithStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void SwitchStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(block, visitor); + } + + visitor->endVisit(this); +} + +void CaseBlock::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(clauses, visitor); + acceptChild(defaultClause, visitor); + acceptChild(moreClauses, visitor); + } + + visitor->endVisit(this); +} + +void CaseClauses::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + CaseClauses *it = this; + do { + acceptChild(it->clause, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void CaseClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + acceptChild(statements, visitor); + } + + visitor->endVisit(this); +} + +void DefaultClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statements, visitor); + } + + visitor->endVisit(this); +} + +void LabelledStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void ThrowStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(expression, visitor); + } + + visitor->endVisit(this); +} + +void TryStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + acceptChild(catchExpression, visitor); + acceptChild(finallyExpression, visitor); + } + + visitor->endVisit(this); +} + +void Catch::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void Finally::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void FunctionDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(formals, visitor); + acceptChild(body, visitor); + } + + visitor->endVisit(this); +} + +void FunctionExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(formals, visitor); + acceptChild(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)) { + acceptChild(elements, visitor); + } + + visitor->endVisit(this); +} + +void Program::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(elements, visitor); + } + + visitor->endVisit(this); +} + +void SourceElements::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + SourceElements *it = this; + do { + acceptChild(it->element, visitor); + it = it->next; + } while (it); + } + + visitor->endVisit(this); +} + +void FunctionSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(declaration, visitor); + } + + visitor->endVisit(this); +} + +void StatementSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + acceptChild(statement, visitor); + } + + visitor->endVisit(this); +} + +void DebuggerStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +} } // namespace QScript::AST + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptast_p.h b/src/script/qscriptast_p.h new file mode 100644 index 0000000..3d3128a --- /dev/null +++ b/src/script/qscriptast_p.h @@ -0,0 +1,1502 @@ +/**************************************************************************** +** +** 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 QSCRIPTAST_P_H +#define QSCRIPTAST_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> + +#ifndef QT_NO_SCRIPT + +#include "qscriptastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptNameIdImpl; + +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 QScript { namespace AST { + +class Node +{ +public: + enum Kind { + Kind_Node, + Kind_ExpressionNode, + Kind_Statement, + Kind_ThisExpression, + Kind_IdentifierExpression, + Kind_NullExpression, + Kind_TrueLiteral, + Kind_FalseLiteral, + Kind_NumericLiteral, + Kind_StringLiteral, + Kind_RegExpLiteral, + Kind_ArrayLiteral, + Kind_ObjectLiteral, + Kind_ElementList, + Kind_Elision, + Kind_PropertyNameAndValueList, + Kind_PropertyName, + Kind_IdentifierPropertyName, + Kind_StringLiteralPropertyName, + Kind_NumericLiteralPropertyName, + Kind_ArrayMemberExpression, + Kind_FieldMemberExpression, + Kind_NewMemberExpression, + Kind_NewExpression, + Kind_CallExpression, + Kind_ArgumentList, + Kind_PostIncrementExpression, + Kind_PostDecrementExpression, + Kind_DeleteExpression, + Kind_VoidExpression, + Kind_TypeOfExpression, + Kind_PreIncrementExpression, + Kind_PreDecrementExpression, + Kind_UnaryPlusExpression, + Kind_UnaryMinusExpression, + Kind_TildeExpression, + Kind_NotExpression, + Kind_BinaryExpression, + Kind_ConditionalExpression, + Kind_Expression, + Kind_Block, + Kind_StatementList, + Kind_VariableStatement, + Kind_VariableDeclarationList, + Kind_VariableDeclaration, + Kind_EmptyStatement, + Kind_ExpressionStatement, + Kind_IfStatement, + Kind_DoWhileStatement, + Kind_WhileStatement, + Kind_ForStatement, + Kind_LocalForStatement, + Kind_ForEachStatement, + Kind_LocalForEachStatement, + Kind_ContinueStatement, + Kind_BreakStatement, + Kind_ReturnStatement, + Kind_WithStatement, + Kind_SwitchStatement, + Kind_CaseBlock, + Kind_CaseClauses, + Kind_CaseClause, + Kind_DefaultClause, + Kind_LabelledStatement, + Kind_ThrowStatement, + Kind_TryStatement, + Kind_Catch, + Kind_Finally, + Kind_FunctionDeclaration, + Kind_FunctionExpression, + Kind_FormalParameterList, + Kind_FunctionBody, + Kind_Program, + Kind_SourceElements, + Kind_SourceElement, + Kind_FunctionSourceElement, + Kind_StatementSourceElement, + Kind_DebuggerStatement + }; + + inline Node(): + startLine(0), startColumn(0), + endLine(0), endColumn(0), kind(Kind_Node) {} + + virtual ~Node() {} + + virtual ExpressionNode *expressionCast(); + virtual BinaryExpression *binaryExpressionCast(); + virtual Statement *statementCast(); + + inline void accept(Visitor *visitor) + { + if (visitor->preVisit(this)) { + accept0(visitor); + visitor->postVisit(this); + } + } + + static void acceptChild(Node *node, Visitor *visitor) + { + if (node) + node->accept(visitor); + } + + virtual void accept0(Visitor *visitor) = 0; + + int startLine; + int startColumn; + int endLine; + int endColumn; + Kind kind; +}; + +class ExpressionNode: public Node +{ +public: + ExpressionNode() { kind = Kind_ExpressionNode; } + virtual ~ExpressionNode() {} + + virtual ExpressionNode *expressionCast(); +}; + +class Statement: public Node +{ +public: + Statement() { kind = Kind_Statement; } + virtual ~Statement() {} + + virtual Statement *statementCast(); +}; + +class ThisExpression: public ExpressionNode +{ +public: + ThisExpression() { kind = Kind_ThisExpression; } + virtual ~ThisExpression() {} + + virtual void accept0(Visitor *visitor); +}; + +class IdentifierExpression: public ExpressionNode +{ +public: + IdentifierExpression(QScriptNameIdImpl *n): + name (n) { kind = Kind_IdentifierExpression; } + + virtual ~IdentifierExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *name; +}; + +class NullExpression: public ExpressionNode +{ +public: + NullExpression() { kind = Kind_NullExpression; } + virtual ~NullExpression() {} + + virtual void accept0(Visitor *visitor); +}; + +class TrueLiteral: public ExpressionNode +{ +public: + TrueLiteral() { kind = Kind_TrueLiteral; } + virtual ~TrueLiteral() {} + + virtual void accept0(Visitor *visitor); +}; + +class FalseLiteral: public ExpressionNode +{ +public: + FalseLiteral() { kind = Kind_FalseLiteral; } + virtual ~FalseLiteral() {} + + virtual void accept0(Visitor *visitor); +}; + +class NumericLiteral: public ExpressionNode +{ +public: + NumericLiteral(double v): + value (v) { kind = Kind_NumericLiteral; } + virtual ~NumericLiteral() {} + + virtual void accept0(Visitor *visitor); + +// attributes: + double value; +}; + +class StringLiteral: public ExpressionNode +{ +public: + StringLiteral(QScriptNameIdImpl *v): + value (v) { kind = Kind_StringLiteral; } + + virtual ~StringLiteral() {} + + virtual void accept0(Visitor *visitor); + +// attributes: + QScriptNameIdImpl *value; +}; + +class RegExpLiteral: public ExpressionNode +{ +public: + RegExpLiteral(QScriptNameIdImpl *p, int f): + pattern (p), flags (f) { kind = Kind_RegExpLiteral; } + + virtual ~RegExpLiteral() {} + + virtual void accept0(Visitor *visitor); + +// attributes: + QScriptNameIdImpl *pattern; + int flags; +}; + +class ArrayLiteral: public ExpressionNode +{ +public: + ArrayLiteral(Elision *e): + elements (0), elision (e) + { kind = Kind_ArrayLiteral; } + + ArrayLiteral(ElementList *elts): + elements (elts), elision (0) + { kind = Kind_ArrayLiteral; } + + ArrayLiteral(ElementList *elts, Elision *e): + elements (elts), elision (e) + { kind = Kind_ArrayLiteral; } + + virtual ~ArrayLiteral() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ElementList *elements; + Elision *elision; +}; + +class ObjectLiteral: public ExpressionNode +{ +public: + ObjectLiteral(): + properties (0) { kind = Kind_ObjectLiteral; } + + ObjectLiteral(PropertyNameAndValueList *plist): + properties (plist) { kind = Kind_ObjectLiteral; } + + virtual ~ObjectLiteral() {} + + virtual void accept0(Visitor *visitor); + +// attributes + PropertyNameAndValueList *properties; +}; + +class ElementList: public Node +{ +public: + ElementList(Elision *e, ExpressionNode *expr): + elision (e), expression (expr), next (this) + { kind = Kind_ElementList; } + + ElementList(ElementList *previous, Elision *e, ExpressionNode *expr): + elision (e), expression (expr) + { + kind = Kind_ElementList; + 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; +}; + +class Elision: public Node +{ +public: + Elision(): + next (this) { kind = Kind_Elision; } + + Elision(Elision *previous) + { + kind = Kind_Elision; + 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; +}; + +class PropertyNameAndValueList: public Node +{ +public: + PropertyNameAndValueList(PropertyName *n, ExpressionNode *v): + name (n), value (v), next (this) + { kind = Kind_PropertyNameAndValueList; } + + PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v): + name (n), value (v) + { + kind = Kind_PropertyNameAndValueList; + 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; +}; + +class PropertyName: public Node +{ +public: + PropertyName() { kind = Kind_PropertyName; } + virtual ~PropertyName() {} +}; + +class IdentifierPropertyName: public PropertyName +{ +public: + IdentifierPropertyName(QScriptNameIdImpl *n): + id (n) { kind = Kind_IdentifierPropertyName; } + + virtual ~IdentifierPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *id; +}; + +class StringLiteralPropertyName: public PropertyName +{ +public: + StringLiteralPropertyName(QScriptNameIdImpl *n): + id (n) { kind = Kind_StringLiteralPropertyName; } + virtual ~StringLiteralPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *id; +}; + +class NumericLiteralPropertyName: public PropertyName +{ +public: + NumericLiteralPropertyName(double n): + id (n) { kind = Kind_NumericLiteralPropertyName; } + virtual ~NumericLiteralPropertyName() {} + + virtual void accept0(Visitor *visitor); + +// attributes + double id; +}; + +class ArrayMemberExpression: public ExpressionNode +{ +public: + ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e): + base (b), expression (e) + { kind = Kind_ArrayMemberExpression; } + + virtual ~ArrayMemberExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; + ExpressionNode *expression; +}; + +class FieldMemberExpression: public ExpressionNode +{ +public: + FieldMemberExpression(ExpressionNode *b, QScriptNameIdImpl *n): + base (b), name (n) + { kind = Kind_FieldMemberExpression; } + + virtual ~FieldMemberExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; + QScriptNameIdImpl *name; +}; + +class NewMemberExpression: public ExpressionNode +{ +public: + NewMemberExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = Kind_NewMemberExpression; } + + virtual ~NewMemberExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; + ArgumentList *arguments; +}; + +class NewExpression: public ExpressionNode +{ +public: + NewExpression(ExpressionNode *e): + expression (e) { kind = Kind_NewExpression; } + + virtual ~NewExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class CallExpression: public ExpressionNode +{ +public: + CallExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = Kind_CallExpression; } + + virtual ~CallExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; + ArgumentList *arguments; +}; + +class ArgumentList: public Node +{ +public: + ArgumentList(ExpressionNode *e): + expression (e), next (this) + { kind = Kind_ArgumentList; } + + ArgumentList(ArgumentList *previous, ExpressionNode *e): + expression (e) + { + kind = Kind_ArgumentList; + 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; +}; + +class PostIncrementExpression: public ExpressionNode +{ +public: + PostIncrementExpression(ExpressionNode *b): + base (b) { kind = Kind_PostIncrementExpression; } + + virtual ~PostIncrementExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; +}; + +class PostDecrementExpression: public ExpressionNode +{ +public: + PostDecrementExpression(ExpressionNode *b): + base (b) { kind = Kind_PostDecrementExpression; } + + virtual ~PostDecrementExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *base; +}; + +class DeleteExpression: public ExpressionNode +{ +public: + DeleteExpression(ExpressionNode *e): + expression (e) { kind = Kind_DeleteExpression; } + virtual ~DeleteExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class VoidExpression: public ExpressionNode +{ +public: + VoidExpression(ExpressionNode *e): + expression (e) { kind = Kind_VoidExpression; } + + virtual ~VoidExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class TypeOfExpression: public ExpressionNode +{ +public: + TypeOfExpression(ExpressionNode *e): + expression (e) { kind = Kind_TypeOfExpression; } + + virtual ~TypeOfExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class PreIncrementExpression: public ExpressionNode +{ +public: + PreIncrementExpression(ExpressionNode *e): + expression (e) { kind = Kind_PreIncrementExpression; } + + virtual ~PreIncrementExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class PreDecrementExpression: public ExpressionNode +{ +public: + PreDecrementExpression(ExpressionNode *e): + expression (e) { kind = Kind_PreDecrementExpression; } + + virtual ~PreDecrementExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class UnaryPlusExpression: public ExpressionNode +{ +public: + UnaryPlusExpression(ExpressionNode *e): + expression (e) { kind = Kind_UnaryPlusExpression; } + + virtual ~UnaryPlusExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class UnaryMinusExpression: public ExpressionNode +{ +public: + UnaryMinusExpression(ExpressionNode *e): + expression (e) { kind = Kind_UnaryMinusExpression; } + + virtual ~UnaryMinusExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class TildeExpression: public ExpressionNode +{ +public: + TildeExpression(ExpressionNode *e): + expression (e) { kind = Kind_TildeExpression; } + + virtual ~TildeExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class NotExpression: public ExpressionNode +{ +public: + NotExpression(ExpressionNode *e): + expression (e) { kind = Kind_NotExpression; } + + virtual ~NotExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class BinaryExpression: public ExpressionNode +{ +public: + BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r): + left (l), op (o), right (r) + { kind = Kind_BinaryExpression; } + + virtual ~BinaryExpression() {} + + virtual BinaryExpression *binaryExpressionCast(); + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *left; + int op; + ExpressionNode *right; +}; + +class ConditionalExpression: public ExpressionNode +{ +public: + ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f): + expression (e), ok (t), ko (f) + { kind = Kind_ConditionalExpression; } + + virtual ~ConditionalExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + ExpressionNode *ok; + ExpressionNode *ko; +}; + +class Expression: public ExpressionNode // ### rename +{ +public: + Expression(ExpressionNode *l, ExpressionNode *r): + left (l), right (r) { kind = Kind_Expression; } + + virtual ~Expression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *left; + ExpressionNode *right; +}; + +class Block: public Statement +{ +public: + Block(StatementList *slist): + statements (slist) { kind = Kind_Block; } + + virtual ~Block() {} + + virtual void accept0(Visitor *visitor); + +// attributes + StatementList *statements; +}; + +class StatementList: public Node +{ +public: + StatementList(Statement *stmt): + statement (stmt), next (this) + { kind = Kind_StatementList; } + + StatementList(StatementList *previous, Statement *stmt): + statement (stmt) + { + kind = Kind_StatementList; + 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: + VariableStatement(VariableDeclarationList *vlist): + declarations (vlist) + { kind = Kind_VariableStatement; } + + virtual ~VariableStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + VariableDeclarationList *declarations; +}; + +class VariableDeclaration: public Node +{ +public: + VariableDeclaration(QScriptNameIdImpl *n, ExpressionNode *e): + name (n), expression (e), readOnly(false) + { kind = Kind_VariableDeclaration; } + + virtual ~VariableDeclaration() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *name; + ExpressionNode *expression; + bool readOnly; +}; + +class VariableDeclarationList: public Node +{ +public: + VariableDeclarationList(VariableDeclaration *decl): + declaration (decl), next (this) + { kind = Kind_VariableDeclarationList; } + + VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl): + declaration (decl) + { + kind = Kind_VariableDeclarationList; + 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; +}; + +class EmptyStatement: public Statement +{ +public: + EmptyStatement() { kind = Kind_EmptyStatement; } + virtual ~EmptyStatement() {} + + virtual void accept0(Visitor *visitor); +}; + +class ExpressionStatement: public Statement +{ +public: + ExpressionStatement(ExpressionNode *e): + expression (e) { kind = Kind_ExpressionStatement; } + + virtual ~ExpressionStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class IfStatement: public Statement +{ +public: + IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0): + expression (e), ok (t), ko (f) + { kind = Kind_IfStatement; } + + virtual ~IfStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + Statement *ok; + Statement *ko; +}; + +class DoWhileStatement: public Statement +{ +public: + DoWhileStatement(Statement *stmt, ExpressionNode *e): + statement (stmt), expression (e) + { kind = Kind_DoWhileStatement; } + + virtual ~DoWhileStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; + ExpressionNode *expression; +}; + +class WhileStatement: public Statement +{ +public: + WhileStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = Kind_WhileStatement; } + + virtual ~WhileStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + Statement *statement; +}; + +class ForStatement: public Statement +{ +public: + ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + initialiser (i), condition (c), expression (e), statement (stmt) + { kind = Kind_ForStatement; } + + virtual ~ForStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *initialiser; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; +}; + +class LocalForStatement: public Statement +{ +public: + LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + declarations (vlist), condition (c), expression (e), statement (stmt) + { kind = Kind_LocalForStatement; } + + virtual ~LocalForStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + VariableDeclarationList *declarations; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; +}; + +class ForEachStatement: public Statement +{ +public: + ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt): + initialiser (i), expression (e), statement (stmt) + { kind = Kind_ForEachStatement; } + + virtual ~ForEachStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *initialiser; + ExpressionNode *expression; + Statement *statement; +}; + +class LocalForEachStatement: public Statement +{ +public: + LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt): + declaration (v), expression (e), statement (stmt) + { kind = Kind_LocalForEachStatement; } + + virtual ~LocalForEachStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + VariableDeclaration *declaration; + ExpressionNode *expression; + Statement *statement; +}; + +class ContinueStatement: public Statement +{ +public: + ContinueStatement(QScriptNameIdImpl *l = 0): + label (l) { kind = Kind_ContinueStatement; } + + virtual ~ContinueStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *label; +}; + +class BreakStatement: public Statement +{ +public: + BreakStatement(QScriptNameIdImpl *l = 0): + label (l) { kind = Kind_BreakStatement; } + + virtual ~BreakStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *label; +}; + +class ReturnStatement: public Statement +{ +public: + ReturnStatement(ExpressionNode *e): + expression (e) { kind = Kind_ReturnStatement; } + + virtual ~ReturnStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class WithStatement: public Statement +{ +public: + WithStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = Kind_WithStatement; } + + virtual ~WithStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + Statement *statement; +}; + +class SwitchStatement: public Statement +{ +public: + SwitchStatement(ExpressionNode *e, CaseBlock *b): + expression (e), block (b) + { kind = Kind_SwitchStatement; } + + virtual ~SwitchStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + CaseBlock *block; +}; + +class CaseBlock: public Node +{ +public: + CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0): + clauses (c), defaultClause (d), moreClauses (r) + { kind = Kind_CaseBlock; } + + virtual ~CaseBlock() {} + + virtual void accept0(Visitor *visitor); + +// attributes + CaseClauses *clauses; + DefaultClause *defaultClause; + CaseClauses *moreClauses; +}; + +class CaseClauses: public Node +{ +public: + CaseClauses(CaseClause *c): + clause (c), next (this) + { kind = Kind_CaseClauses; } + + CaseClauses(CaseClauses *previous, CaseClause *c): + clause (c) + { + kind = Kind_CaseClauses; + 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: + CaseClause(ExpressionNode *e, StatementList *slist): + expression (e), statements (slist) + { kind = Kind_CaseClause; } + + virtual ~CaseClause() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + StatementList *statements; +}; + +class DefaultClause: public Node +{ +public: + DefaultClause(StatementList *slist): + statements (slist) + { kind = Kind_DefaultClause; } + + virtual ~DefaultClause() {} + + virtual void accept0(Visitor *visitor); + +// attributes + StatementList *statements; +}; + +class LabelledStatement: public Statement +{ +public: + LabelledStatement(QScriptNameIdImpl *l, Statement *stmt): + label (l), statement (stmt) + { kind = Kind_LabelledStatement; } + + virtual ~LabelledStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *label; + Statement *statement; +}; + +class ThrowStatement: public Statement +{ +public: + ThrowStatement(ExpressionNode *e): + expression (e) { kind = Kind_ThrowStatement; } + + virtual ~ThrowStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; +}; + +class TryStatement: public Statement +{ +public: + TryStatement(Statement *stmt, Catch *c, Finally *f): + statement (stmt), catchExpression (c), finallyExpression (f) + { kind = Kind_TryStatement; } + + TryStatement(Statement *stmt, Finally *f): + statement (stmt), catchExpression (0), finallyExpression (f) + { kind = Kind_TryStatement; } + + TryStatement(Statement *stmt, Catch *c): + statement (stmt), catchExpression (c), finallyExpression (0) + { kind = Kind_TryStatement; } + + virtual ~TryStatement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; + Catch *catchExpression; + Finally *finallyExpression; +}; + +class Catch: public Node +{ +public: + Catch(QScriptNameIdImpl *n, Statement *stmt): + name (n), statement (stmt) + { kind = Kind_Catch; } + + virtual ~Catch() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *name; + Statement *statement; +}; + +class Finally: public Node +{ +public: + Finally(Statement *stmt): + statement (stmt) + { kind = Kind_Finally; } + + virtual ~Finally() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; +}; + +class FunctionExpression: public ExpressionNode +{ +public: + FunctionExpression(QScriptNameIdImpl *n, FormalParameterList *f, FunctionBody *b): + name (n), formals (f), body (b) + { kind = Kind_FunctionExpression; } + + virtual ~FunctionExpression() {} + + virtual void accept0(Visitor *visitor); + +// attributes + QScriptNameIdImpl *name; + FormalParameterList *formals; + FunctionBody *body; +}; + +class FunctionDeclaration: public FunctionExpression +{ +public: + FunctionDeclaration(QScriptNameIdImpl *n, FormalParameterList *f, FunctionBody *b): + FunctionExpression(n, f, b) + { kind = Kind_FunctionDeclaration; } + + virtual ~FunctionDeclaration() {} + + virtual void accept0(Visitor *visitor); +}; + +class FormalParameterList: public Node +{ +public: + FormalParameterList(QScriptNameIdImpl *n): + name (n), next (this) + { kind = Kind_FormalParameterList; } + + FormalParameterList(FormalParameterList *previous, QScriptNameIdImpl *n): + name (n) + { + kind = Kind_FormalParameterList; + next = previous->next; + previous->next = this; + } + + virtual ~FormalParameterList() {} + + virtual void accept0(Visitor *visitor); + + inline FormalParameterList *finish () + { + FormalParameterList *front = next; + next = 0; + return front; + } + +// attributes + QScriptNameIdImpl *name; + FormalParameterList *next; +}; + +class FunctionBody: public Node +{ +public: + FunctionBody(SourceElements *elts): + elements (elts) + { kind = Kind_FunctionBody; } + + virtual ~FunctionBody() {} + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class Program: public Node +{ +public: + Program(SourceElements *elts): + elements (elts) + { kind = Kind_Program; } + + virtual ~Program() {} + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class SourceElements: public Node +{ +public: + SourceElements(SourceElement *elt): + element (elt), next (this) + { kind = Kind_SourceElements; } + + SourceElements(SourceElements *previous, SourceElement *elt): + element (elt) + { + kind = Kind_SourceElements; + 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: + inline SourceElement() + { kind = Kind_SourceElement; } + + virtual ~SourceElement() {} +}; + +class FunctionSourceElement: public SourceElement +{ +public: + FunctionSourceElement(FunctionDeclaration *f): + declaration (f) + { kind = Kind_FunctionSourceElement; } + + virtual ~FunctionSourceElement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + FunctionDeclaration *declaration; +}; + +class StatementSourceElement: public SourceElement +{ +public: + StatementSourceElement(Statement *stmt): + statement (stmt) + { kind = Kind_StatementSourceElement; } + + virtual ~StatementSourceElement() {} + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; +}; + +class DebuggerStatement: public Statement +{ +public: + DebuggerStatement() + { kind = Kind_DebuggerStatement; } + + virtual ~DebuggerStatement() {} + + virtual void accept0(Visitor *visitor); +}; + +} } // namespace AST + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptastfwd_p.h b/src/script/qscriptastfwd_p.h new file mode 100644 index 0000000..192ede1 --- /dev/null +++ b/src/script/qscriptastfwd_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 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 QSCRIPTAST_FWD_P_H +#define QSCRIPTAST_FWD_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 + +namespace QScript { namespace AST { + +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; + +} } // namespace AST + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptastvisitor.cpp b/src/script/qscriptastvisitor.cpp new file mode 100644 index 0000000..8502bc5 --- /dev/null +++ b/src/script/qscriptastvisitor.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 "qscriptastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace AST { + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +} } // namespace QScript::AST + +QT_END_NAMESPACE diff --git a/src/script/qscriptastvisitor_p.h b/src/script/qscriptastvisitor_p.h new file mode 100644 index 0000000..de5528c --- /dev/null +++ b/src/script/qscriptastvisitor_p.h @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** 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 QSCRIPTASTVISITOR_P_H +#define QSCRIPTASTVISITOR_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 "qscriptastfwd_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace AST { + +class Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual bool preVisit(Node *) { return true; } + virtual void postVisit(Node *) {} + + 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(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_END_NAMESPACE + +#endif // QSCRIPTASTVISITOR_P_H diff --git a/src/script/qscriptbuffer_p.h b/src/script/qscriptbuffer_p.h new file mode 100644 index 0000000..92fe6db --- /dev/null +++ b/src/script/qscriptbuffer_p.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** 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 QSCRIPTBUFFER_P_H +#define QSCRIPTBUFFER_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +namespace QScript +{ + template <typename T> class Buffer + { + public: + typedef T *iterator; + typedef const T *const_iterator; + + Buffer() : m_data(0), m_capacity(0), m_size(0) { } + ~Buffer() { delete [] m_data; } + + inline void reserve(int num); + inline void reset(); + inline void clear(); + inline void append(const T &t); + + inline iterator begin(); + inline iterator end(); + + inline const_iterator begin() const; + inline const_iterator end() const; + + inline int size() const; + inline void resize(int s); + + inline int capacity() const; + inline T *data(); + inline const T *constData() const; + + inline T &last(); + inline T &takeLast(); + + inline T &at(int i) { return (*this)[i]; } + inline const T &at(int i) const { return (*this)[i]; } + + inline T &operator[](int i); + inline const T &operator[](int i) const; + + inline bool isEmpty() const; + + private: + T *m_data; + int m_capacity; + int m_size; + + private: + Q_DISABLE_COPY(Buffer) + }; + +} // namespace QScript + +template <typename T> T *QScript::Buffer<T>::data() { return m_data; } +template <typename T> const T *QScript::Buffer<T>::constData() const { return m_data; } +template <typename T> void QScript::Buffer<T>::reset() { m_size = 0; } +template <typename T> int QScript::Buffer<T>::capacity() const { return m_capacity; } + +template <typename T> int QScript::Buffer<T>::size() const { return m_size; } +template <typename T> void QScript::Buffer<T>::resize(int s) +{ + if (m_capacity < s) + reserve (s << 1); + + m_size = s; +} + +template <typename T> void QScript::Buffer<T>::clear() +{ + delete [] m_data; + m_data = 0; + m_size = 0; + m_capacity = 0; +} + +template <typename T> void QScript::Buffer<T>::reserve(int x) +{ + // its an ever expanding buffer so it never gets smaller.. + if (x < m_capacity) + return; + m_capacity = x; + T *new_data = new T[m_capacity]; + for (int i=0; i<m_size; ++i) + new_data[i] = m_data[i]; + delete [] m_data; + m_data = new_data; +} + +template <typename T> void QScript::Buffer<T>::append(const T &t) +{ + if (m_size == m_capacity) + reserve(m_capacity + 32); + m_data[m_size++] = t; +} + +template <typename T> T &QScript::Buffer<T>::operator[](int i) +{ + Q_ASSERT(i >= 0); + Q_ASSERT(i < m_size); + return m_data[i]; +} + +template <typename T> const T &QScript::Buffer<T>::operator[](int i) const +{ + Q_ASSERT(i >= 0); + Q_ASSERT(i < m_size); + return m_data[i]; +} + +template <typename T> bool QScript::Buffer<T>::isEmpty() const +{ + return m_size == 0; +} + +template <typename T> T &QScript::Buffer<T>::takeLast() +{ + Q_ASSERT(!isEmpty()); + --m_size; + return m_data[m_size]; +} + +template <typename T> T &QScript::Buffer<T>::last() +{ + return m_data[m_size - 1]; +} + +template <typename T> typename QScript::Buffer<T>::iterator QScript::Buffer<T>::begin() +{ + return m_data; +} + +template <typename T> typename QScript::Buffer<T>::iterator QScript::Buffer<T>::end() +{ + return m_data + m_size; +} + +template <typename T> typename QScript::Buffer<T>::const_iterator QScript::Buffer<T>::begin() const +{ + return m_data; +} + +template <typename T> typename QScript::Buffer<T>::const_iterator QScript::Buffer<T>::end() const +{ + return m_data + m_size; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptclass.cpp b/src/script/qscriptclass.cpp new file mode 100644 index 0000000..14b8add --- /dev/null +++ b/src/script/qscriptclass.cpp @@ -0,0 +1,684 @@ +/**************************************************************************** +** +** 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 "qscriptclass.h" + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qstringlist.h> + +#include "qscriptclasspropertyiterator.h" +#include "qscriptstring.h" +#include "qscriptstring_p.h" +#include "qscriptclass_p.h" +#include "qscriptclassinfo_p.h" +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptfunction_p.h" + +Q_DECLARE_METATYPE(QScriptContext*) +Q_DECLARE_METATYPE(QScriptValueList) + +QT_BEGIN_NAMESPACE + +/*! + \since 4.4 + \class QScriptClass + + \brief The QScriptClass class provides an interface for defining custom behavior of (a class of) Qt Script objects. + + \ingroup script + \mainclass + + The QScriptClass class defines an interface for handling various + aspects of interaction with the Qt Script objects associated with + the class. Such objects are created by calling + QScriptEngine::newObject(), passing a pointer to the QScriptClass as + argument. + + By subclassing QScriptClass, you can define precisely how access to + properties of the objects that use your class is handled. This + enables a fully dynamic handling of properties, e.g. it's more + powerful than QScriptEngine::newQObject(). For example, you can use + QScriptClass to implement array-type objects (i.e. objects that + handle the \c{length} property, and properties whose names are valid + array indexes, in a special way), or to implement a "live" + (runtime-defined) proxy to an underlying object. + + If you just need to handle access to a set of properties that are + known at the time an object is created (i.e. "semi-statically"), you + might consider using QScriptValue::setProperty() to define + getter/setter functions for the relevant properties, rather than + subclassing QScriptClass. + + Reimplement queryProperty() to specify which properties are handled + in a custom way by your script class (i.e. should be + \bold{delegated} to the QScriptClass), and which properties should + be handled just like normal Qt Script object properties. + + Reimplement property() and setProperty() to perform the actual + access (read or write) to the properties that your class + handles. Additionally, you can reimplement propertyFlags() to + specify custom flags for your properties. + + Reimplement newIterator() to provide an iterator for objects of your + custom class. This is only necessary if objects of your class can + have custom properties that you want to be reported when an object + is used together with the QScriptValueIterator class, or when an + object is used in a for-in enumeration statement in a script. + + When implementing custom classes of objects, you typically use + QScriptValue::setData() to store instance-specific data as part of + object initialization; the data won't be accessible from scripts + directly, but you can access it in e.g. your reimplementations of + property() and setProperty() (by calling QScriptValue::data()) to + perform custom processing. + + Reimplement prototype() to provide a custom prototype object for + your script class. + + Reimplement supportsExtension() and extension() if your custom + script class supports one or more of the extensions specified by the + Extension enum. + + \sa QScriptClassPropertyIterator, QScriptEngine::newObject(), {Custom Script Class Example} +*/ + +/*! + \enum QScriptClass::Extension + + This enum specifies the possible extensions to a QScriptClass. + + \value Callable Instances of this class can be called as functions. + + \value HasInstance Instances of this class implement [[HasInstance]]. + + \sa extension() +*/ + +/*! + \enum QScriptClass::QueryFlag + + This enum describes flags that are used to query a QScriptClass + regarding how access to a property should be handled. + + \value HandlesReadAccess The QScriptClass handles read access to this property. + \value HandlesWriteAccess The QScriptClass handles write access to this property. + + \sa queryProperty() +*/ + +class QScriptCustomClassData : public QScriptClassData +{ +public: + QScriptCustomClassData(QScriptClass *klass); + ~QScriptCustomClassData(); + + virtual void mark(const QScriptValueImpl &object, int generation); + virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &obj, const QScript::Member &m, + QScriptValueImpl *result); + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value); + virtual bool removeMember(const QScriptValueImpl &object, + const QScript::Member &member); + virtual bool implementsHasInstance(const QScriptValueImpl &object); + virtual bool hasInstance(const QScriptValueImpl &object, + const QScriptValueImpl &value); + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object); + + QScriptClass *scriptClass() const; + +private: + QScriptClass *m_class; +}; + +class QScriptCustomClassDataIterator : public QScriptClassDataIterator +{ +public: + QScriptCustomClassDataIterator(const QScriptValueImpl &object, + QScriptClass *klass); + virtual ~QScriptCustomClassDataIterator(); + + virtual bool hasNext() const; + virtual void next(QScript::Member *member); + + virtual bool hasPrevious() const; + virtual void previous(QScript::Member *member); + + virtual void toFront(); + virtual void toBack(); + +private: + void iteratorToMember(QScript::Member *member); + + QScriptClassPropertyIterator *m_it; +}; + +QScriptCustomClassData::QScriptCustomClassData(QScriptClass *klass) + : m_class(klass) +{ +} + +QScriptCustomClassData::~QScriptCustomClassData() +{ +} + +void QScriptCustomClassData::mark(const QScriptValueImpl &, int) +{ +} + +bool QScriptCustomClassData::resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access) +{ + uint id = 0; + QScriptClass::QueryFlags queryIn = 0; + if (access & QScript::Read) + queryIn |= QScriptClass::HandlesReadAccess; + if (access & QScript::Write) + queryIn |= QScriptClass::HandlesWriteAccess; + QScriptEnginePrivate *eng = object.engine(); + QScriptString str = eng->internedString(nameId); + QScriptClass::QueryFlags queryOut; + queryOut = m_class->queryProperty(eng->toPublic(object), str, queryIn, &id); + if (queryOut & queryIn) { + if (base) + *base = object; + QScriptValue::PropertyFlags flags = m_class->propertyFlags(eng->toPublic(object), str, id); + member->native(nameId, id, flags); + return true; + } + return false; +} + +bool QScriptCustomClassData::get(const QScriptValueImpl &object, const QScript::Member &member, + QScriptValueImpl *result) +{ + QScriptEnginePrivate *eng = object.engine(); + QScriptString str = eng->internedString(member.nameId()); + *result = eng->toImpl(m_class->property(eng->toPublic(object), str, member.id())); + if (!result->isValid()) + *result = eng->undefinedValue(); + return true; +} + +bool QScriptCustomClassData::put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value) +{ + QScriptEnginePrivate *eng = object->engine(); + QScriptString str = eng->internedString(member.nameId()); + QScriptValue publicObject = eng->toPublic(*object); + m_class->setProperty(publicObject, str, member.id(), eng->toPublic(value)); + return true; +} + +bool QScriptCustomClassData::removeMember(const QScriptValueImpl &object, + const QScript::Member &member) +{ + QScriptEnginePrivate *eng = object.engine(); + QScriptString str = eng->internedString(member.nameId()); + QScriptValue publicObject = eng->toPublic(object); + m_class->setProperty(publicObject, str, member.id(), QScriptValue()); + return true; +} + +bool QScriptCustomClassData::implementsHasInstance(const QScriptValueImpl &object) +{ + if (object.classInfo() != QScriptClassPrivate::get(m_class)->classInfo()) + return false; + return m_class->supportsExtension(QScriptClass::HasInstance); +} + +bool QScriptCustomClassData::hasInstance(const QScriptValueImpl &object, + const QScriptValueImpl &value) +{ + QScriptEnginePrivate *eng = object.engine(); + QScriptValueList arguments; + arguments << eng->toPublic(object) << eng->toPublic(value); + QVariant ret = m_class->extension(QScriptClass::HasInstance, qVariantFromValue(arguments)); + return ret.toBool(); +} + +QScriptClassDataIterator *QScriptCustomClassData::newIterator(const QScriptValueImpl &object) +{ + return new QScriptCustomClassDataIterator(object, m_class); +} + +QScriptClass *QScriptCustomClassData::scriptClass() const +{ + return m_class; +} + + + +QScriptCustomClassDataIterator::QScriptCustomClassDataIterator(const QScriptValueImpl &object, + QScriptClass *klass) +{ + QScriptEnginePrivate *eng = object.engine(); + m_it = klass->newIterator(eng->toPublic(object)); +} + +QScriptCustomClassDataIterator::~QScriptCustomClassDataIterator() +{ + if (m_it) { + delete m_it; + m_it = 0; + } +} + +bool QScriptCustomClassDataIterator::hasNext() const +{ + return m_it && m_it->hasNext(); +} + +void QScriptCustomClassDataIterator::next(QScript::Member *member) +{ + if (m_it) { + m_it->next(); + iteratorToMember(member); + } +} + +bool QScriptCustomClassDataIterator::hasPrevious() const +{ + return m_it && m_it->hasPrevious(); +} + +void QScriptCustomClassDataIterator::previous(QScript::Member *member) +{ + if (m_it) { + m_it->previous(); + iteratorToMember(member); + } +} + +void QScriptCustomClassDataIterator::toFront() +{ + if (m_it) + m_it->toFront(); +} + +void QScriptCustomClassDataIterator::toBack() +{ + if (m_it) + m_it->toBack(); +} + +void QScriptCustomClassDataIterator::iteratorToMember(QScript::Member *member) +{ + QScriptString str = m_it->name(); + QScriptNameIdImpl *nameId = 0; + if (str.isValid()) + nameId = QScriptStringPrivate::get(str)->nameId; + member->native(nameId, m_it->id(), m_it->flags()); +} + + + +QScriptClassPrivate::QScriptClassPrivate(QScriptClass *q) + : engine(0), m_classInfo(0), q_ptr(q) +{ +} + +QScriptClassPrivate::~QScriptClassPrivate() +{ + if (m_classInfo) { + // classInfo is owned by engine + // set the data to the normal Object class data + delete m_classInfo->data(); + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + m_classInfo->setData(eng_p->m_class_object->data()); + } +} + +QScriptClassPrivate *QScriptClassPrivate::get(QScriptClass *klass) +{ + return klass->d_func(); +} + +QScriptClassInfo *QScriptClassPrivate::classInfo() +{ + Q_Q(QScriptClass); + if (m_classInfo) + return m_classInfo; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + int classType = eng_p->registerCustomClassType(); + if (q->supportsExtension(QScriptClass::Callable)) + classType |= QScriptClassInfo::FunctionBased; + QString name = q->name(); + if (name.isEmpty()) + name = QLatin1String("Object"); + m_classInfo = eng_p->registerClass(name, classType); + m_classInfo->setData(new QScriptCustomClassData(q_func())); + return m_classInfo; +} + +QScriptClass *QScriptClassPrivate::classFromInfo(QScriptClassInfo *info) +{ + QScriptCustomClassData *data = static_cast<QScriptCustomClassData*>(info->data()); + Q_ASSERT(data != 0); + return data->scriptClass(); +} + +static QScriptValueImpl callScriptClassFunction(QScriptContextPrivate *ctx, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + qMetaTypeId<QScriptContext*>(); + if (QScriptClassData *data = classInfo->data()) { + QScriptCustomClassData *customData = static_cast<QScriptCustomClassData*>(data); + QScriptClass *klass = customData->scriptClass(); + QVariant arg = qVariantFromValue(QScriptContextPrivate::get(ctx)); + QVariant ret = klass->extension(QScriptClass::Callable, arg); + QScriptValueImpl val = eng->valueFromVariant(ret); + if (val.isValid()) + return val; + } + return eng->undefinedValue(); +} + +QScriptFunction *QScriptClassPrivate::newFunction() +{ + return new QScript::C2Function(callScriptClassFunction, /*length=*/0, + classInfo(), /*name=*/QString()); +} + +/*! + Constructs a QScriptClass object to be used in the given \a engine. + + The engine does not take ownership of the QScriptClass object. +*/ +QScriptClass::QScriptClass(QScriptEngine *engine) + : d_ptr(new QScriptClassPrivate(this)) +{ + d_ptr->engine = engine; +} + +/*! + \internal +*/ +QScriptClass::QScriptClass(QScriptEngine *engine, QScriptClassPrivate &dd) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; + d_ptr->engine = engine; +} + +/*! + Destroys the QScriptClass object. + + If a QScriptClass object is deleted before the associated engine(), + any Qt Script objects using the QScriptClass will be "demoted" to + normal Qt Script objects. +*/ +QScriptClass::~QScriptClass() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Returns the engine that this QScriptClass is associated with. +*/ +QScriptEngine *QScriptClass::engine() const +{ + Q_D(const QScriptClass); + return d->engine; +} + +/*! + Returns the object to be used as the prototype of new instances + of this class (created with QScriptEngine::newObject()). + + The default implementation returns an invalid QScriptValue, meaning + that the standard Object prototype will be used. Reimplement this + function to provide your own custom prototype. + + Typically you initialize your prototype object in the constructor of + your class, then return it in this function. + + See the "Making Use of Prototype-Based Inheritance" section in the + QtScript documentation for more information on how prototypes are + used. +*/ +QScriptValue QScriptClass::prototype() const +{ + return QScriptValue(); +} + +/*! + Returns the name of the script class. + + Qt Script uses this name to generate a default string representation + of objects in case you do not provide a toString function. + + The default implementation returns a null string. +*/ +QString QScriptClass::name() const +{ + return QString(); +} + +/*! + Queries this script class for how access to the property with the + given \a name of the given \a object should be handled. The given \a + flags specify the aspects of interest. This function should return a + subset of \a flags to indicate which aspects of property access + should be further handled by the script class. + + For example, if the \a flags contain HandlesReadAccess, and you + would like your class to handle the reading of the property (through + the property() function), the returned flags should include + HandlesReadAccess. If the returned flags do not contain + HandlesReadAccess, the property will be handled as a normal script + object property. + + You can optionally use the \a id argument to store a value that will + subsequently be passed on to functions such as property() and + setProperty(). + + The default implementation of this function returns 0. + + Note: This function is only called if the given property isn't + already a normal property of the object. For example, say you + advertise that you want to handle read access to property \c{foo}, + but not write access; if \c{foo} is then assigned a value, it will + become a normal script object property, and subsequently you will no + longer be queried regarding read access to \c{foo}. + + \sa property() +*/ +QScriptClass::QueryFlags QScriptClass::queryProperty( + const QScriptValue &object, const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(flags); + Q_UNUSED(id); + return 0; +} + +/*! + Returns the value of the property with the given \a name of the given + \a object. + + The \a id argument is only useful if you assigned a value to it in + queryProperty(). + + The default implementation does nothing and returns an invalid QScriptValue. + + \sa setProperty(), propertyFlags() +*/ +QScriptValue QScriptClass::property(const QScriptValue &object, + const QScriptString &name, uint id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(id); + return QScriptValue(); +} + +/*! + Returns the flags of the property with the given \a name of the given + \a object. + + The \a id argument is only useful if you assigned a value to it in + queryProperty(). + + The default implementation returns 0. + + \sa property() +*/ +QScriptValue::PropertyFlags QScriptClass::propertyFlags( + const QScriptValue &object, const QScriptString &name, uint id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(id); + return 0; +} + +/*! + Sets the property with the given \a name of the given \a object to + the given \a value. + + The \a id argument is only useful if you assigned a value to it in + queryProperty(). + + The default implementation does nothing. + + An invalid \a value represents a request to remove the property. + + \sa property() +*/ +void QScriptClass::setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(id); + Q_UNUSED(value); +} + +/*! + Returns an iterator for traversing custom properties of the given \a + object. + + The default implementation returns 0, meaning that there are no + custom properties to traverse. + + Reimplement this function if objects of your script class can have + one or more custom properties (e.g. those reported to be handled by + queryProperty()) that you want to appear when an object's properties + are enumerated (e.g. by a for-in statement in a script). + + Qt Script takes ownership of the new iterator object. + + \sa QScriptValueIterator +*/ +QScriptClassPropertyIterator *QScriptClass::newIterator(const QScriptValue &object) +{ + Q_UNUSED(object); + return 0; +} + +/*! + Returns true if the QScriptClass supports the given \a extension; + otherwise, false is returned. By default, no extensions + are supported. + + Reimplement this function to indicate which extensions your custom + class supports. + + \sa extension() +*/ +bool QScriptClass::supportsExtension(Extension extension) const +{ + Q_UNUSED(extension); + return false; +} + +/*! + This virtual function can be reimplemented in a QScriptClass + subclass to provide support for extensions. The optional \a argument + can be provided as input to the \a extension; the result must be + returned in the form of a QVariant. You can call supportsExtension() + to check if an extension is supported by the QScriptClass. By + default, no extensions are supported, and this function returns an + invalid QVariant. + + If you implement the Callable extension, Qt Script will call this + function when an instance of your class is called as a function + (e.g. from a script or using QScriptValue::call()). The \a argument + will contain a pointer to the QScriptContext that represents the + function call, and you should return a QVariant that holds the + result of the function call. In the following example the sum of the + arguments to the script function are added up and returned: + + \snippet doc/src/snippets/code/src_script_qscriptclass.cpp 0 + + If you implement the HasInstance extension, Qt Script will call this + function as part of evaluating the \c{instanceof} operator, as + described in ECMA-262 Section 11.8.6. The \a argument is a + QScriptValueList containing two items: The first item is the object + that HasInstance is being applied to (an instance of your class), + and the second item can be any value. extension() should return true + if the value delegates behavior to the object, false otherwise. + + \sa supportsExtension() +*/ +QVariant QScriptClass::extension(Extension extension, const QVariant &argument) +{ + Q_UNUSED(extension); + Q_UNUSED(argument); + return QVariant(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptclass.h b/src/script/qscriptclass.h new file mode 100644 index 0000000..9c06ea2 --- /dev/null +++ b/src/script/qscriptclass.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 QSCRIPTCLASS_H +#define QSCRIPTCLASS_H + +#include <QtCore/qstring.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qvariant.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptString; +class QScriptClassPropertyIterator; + +class QScriptClassPrivate; +class Q_SCRIPT_EXPORT QScriptClass +{ +public: + enum QueryFlag { + HandlesReadAccess = 0x01, + HandlesWriteAccess = 0x02 + }; + Q_DECLARE_FLAGS(QueryFlags, QueryFlag) + + enum Extension { + Callable, + HasInstance + }; + + QScriptClass(QScriptEngine *engine); + virtual ~QScriptClass(); + + QScriptEngine *engine() const; + + 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); + + virtual QScriptValue::PropertyFlags propertyFlags( + const QScriptValue &object, const QScriptString &name, uint id); + + virtual QScriptClassPropertyIterator *newIterator(const QScriptValue &object); + + virtual QScriptValue prototype() const; + + virtual QString name() const; + + virtual bool supportsExtension(Extension extension) const; + virtual QVariant extension(Extension extension, + const QVariant &argument = QVariant()); + +protected: + QScriptClass(QScriptEngine *engine, QScriptClassPrivate &dd); + QScriptClassPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QScriptClass) + Q_DISABLE_COPY(QScriptClass) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QScriptClass::QueryFlags) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptclass_p.h b/src/script/qscriptclass_p.h new file mode 100644 index 0000000..79c1a99 --- /dev/null +++ b/src/script/qscriptclass_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 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 QSCRIPTCLASS_P_H +#define QSCRIPTCLASS_P_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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; +class QScriptClassInfo; +class QScriptFunction; + +class QScriptClass; +class QScriptClassPrivate +{ + Q_DECLARE_PUBLIC(QScriptClass) +public: + QScriptClassPrivate(QScriptClass*); + virtual ~QScriptClassPrivate(); + + static QScriptClassPrivate *get(QScriptClass *klass); + + QScriptClassInfo *classInfo(); + static QScriptClass *classFromInfo(QScriptClassInfo *info); + + QScriptFunction *newFunction(); + + QScriptEngine *engine; + QScriptClassInfo *m_classInfo; + + QScriptClass *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptclassdata.cpp b/src/script/qscriptclassdata.cpp new file mode 100644 index 0000000..aed6fea --- /dev/null +++ b/src/script/qscriptclassdata.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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 "qscriptclassdata_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +QScriptClassData::QScriptClassData() +{ +} + +QScriptClassData::~QScriptClassData() +{ +} + +void QScriptClassData::mark(const QScriptValueImpl &, int) +{ +} + +bool QScriptClassData:: resolve(const QScriptValueImpl &, QScriptNameIdImpl *, + QScript::Member *, QScriptValueImpl *, + QScript::AccessMode) +{ + return false; +} + +bool QScriptClassData::get(const QScriptValueImpl &, const QScript::Member &, + QScriptValueImpl *) +{ + Q_ASSERT_X(false, "QScriptClassData::get()", + "implement if resolveMember is implemented"); + return false; +} + +bool QScriptClassData::put(QScriptValueImpl *, const QScript::Member &, + const QScriptValueImpl &) +{ + Q_ASSERT_X(false, "QScriptClassData::put()", + "implement if resolveMember is implemented"); + return false; +} + +bool QScriptClassData::removeMember(const QScriptValueImpl &, + const QScript::Member &) +{ + return true; +} + +bool QScriptClassData::implementsHasInstance(const QScriptValueImpl &) +{ + return false; +} + +bool QScriptClassData::hasInstance(const QScriptValueImpl &, + const QScriptValueImpl &) +{ + Q_ASSERT_X(false, "QScriptClassData::hasInstance()", + "implement if implementsHasInstance() returns true"); + return false; +} + +QScriptClassDataIterator *QScriptClassData::newIterator(const QScriptValueImpl &) +{ + return 0; +} + +QScriptClassDataIterator::QScriptClassDataIterator() +{ +} + +QScriptClassDataIterator::~QScriptClassDataIterator() +{ +} + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptclassdata_p.h b/src/script/qscriptclassdata_p.h new file mode 100644 index 0000000..e801ed8 --- /dev/null +++ b/src/script/qscriptclassdata_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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 QSCRIPTCLASSDATA_P_H +#define QSCRIPTCLASSDATA_P_H + +#include "qscriptglobals_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptValueImpl; +class QScriptNameIdImpl; +class QScriptClassDataIterator; + +namespace QScript { + class Member; +} + +class QScriptClassData +{ +protected: + QScriptClassData(); + +public: + virtual ~QScriptClassData(); + + virtual void mark(const QScriptValueImpl &object, int generation); + virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &obj, const QScript::Member &m, + QScriptValueImpl *result); + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value); + virtual bool removeMember(const QScriptValueImpl &object, + const QScript::Member &member); + virtual bool implementsHasInstance(const QScriptValueImpl &object); + virtual bool hasInstance(const QScriptValueImpl &object, + const QScriptValueImpl &value); + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object); + +private: + Q_DISABLE_COPY(QScriptClassData) +}; + +class QScriptClassDataIterator +{ +protected: + QScriptClassDataIterator(); + +public: + virtual ~QScriptClassDataIterator(); + + virtual bool hasNext() const = 0; + virtual void next(QScript::Member *member) = 0; + + virtual bool hasPrevious() const = 0; + virtual void previous(QScript::Member *member) = 0; + + virtual void toFront() = 0; + virtual void toBack() = 0; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTCLASSDATA_P_H diff --git a/src/script/qscriptclassinfo_p.h b/src/script/qscriptclassinfo_p.h new file mode 100644 index 0000000..8eab8a3 --- /dev/null +++ b/src/script/qscriptclassinfo_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 QSCRIPTCLASSINFO_P_H +#define QSCRIPTCLASSINFO_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 "qscriptclassdata_p.h" + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +class QScriptClassInfo +{ +public: + enum Type { + FunctionBased = 0x40000000, + + ObjectType = 1, + FunctionType = 2 | FunctionBased, + ArrayType = 3, + StringType = 4, + BooleanType = 5, + NumberType = 6, + DateType = 7, + RegExpType = 8, + ErrorType = 9, + + VariantType = 10, + QObjectType = 11, + QMetaObjectType = 12 | FunctionBased, + + // Types used by the runtime + ActivationType = 100, + EnumerationType = 101, + + CustomType = 1000, + + TypeMask = 0x0000FFFF + }; + + inline QScriptClassInfo(QScriptEnginePrivate *engine, Type type, const QString &name) + : m_engine(engine), m_type(type), m_name(name), m_data(0) { } + inline ~QScriptClassInfo() { delete m_data; } + + inline QScriptEnginePrivate *engine() const + { return m_engine; } + inline Type type() const + { return m_type; } + inline QString name() const + { return m_name; } + + inline void setData(QScriptClassData *data) + { m_data = data; } + QScriptClassData *data() const + { return m_data; } + +private: + QScriptEnginePrivate *m_engine; + Type m_type; + QString m_name; + QScriptClassData *m_data; + +private: + Q_DISABLE_COPY(QScriptClassInfo) +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTCLASSINFO_P_H diff --git a/src/script/qscriptclasspropertyiterator.cpp b/src/script/qscriptclasspropertyiterator.cpp new file mode 100644 index 0000000..96f34d5 --- /dev/null +++ b/src/script/qscriptclasspropertyiterator.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** 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 "qscriptclasspropertyiterator.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptclasspropertyiterator_p.h" +#include "qscriptstring.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.4 + \class QScriptClassPropertyIterator + + \brief The QScriptClassPropertyIterator class provides an iterator interface for custom Qt Script objects. + + \ingroup script + + This class is only relevant if you have subclassed QScriptClass and + want to provide enumeration of your custom properties (e.g. when + objects of your class are used with QScriptValueIterator, or with + the for-in statement in scripts). + + The object() function returns the Qt Script object the iterator is + traversing. + + toFront(), hasNext() and next() provide forward iteration. + + toBack(), hasPrevious() and previous() provide backward iteration. + + name(), id() and flags() return information about the last property + that was jumped over using next() or previous(). + + \sa QScriptClass::newIterator(), QScriptValueIterator +*/ + +QScriptClassPropertyIteratorPrivate::QScriptClassPropertyIteratorPrivate(QScriptClassPropertyIterator *q) + : q_ptr(q) +{ +} + +QScriptClassPropertyIteratorPrivate::~QScriptClassPropertyIteratorPrivate() +{ +} + +/*! + Constructs an iterator for traversing \a object. + + Subclasses should ensure that the iterator is set to the front of the + sequence of properties (before the first property). +*/ +QScriptClassPropertyIterator::QScriptClassPropertyIterator(const QScriptValue &object) + : d_ptr(new QScriptClassPropertyIteratorPrivate(this)) +{ + d_ptr->object = object; +} + +/*! + \internal +*/ +QScriptClassPropertyIterator::QScriptClassPropertyIterator(const QScriptValue &object, + QScriptClassPropertyIteratorPrivate &dd) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; + d_ptr->object = object; +} + +/*! + Destroys the iterator. +*/ +QScriptClassPropertyIterator::~QScriptClassPropertyIterator() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Returns the Qt Script object this iterator is traversing. +*/ +QScriptValue QScriptClassPropertyIterator::object() const +{ + Q_D(const QScriptClassPropertyIterator); + return d->object; +} + +/*! + \fn bool QScriptClassPropertyIterator::hasNext() const + + Returns true if there is at least one item ahead of the iterator + (i.e. the iterator is \e not at the back of the property sequence); + otherwise returns false. + + \sa next(), hasPrevious() +*/ + +/*! + \fn void QScriptClassPropertyIterator::next() + + Advances the iterator by one position. + + Calling this function on an iterator located at the back of the + container leads to undefined results. + + \sa hasNext(), previous(), name() +*/ + +/*! + \fn bool QScriptClassPropertyIterator::hasPrevious() const + + Returns true if there is at least one item behind the iterator + (i.e. the iterator is \e not at the front of the property sequence); + otherwise returns false. + + \sa previous(), hasNext() +*/ + +/*! + \fn void QScriptClassPropertyIterator::previous() + + Moves the iterator back by one position. + + Calling this function on an iterator located at the front of the + container leads to undefined results. + + \sa hasPrevious(), next(), name() +*/ + +/*! + \fn void QScriptClassPropertyIterator::toFront() + + Moves the iterator to the front of the QScriptValue (before the + first property). + + \sa toBack(), next() +*/ + +/*! + \fn void QScriptClassPropertyIterator::toBack() + + Moves the iterator to the back of the QScriptValue (after the + last property). + + \sa toFront(), previous() +*/ + +/*! + \fn QScriptString QScriptClassPropertyIterator::name() const + + Returns the name of the last property that was jumped over using + next() or previous(). + + \sa id() +*/ + +/*! + \fn uint QScriptClassPropertyIterator::id() const + + Returns the id of the last property that was jumped over using + next() or previous(). + + The default implementation returns 0. + + \sa name() +*/ +uint QScriptClassPropertyIterator::id() const +{ + return 0; +} + +/*! + Returns the flags of the last property that was jumped over using + next() or previous(). + + The default implementation calls the propertyFlags() function of + object() with argument name(). +*/ +QScriptValue::PropertyFlags QScriptClassPropertyIterator::flags() const +{ + return object().propertyFlags(name()); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptclasspropertyiterator.h b/src/script/qscriptclasspropertyiterator.h new file mode 100644 index 0000000..2041a65 --- /dev/null +++ b/src/script/qscriptclasspropertyiterator.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 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 QSCRIPTCLASSPROPERTYITERATOR_H +#define QSCRIPTCLASSPROPERTYITERATOR_H + +#include <QtCore/qstring.h> + +#ifndef QT_NO_SCRIPT + +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptClassPropertyIteratorPrivate; +class Q_SCRIPT_EXPORT QScriptClassPropertyIterator +{ +protected: + QScriptClassPropertyIterator(const QScriptValue &object); + +public: + virtual ~QScriptClassPropertyIterator(); + + QScriptValue object() const; + + virtual bool hasNext() const = 0; + virtual void next() = 0; + + virtual bool hasPrevious() const = 0; + virtual void previous() = 0; + + virtual void toFront() = 0; + virtual void toBack() = 0; + + virtual QScriptString name() const = 0; + virtual uint id() const; + virtual QScriptValue::PropertyFlags flags() const; + +protected: + QScriptClassPropertyIterator(const QScriptValue &object, QScriptClassPropertyIteratorPrivate &dd); + QScriptClassPropertyIteratorPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QScriptClassPropertyIterator) + Q_DISABLE_COPY(QScriptClassPropertyIterator) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptclasspropertyiterator_p.h b/src/script/qscriptclasspropertyiterator_p.h new file mode 100644 index 0000000..b1d7467 --- /dev/null +++ b/src/script/qscriptclasspropertyiterator_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 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 QSCRIPTCLASSPROPERTYITERATOR_P_H +#define QSCRIPTCLASSPROPERTYITERATOR_P_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalue.h" + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptClassPropertyIterator; +class QScriptClassPropertyIteratorPrivate +{ + Q_DECLARE_PUBLIC(QScriptClassPropertyIterator) +public: + QScriptClassPropertyIteratorPrivate(QScriptClassPropertyIterator*); + virtual ~QScriptClassPropertyIteratorPrivate(); + + QScriptValue object; + + QScriptClassPropertyIterator *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptcompiler.cpp b/src/script/qscriptcompiler.cpp new file mode 100644 index 0000000..157e466 --- /dev/null +++ b/src/script/qscriptcompiler.cpp @@ -0,0 +1,2111 @@ +/**************************************************************************** +** +** 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 "qscriptcompiler_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptast_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { + +class Compare : protected AST::Visitor +{ +public: + bool operator()(AST::ExpressionNode *e1, AST::ExpressionNode *e2) + { + if (!e1 || !e2) + return (e1 == e2); + + if (e1->kind != e2->kind) + return false; + + m_e2 = e2; + m_equal = false; + e1->accept(this); + return m_equal; + } + +protected: + virtual bool visit(AST::ThisExpression *) + { + m_equal = true; + return false; + } + virtual bool visit(AST::NullExpression *) + { + m_equal = true; + return false; + } + virtual bool visit(AST::VoidExpression *) + { + m_equal = true; + return false; + } + virtual bool visit(AST::FalseLiteral *) + { + m_equal = true; + return false; + } + virtual bool visit(AST::TrueLiteral *) + { + m_equal = true; + return false; + } + virtual bool visit(AST::NumericLiteral *e1) + { + AST::NumericLiteral *e2 = static_cast<AST::NumericLiteral*>(m_e2); + m_equal = (e1->value == e2->value); + return false; + } + virtual bool visit(AST::RegExpLiteral *e1) + { + AST::RegExpLiteral *e2 = static_cast<AST::RegExpLiteral*>(m_e2); + m_equal = (e1->pattern == e2->pattern) + && (e1->flags == e2->flags); + return false; + } + virtual bool visit(AST::StringLiteral *e1) + { + AST::StringLiteral *e2 = static_cast<AST::StringLiteral*>(m_e2); + m_equal = (e1->value == e2->value); + return false; + } + virtual bool visit(AST::IdentifierExpression *e1) + { + AST::IdentifierExpression *e2 = static_cast<AST::IdentifierExpression*>(m_e2); + m_equal = (e1->name == e2->name); + return false; + } + virtual bool visit(AST::ArrayMemberExpression *e1) + { + AST::ArrayMemberExpression *e2 = static_cast<AST::ArrayMemberExpression*>(m_e2); + m_equal = operator()(e1->base, e2->base) + && operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::FieldMemberExpression *e1) + { + AST::FieldMemberExpression *e2 = static_cast<AST::FieldMemberExpression*>(m_e2); + m_equal = (e1->name == e2->name) && operator()(e1->base, e2->base); + return false; + } + virtual bool visit(AST::BinaryExpression *e1) + { + AST::BinaryExpression *e2 = static_cast<AST::BinaryExpression*>(m_e2); + m_equal = (e1->op == e2->op) && operator()(e1->left, e2->left) + && operator()(e1->right, e2->right); + return false; + } + virtual bool visit(AST::ConditionalExpression *e1) + { + AST::ConditionalExpression *e2 = static_cast<AST::ConditionalExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression) + && operator()(e1->ok, e2->ok) + && operator()(e1->ko, e2->ko); + return false; + } + virtual bool visit(AST::TypeOfExpression *e1) + { + AST::TypeOfExpression *e2 = static_cast<AST::TypeOfExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::UnaryPlusExpression *e1) + { + AST::UnaryPlusExpression *e2 = static_cast<AST::UnaryPlusExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::UnaryMinusExpression *e1) + { + AST::UnaryMinusExpression *e2 = static_cast<AST::UnaryMinusExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::TildeExpression *e1) + { + AST::TildeExpression *e2 = static_cast<AST::TildeExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::NotExpression *e1) + { + AST::NotExpression *e2 = static_cast<AST::NotExpression*>(m_e2); + m_equal = operator()(e1->expression, e2->expression); + return false; + } + virtual bool visit(AST::Expression *) + { return false; } + virtual bool visit(AST::ArrayLiteral *) + { return false; } + virtual bool visit(AST::ObjectLiteral *) + { return false; } + virtual bool visit(AST::CallExpression *) + { return false; } + virtual bool visit(AST::DeleteExpression *) + { return false; } + virtual bool visit(AST::FunctionExpression *) + { return false; } + virtual bool visit(AST::NewExpression *) + { return false; } + virtual bool visit(AST::NewMemberExpression *) + { return false; } + virtual bool visit(AST::PostDecrementExpression *) + { return false; } + virtual bool visit(AST::PostIncrementExpression *) + { return false; } + virtual bool visit(AST::PreDecrementExpression *) + { return false; } + virtual bool visit(AST::PreIncrementExpression *) + { return false; } + +private: + AST::ExpressionNode *m_e2; + bool m_equal; +}; + +class FetchName: protected AST::Visitor +{ +public: + inline FetchName(QScriptEnginePrivate *e): + eng(e), name(0) {} + + QScriptNameIdImpl *operator() (AST::PropertyName *node) + { + name = 0; + node->accept(this); + return name; + } + +protected: + virtual bool visit(AST::IdentifierPropertyName *node) + { + name = node->id; + return false; + } + + virtual bool visit(AST::StringLiteralPropertyName *node) + { + name = node->id; + return false; + } + + virtual bool visit(AST::NumericLiteralPropertyName *node) + { + name = eng->nameId(QString::number(node->id), /*persistent=*/false); // ### don't use QString::number + name->persistent = true; // ### remove + return false; + } + +private: + QScriptEnginePrivate *eng; + QScriptNameIdImpl *name; +}; + +class EmptySourceElements: protected AST::Visitor +{ +public: + EmptySourceElements(QScriptEngine *d): + driver(d), empty(false) {} + + inline bool operator () (AST::Node *) + { + empty = false; + return empty; + } + +private: + QScriptEngine *driver; + bool empty; +}; + +class DeclareLocals: protected AST::Visitor +{ +public: + DeclareLocals(Compiler *c): + compiler(c), + eng(c->engine()) + { + } + + void operator () (AST::Node *node) + { + if (node) + node->accept(this); + } + +protected: + virtual bool visit(AST::FunctionDeclaration *node) + { + compiler->iDeclareLocal(node->name, /*readOnly=*/false); + return false; + } + + virtual bool visit(AST::FunctionExpression *) + { return false; } + + virtual bool visit(AST::VariableDeclaration *node) + { + compiler->iDeclareLocal(node->name, node->readOnly); + return false; + } + +private: + Compiler *compiler; + QScriptEnginePrivate *eng; +}; + +Compiler::Compiler(QScriptEnginePrivate *eng): + m_eng(eng), + m_generateReferences(0), m_iterationStatement(0), + m_switchStatement(0), m_withStatement(0), + m_generateLeaveWithOnBreak(0), m_generateFastArgumentLookup(0), + m_parseStatements(0), m_pad(0), + m_topLevelCompiler(false), + m_activeLoop(0) +{ +} + +Compiler::~Compiler() +{ +} + +bool Compiler::topLevelCompiler() const +{ + return m_topLevelCompiler; +} + +void Compiler::setTopLevelCompiler(bool b) +{ + m_topLevelCompiler = b; +} + + CompilationUnit Compiler::compile(AST::Node *node, const QList<QScriptNameIdImpl *> &formals) +{ + m_formals = formals; + m_generateReferences = 0; + m_iterationStatement = 0; + m_switchStatement = 0; + m_withStatement = 0; + m_generateLeaveWithOnBreak = 0; + m_generateFastArgumentLookup = 0; + m_parseStatements = 0; + m_pad = 0; + m_instructions.clear(); + m_exceptionHandlers.clear(); + m_generateFastArgumentLookup = false; // ### !formals.isEmpty(); // ### disabled for now.. it's buggy :( + + m_compilationUnit = CompilationUnit(); + + if (node) + node->accept(this); + + // add a terminator + if (topLevelCompiler()) { + iHalt(); + } else if (m_instructions.isEmpty() || m_instructions.last().op != QScriptInstruction::OP_Ret) { + iLoadUndefined(); + iRet(); + } + + m_compilationUnit.setInstructions(m_instructions); + m_compilationUnit.setExceptionHandlers(m_exceptionHandlers); + return m_compilationUnit; +} + +bool Compiler::preVisit(AST::Node *) +{ + return m_compilationUnit.isValid(); +} + +bool Compiler::visit(AST::SourceElements *node) +{ + DeclareLocals declareLocals(this); + declareLocals(node); + + bool was = changeParseStatements(false); + + for (AST::SourceElements *it = node; it != 0; it = it->next) + it->element->accept(this); + + changeParseStatements(true); + + for (AST::SourceElements *it = node; it != 0; it = it->next) + it->element->accept(this); + + changeParseStatements(was); + + return false; +} + +bool Compiler::visit(AST::StatementList *) +{ + return true; +} + +bool Compiler::visit(AST::FunctionSourceElement *) +{ + return m_parseStatements == 0; +} + +bool Compiler::visit(AST::StatementSourceElement *) +{ + return m_parseStatements; +} + +bool Compiler::visit(AST::ThisExpression *) +{ + iLoadThis(); + return false; +} + +bool Compiler::visit(AST::NullExpression *) +{ + iLoadNull(); + return false; +} + +bool Compiler::visit(AST::RegExpLiteral *node) +{ + Q_ASSERT(node->pattern != 0); + + if (node->flags) + iNewRegExp(node->pattern, node->flags); + else + iNewRegExp(node->pattern); + + return false; +} + +bool Compiler::visit(AST::NumericLiteral *node) +{ + iLoadNumber(node->value); + return false; +} + +bool Compiler::visit(AST::StringLiteral *node) +{ + iNewString(node->value); + + return false; +} + +bool Compiler::visit(AST::ObjectLiteral *node) +{ + iNewObject(); + + FetchName fetchName(m_eng); + bool was = generateReferences(false); + for (AST::PropertyNameAndValueList *it = node->properties; it != 0; it = it->next) { + iLine(it->value); + iDuplicate(); + + QScriptNameIdImpl *name = fetchName(it->name); + Q_ASSERT(name != 0); + iLoadString(name); + iMakeReference(); + + it->value->accept(this); + iPutField(); + } + generateReferences(was); + + return false; +} + +bool Compiler::visit(AST::IdentifierExpression *node) +{ + Q_ASSERT(node->name != 0); + + if (node->name == m_eng->idTable()->id_arguments) + iLazyArguments(); + if (m_generateReferences) + iResolve(node->name); + else + iFetch(node->name); + + return false; +} + +bool Compiler::visit(AST::FunctionDeclaration *node) +{ + iLoadActivation(); + iLoadString(node->name); + iMakeReference(); + iNewClosure(node); + iPutField(); + return false; +} + +bool Compiler::visit(AST::FunctionExpression *node) +{ + iNewClosure(node); + if (node->name) { + iDuplicate(); + iLoadActivation(); + iSwap(); + iLoadString(node->name); + iSwap(); + iMakeReference(); + iSwap(); + iPutField(); + } + return false; +} + +bool Compiler::visit(AST::CallExpression *node) +{ + bool was = generateReferences(true); + node->base->accept(this); + generateReferences(false); + + int argc = 0; + for (AST::ArgumentList *it = node->arguments; it != 0; it = it->next) { + it->expression->accept(this); + ++argc; + } + + generateReferences(was); + + iCall(argc); + return false; +} + +bool Compiler::visit(AST::NewExpression *node) +{ + bool was = generateReferences(true); + node->expression->accept(this); + generateReferences(was); + iNew(0); + return false; +} + +bool Compiler::visit(AST::NewMemberExpression *node) +{ + bool was = generateReferences(true); + node->base->accept(this); + generateReferences(false); + + int argc = 0; + for (AST::ArgumentList *it = node->arguments; it != 0; it = it->next) { + it->expression->accept(this); + ++argc; + } + + generateReferences(was); + + iNew(argc); + return false; +} + +bool Compiler::visit(AST::FieldMemberExpression *node) +{ + bool was = generateReferences(false); + node->base->accept(this); + generateReferences(was); + + iLoadString(node->name); + + if (! was) + iFetchField(); + else + iMakeReference(); + + return false; +} + +bool Compiler::visit(AST::ArrayMemberExpression *node) +{ + bool was = generateReferences(false); + node->base->accept(this); + node->expression->accept(this); + generateReferences(was); + + if (! was) + iFetchField(); + else + iMakeReference(); + + return false; +} + +bool Compiler::visit(AST::PostIncrementExpression *node) +{ + bool was = generateReferences(true); + node->base->accept(this); + generateReferences(was); + iPostIncr(); + + return false; +} + +bool Compiler::visit(AST::PostDecrementExpression *node) +{ + bool was = generateReferences(true); + node->base->accept(this); + generateReferences(was); + iPostDecr(); + + return false; +} + +bool Compiler::visit(AST::PreIncrementExpression *node) +{ + bool was = generateReferences(true); + node->expression->accept(this); + generateReferences(was); + iIncr(); + return false; +} + +bool Compiler::visit(AST::PreDecrementExpression *node) +{ + bool was = generateReferences(true); + node->expression->accept(this); + generateReferences(was); + iDecr(); + return false; +} + +void Compiler::endVisit(AST::NotExpression *) +{ + iNot(); +} + +void Compiler::endVisit(AST::TildeExpression *) +{ + iBitNot(); +} + +bool Compiler::visit(AST::ThrowStatement *node) +{ + iLine(node); + return true; +} + +bool Compiler::visit(AST::TryStatement *node) +{ + int start = nextInstructionOffset(); + if (node->statement) + node->statement->accept(this); + int end = nextInstructionOffset(); + if (node->catchExpression) { + iBranch(0); // skip the catch if no exception + ExceptionHandlerDescriptor ehd(start, end, nextInstructionOffset()); + m_exceptionHandlers.append(ehd); + iBeginCatch(node->catchExpression->name); + node->catchExpression->statement->accept(this); + iEndCatch(); + patchInstruction(end, nextInstructionOffset() - end); + } + if (node->finallyExpression) { + if (!node->catchExpression) { + ExceptionHandlerDescriptor ehd(start, end, nextInstructionOffset()); + m_exceptionHandlers.prepend(ehd); + } + node->finallyExpression->statement->accept(this); + } + return false; +} + +void Compiler::endVisit(AST::ThrowStatement *node) +{ + if (! node->expression) + iLoadUndefined(); + + iThrow(); +} + +void Compiler::endVisit(AST::VoidExpression *) +{ + iPop(); + iLoadUndefined(); +} + +bool Compiler::visit(AST::TypeOfExpression *node) +{ + bool was = generateReferences(true); + node->expression->accept(this); + generateReferences(was); + iTypeOf(); + return false; +} + +bool Compiler::visit(AST::DeleteExpression *node) +{ + bool was = generateReferences(true); + node->expression->accept(this); + generateReferences(was); + iDelete(); + return false; +} + +bool Compiler::visit(AST::ReturnStatement *node) +{ + if (topLevelCompiler()) { + m_compilationUnit.setError(QString::fromUtf8("return outside function body"), + node->startLine); + return false; + } + iLine(node); + return true; +} + +void Compiler::endVisit(AST::ReturnStatement *node) +{ + if (! node->expression) + iLoadUndefined(); + + iRet(); +} + +bool Compiler::visit(AST::VariableStatement *node) +{ + AST::VariableDeclarationList *lst = node->declarations; + while (lst) { + if (lst->declaration->expression) { + iLine(node); + break; + } + lst = lst->next; + } + return true; +} + +bool Compiler::visit(AST::VariableDeclaration *node) +{ + if (node->expression != 0) { + iResolve(node->name); + node->expression->accept(this); + iAssign(); + iPop(); + } + + return false; +} + +bool Compiler::visit(AST::ConditionalExpression *node) +{ + node->expression->accept(this); + + int cond = nextInstructionOffset(); + iBranchFalse(0); + + node->ok->accept(this); + + if (! node->ko) { + patchInstruction(cond, nextInstructionOffset() - cond); + } else { + int terminator = nextInstructionOffset(); + iBranch(0); + node->ko->accept(this); + + patchInstruction(cond, terminator + 1 - cond); + patchInstruction(terminator, nextInstructionOffset() - terminator); + } + + return false; +} + +bool Compiler::visit(AST::IfStatement *node) +{ + iLine(node); + node->expression->accept(this); + + int cond = nextInstructionOffset(); + iBranchFalse(0); + + node->ok->accept(this); + + if (! node->ko) { + patchInstruction(cond, nextInstructionOffset() - cond); + } else { + int terminator = nextInstructionOffset(); + iBranch(0); + node->ko->accept(this); + + patchInstruction(cond, terminator + 1 - cond); + patchInstruction(terminator, nextInstructionOffset() - terminator); + } + if (!m_instructions.isEmpty() && m_instructions.last().op == QScriptInstruction::OP_Ret) + iNop(); + + return false; +} + +bool Compiler::visit(AST::Block *node) +{ + if (node->statements && m_loops.contains(node)) { + Loop &loop = m_loops[node]; + + node->statements->accept(this); + + loop.breakLabel.offset = nextInstructionOffset(); + + foreach (int index, loop.breakLabel.uses) { + patchInstruction(index, loop.breakLabel.offset - index); + } + + return false; + } + + return true; +} + +bool Compiler::visit(AST::WhileStatement *node) +{ + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + m_activeLoop->continueLabel.offset = nextInstructionOffset(); + + iLine(node); + int again = nextInstructionOffset(); + node->expression->accept(this); + + int cond = nextInstructionOffset(); + iBranchFalse(0); + + bool was = iterationStatement(true); + bool was2 = generateLeaveOnBreak(false); + node->statement->accept(this); + generateLeaveOnBreak(was2); + iterationStatement(was); + + iBranch(again - nextInstructionOffset()); + patchInstruction(cond, nextInstructionOffset() - cond); + + m_activeLoop->breakLabel.offset = nextInstructionOffset(); + + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, m_activeLoop->breakLabel.offset - index); + } + + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, m_activeLoop->continueLabel.offset - index); + } + + changeActiveLoop(previousLoop); + m_loops.remove(node); + + return false; +} + +bool Compiler::visit(AST::DoWhileStatement *node) +{ + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + int again = nextInstructionOffset(); + iLine(node); + bool was = iterationStatement(true); + node->statement->accept(this); + iterationStatement(was); + + m_activeLoop->continueLabel.offset = nextInstructionOffset(); + + node->expression->accept(this); + + iBranchTrue(again - nextInstructionOffset()); + m_activeLoop->breakLabel.offset = nextInstructionOffset(); + + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, m_activeLoop->breakLabel.offset - index); + } + + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, m_activeLoop->continueLabel.offset - index); + } + + changeActiveLoop(previousLoop); + m_loops.remove(node); + + return false; +} + +bool Compiler::visit(AST::ForEachStatement *node) +{ + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + + iLine(node); + node->expression->accept(this); + iNewEnumeration(); + iDuplicate(); + iToFirstElement(); + + int again = nextInstructionOffset(); + m_activeLoop->continueLabel.offset = again; + iDuplicate(); + iHasNextElement(); + int cond = nextInstructionOffset(); + iBranchFalse(0); + bool was = generateReferences(true); + node->initialiser->accept(this); + generateReferences(was); + iNextElement(); + iAssign(); + iPop(); + was = iterationStatement(true); + node->statement->accept(this); + iterationStatement(was); + iBranch(again - nextInstructionOffset()); + patchInstruction(cond, nextInstructionOffset() - cond); + + m_activeLoop->breakLabel.offset = nextInstructionOffset(); + iPop(); // pop the Enumeration + + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, m_activeLoop->breakLabel.offset - index); + } + + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, m_activeLoop->continueLabel.offset - index); + } + + changeActiveLoop(previousLoop); + m_loops.remove(node); + + return false; +} + +bool Compiler::visit(AST::LocalForEachStatement *node) +{ + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + + iLine(node); + node->declaration->accept(this); + node->expression->accept(this); + iNewEnumeration(); + iDuplicate(); + iToFirstElement(); + + int again = nextInstructionOffset(); + m_activeLoop->continueLabel.offset = again; + iDuplicate(); + iHasNextElement(); + int cond = nextInstructionOffset(); + iBranchFalse(0); + iResolve(node->declaration->name); + iNextElement(); + iAssign(); + iPop(); + bool was = iterationStatement(true); + node->statement->accept(this); + iterationStatement(was); + iBranch(again - nextInstructionOffset()); + patchInstruction(cond, nextInstructionOffset() - cond); + + m_activeLoop->breakLabel.offset = nextInstructionOffset(); + iPop(); // pop the Enumeration + + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, m_activeLoop->breakLabel.offset - index); + } + + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, m_activeLoop->continueLabel.offset - index); + } + + changeActiveLoop(previousLoop); + m_loops.remove(node); + + return false; +} + +void Compiler::visitForInternal(AST::Statement *node, AST::ExpressionNode *condition, AST::Statement *statement, AST::ExpressionNode *expression) +{ + Q_ASSERT(statement != 0); + + int again = nextInstructionOffset(); + if (condition != 0) { +// iLine(condition); + condition->accept(this); + } else { +// iLine(node); + iLoadNumber(1); + } + + int cond = nextInstructionOffset(); + iBranchFalse(0); + + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + + bool was = iterationStatement(true); + statement->accept(this); + iterationStatement(was); + + m_activeLoop->continueLabel.offset = nextInstructionOffset(); + + if (expression != 0) { + expression->accept(this); + iPop(); + } + + iBranch(again - nextInstructionOffset()); + patchInstruction(cond, nextInstructionOffset() - cond); + + m_activeLoop->breakLabel.offset = nextInstructionOffset(); + + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, m_activeLoop->breakLabel.offset - index); + } + + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, m_activeLoop->continueLabel.offset - index); + } + + changeActiveLoop(previousLoop); + m_loops.remove(node); +} + +bool Compiler::visit(AST::ForStatement *node) +{ + iLine(node); + + if (node->initialiser != 0) { + node->initialiser->accept(this); + iPop(); + } + + visitForInternal(node, node->condition, node->statement, node->expression); + return false; +} + +bool Compiler::visit(AST::LocalForStatement *node) +{ + iLine(node); + + if (node->declarations) + node->declarations->accept(this); + + visitForInternal(node, node->condition, node->statement, node->expression); + return false; +} + +bool Compiler::isAssignmentOperator(int op) const +{ + switch (op) { + + case QSOperator::Assign: + case QSOperator::InplaceAnd: + case QSOperator::InplaceSub: + case QSOperator::InplaceDiv: + case QSOperator::InplaceAdd: + case QSOperator::InplaceLeftShift: + case QSOperator::InplaceMod: + case QSOperator::InplaceMul: + case QSOperator::InplaceOr: + case QSOperator::InplaceRightShift: + case QSOperator::InplaceURightShift: + case QSOperator::InplaceXor: + return true; + + default: + break; + + } + + return false; +} + +int Compiler::inplaceAssignmentOperator(int op) const +{ + switch (op) { + case QSOperator::BitAnd: + return QSOperator::InplaceAnd; + case QSOperator::Sub: + return QSOperator::InplaceSub; + case QSOperator::Div: + return QSOperator::InplaceDiv; + case QSOperator::Add: + return QSOperator::InplaceAdd; + case QSOperator::LShift: + return QSOperator::InplaceLeftShift; + case QSOperator::Mod: + return QSOperator::InplaceMod; + case QSOperator::Mul: + return QSOperator::InplaceMul; + case QSOperator::BitOr: + return QSOperator::InplaceOr; + case QSOperator::RShift: + return QSOperator::InplaceRightShift; + case QSOperator::URShift: + return QSOperator::InplaceURightShift; + case QSOperator::BitXor: + return QSOperator::InplaceXor; + + default: + break; + + } + + return(-1); +} + +bool Compiler::visit(AST::Expression *node) +{ + node->left->accept(this); + iPop(); // ### or iSync? + node->right->accept(this); + return false; +} + +bool Compiler::visit(AST::BinaryExpression *node) +{ + if (isAssignmentOperator(node->op)) { + bool was = generateReferences(true); + node->left->accept(this); + generateReferences(was); + } else { + node->left->accept(this); + } + + int address = 0; + if (node->op == QSOperator::Or || node->op == QSOperator::And) { + iDuplicate(); + address = nextInstructionOffset(); + if (node->op == QSOperator::Or) + iBranchTrue(0); + else + iBranchFalse(0); + iPop(); + } + + int op = node->op; + Compare compare; + if ((op == QSOperator::Assign) && node->right->binaryExpressionCast() + && (inplaceAssignmentOperator(node->right->binaryExpressionCast()->op) != -1) + && compare(node->left, node->right->binaryExpressionCast()->left)) { + // node->left is equivalent to node->right->left, so we generate + // x op= y rather than x = x op y + op = inplaceAssignmentOperator(node->right->binaryExpressionCast()->op); + node->right->binaryExpressionCast()->right->accept(this); + } else { + node->right->accept(this); + } + + switch (op) { + + case QSOperator::Assign: + iAssign(); + break; + + case QSOperator::InplaceAnd: + iInplaceAnd(); + break; + + case QSOperator::InplaceSub: + iInplaceSub(); + break; + + case QSOperator::InplaceDiv: + iInplaceDiv(); + break; + + case QSOperator::InplaceAdd: + iInplaceAdd(); + break; + + case QSOperator::InplaceLeftShift: + iInplaceLeftShift(); + break; + + case QSOperator::InplaceMod: + iInplaceMod(); + break; + + case QSOperator::InplaceMul: + iInplaceMul(); + break; + + case QSOperator::InplaceOr: + iInplaceOr(); + break; + + case QSOperator::InplaceRightShift: + iInplaceRightShift(); + break; + + case QSOperator::InplaceURightShift: + iInplaceURightShift(); + break; + + case QSOperator::InplaceXor: + iInplaceXor(); + break; + + case QSOperator::BitAnd: + iBitAnd(); + break; + + case QSOperator::BitOr: + iBitOr(); + break; + + case QSOperator::BitXor: + iBitXor(); + break; + + case QSOperator::LShift: + iLeftShift(); + break; + + case QSOperator::Mod: + iMod(); + break; + + case QSOperator::RShift: + iRightShift(); + break; + + case QSOperator::URShift: + iURightShift(); + break; + + case QSOperator::InstanceOf: + iInstanceOf(); + break; + + case QSOperator::Add: + iAdd(); + break; + + case QSOperator::And: + patchInstruction(address, nextInstructionOffset() - address); + break; + + case QSOperator::Div: + iDiv(); + break; + + case QSOperator::Equal: + iEqual(); + break; + + case QSOperator::Ge: + iGreatOrEqual(); + break; + + case QSOperator::Gt: + iGreatThan(); + break; + + case QSOperator::Le: + iLessOrEqual(); + break; + + case QSOperator::Lt: + iLessThan(); + break; + + case QSOperator::Mul: + iMul(); + break; + + case QSOperator::NotEqual: + iNotEqual(); + break; + + case QSOperator::Or: + patchInstruction(address, nextInstructionOffset() - address); + break; + + case QSOperator::Sub: + iSub(); + break; + + case QSOperator::StrictEqual: + iStrictEqual(); + break; + + case QSOperator::StrictNotEqual: + iStrictNotEqual(); + break; + + case QSOperator::In: + iIn(); + break; + } + + return false; +} + +bool Compiler::visit(AST::TrueLiteral *) +{ + iLoadTrue(); + return false; +} + +bool Compiler::visit(AST::FalseLiteral *) +{ + iLoadFalse(); + return false; +} + +bool Compiler::visit(AST::SwitchStatement *node) +{ + iLine(node); + Loop *previousLoop = changeActiveLoop(&m_loops[node]); + + node->expression->accept(this); + + bool was = switchStatement(true); + + AST::CaseClauses *clauses; + int skipIndex = -1; + int fallthroughIndex = -1; + // ### make a function for this + for (clauses = node->block->clauses; clauses != 0; clauses = clauses->next) { + AST::CaseClause *clause = clauses->clause; + if (skipIndex != -1) + patchInstruction(skipIndex, nextInstructionOffset() - skipIndex); + + iDuplicate(); // expression + clause->expression->accept(this); + iStrictEqual(); + skipIndex = nextInstructionOffset(); + iBranchFalse(0); // next case + + if (fallthroughIndex != -1) // previous case falls through to here + patchInstruction(fallthroughIndex, nextInstructionOffset() - fallthroughIndex); + + int breaksBefore = m_activeLoop->breakLabel.uses.count(); + if (clause->statements) + clause->statements->accept(this); + int breaksAfter = m_activeLoop->breakLabel.uses.count(); + if (breaksAfter == breaksBefore) { // fallthrough + fallthroughIndex = nextInstructionOffset(); + iBranch(0); + } else { // no fallthrough (break) + fallthroughIndex = -1; + } + } + + if (fallthroughIndex != -1) { + patchInstruction(fallthroughIndex, nextInstructionOffset() - fallthroughIndex); + fallthroughIndex = -1; + } + + int defaultIndex = -1; + if (node->block->defaultClause) { + int skipDefaultIndex = -1; + if (!node->block->clauses && node->block->moreClauses) { + skipDefaultIndex = nextInstructionOffset(); + iBranch(0); + } + defaultIndex = nextInstructionOffset(); + int breaksBefore = m_activeLoop->breakLabel.uses.count(); + if (node->block->defaultClause->statements) + node->block->defaultClause->statements->accept(this); + int breaksAfter = m_activeLoop->breakLabel.uses.count(); + if (breaksAfter == breaksBefore) { // fallthrough + fallthroughIndex = nextInstructionOffset(); + iBranch(0); + } else { // no fallthrough (break) + fallthroughIndex = -1; + } + if (skipDefaultIndex != -1) + patchInstruction(skipDefaultIndex, nextInstructionOffset() - skipDefaultIndex); + } + + for (clauses = node->block->moreClauses; clauses != 0; clauses = clauses->next) { + AST::CaseClause *clause = clauses->clause; + if (skipIndex != -1) + patchInstruction(skipIndex, nextInstructionOffset() - skipIndex); + + iDuplicate(); // expression + clause->expression->accept(this); + iStrictEqual(); + skipIndex = nextInstructionOffset(); + iBranchFalse(0); // next case + + if (fallthroughIndex != -1) // previous case falls through to here + patchInstruction(fallthroughIndex, nextInstructionOffset() - fallthroughIndex); + + int breaksBefore = m_activeLoop->breakLabel.uses.count(); + if (clause->statements) + clause->statements->accept(this); + int breaksAfter = m_activeLoop->breakLabel.uses.count(); + if (breaksAfter == breaksBefore) { // fallthrough + fallthroughIndex = nextInstructionOffset(); + iBranch(0); + } else { // no fallthrough (break) + fallthroughIndex = -1; + } + } + + if (skipIndex != -1) { + patchInstruction(skipIndex, nextInstructionOffset() - skipIndex); + if (defaultIndex != -1) + iBranch(defaultIndex - nextInstructionOffset()); // goto default + } + + if (fallthroughIndex != -1) + patchInstruction(fallthroughIndex, nextInstructionOffset() - fallthroughIndex); + + // backpatch the breaks + int term = nextInstructionOffset(); + foreach (int index, m_activeLoop->breakLabel.uses) { + patchInstruction(index, term - index); + } + + iPop(); // expression + + if (previousLoop && !m_activeLoop->continueLabel.uses.isEmpty()) { + // join the continues and add to outer loop + iBranch(3); + foreach (int index, m_activeLoop->continueLabel.uses) { + patchInstruction(index, nextInstructionOffset() - index); + } + iPop(); + iBranch(0); + previousLoop->continueLabel.uses.append(nextInstructionOffset() - 1); + } + + switchStatement(was); + changeActiveLoop(previousLoop); + m_loops.remove(node); + return false; +} + +bool Compiler::visit(AST::LabelledStatement *node) +{ + Loop *loop = findLoop(node->label); + if (loop != 0) { + QString str = m_eng->toString(node->label); + m_compilationUnit.setError(QString::fromUtf8("duplicate label `%1'").arg(str), + node->startLine); + return false; + } + + loop = &m_loops[node->statement]; + loop->name = node->label; + node->statement->accept(this); + if (m_loops.contains(node->statement)) { + loop->breakLabel.offset = nextInstructionOffset(); + foreach (int index, loop->breakLabel.uses) { + patchInstruction(index, loop->breakLabel.offset - index); + } + m_loops.remove(node->statement); + } + return false; +} + +bool Compiler::visit(AST::ExpressionStatement *node) +{ + if (node->expression) + iLine(node->expression); + return true; +} + +void Compiler::endVisit(AST::ExpressionStatement *) +{ + if (topLevelCompiler()) + iSync(); + else + iPop(); +} + +void Compiler::endVisit(AST::UnaryPlusExpression *) +{ + iUnaryPlus(); +} + +void Compiler::endVisit(AST::UnaryMinusExpression *) +{ + iUnaryMinus(); +} + +bool Compiler::visit(AST::ContinueStatement *node) +{ + iLine(node); + return true; +} + +void Compiler::endVisit(AST::ContinueStatement *node) +{ + int offset = nextInstructionOffset(); + iBranch(0); + + Loop *loop = findLoop(node->label); + if (!loop || !m_iterationStatement) { + m_compilationUnit.setError(QString::fromUtf8("label not found"), + node->startLine); + return; + } + + loop->continueLabel.uses.append(offset); +} + +bool Compiler::visit(AST::BreakStatement *node) +{ + iLine(node); + return true; +} + +void Compiler::endVisit(AST::BreakStatement *node) +{ + Loop *loop = findLoop(node->label); + if (! loop) { + m_compilationUnit.setError(QString::fromUtf8("label not found"), + node->startLine); + return; + } + + if (m_generateLeaveWithOnBreak) + iLeaveWith(); + int offset = nextInstructionOffset(); + iBranch(0); + loop->breakLabel.uses.append(offset); +} + +void Compiler::endVisit(AST::EmptyStatement *node) +{ + iLine(node); +} + +bool Compiler::visit(AST::DebuggerStatement *node) +{ + iLine(node); + iDebugger(); + return false; +} + +void Compiler::patchInstruction(int index, int offset) +{ + QScriptInstruction &i = m_instructions[index]; + + switch (i.op) { + case QScriptInstruction::OP_Branch: + case QScriptInstruction::OP_BranchFalse: + case QScriptInstruction::OP_BranchTrue: + m_eng->newInteger(&i.operand[0], offset); + break; + + default: + Q_ASSERT_X(0, "Compiler::patchInstruction()", "expected a branch instruction"); + break; + } +} + +bool Compiler::visit(AST::WithStatement *node) +{ + iLine(node); + node->expression->accept(this); + iEnterWith(); + bool was = withStatement(true); + bool was2 = generateLeaveOnBreak(true); + node->statement->accept(this); + generateLeaveOnBreak(was2); + withStatement(was); + iLeaveWith(); + return false; +} + +bool Compiler::visit(AST::ArrayLiteral *node) +{ + iNewArray(); + + int length = 0; + + for (AST::ElementList *it = node->elements; it != 0; it = it->next) { + for (AST::Elision *eit = it->elision; eit != 0; eit = eit->next) { + iDuplicate(); + iLoadNumber(length); + iMakeReference(); + iLoadUndefined(); + iAssign(); + iPop(); + ++length; + } + + if (it->expression) { + iDuplicate(); + iLoadNumber(length); + iMakeReference(); + it->expression->accept(this); + iAssign(); + iPop(); + ++length; + } + } + + for (AST::Elision *eit = node->elision; eit != 0; eit = eit->next) { + iDuplicate(); + iLoadNumber(length); + iMakeReference(); + iLoadUndefined(); + iAssign(); + iPop(); + ++length; + } + + return false; +} + +void Compiler::iLoadUndefined() +{ + pushInstruction(QScriptInstruction::OP_LoadUndefined); +} + +void Compiler::iLoadThis() +{ + pushInstruction(QScriptInstruction::OP_LoadThis); +} + +void Compiler::iLoadActivation() +{ + pushInstruction(QScriptInstruction::OP_LoadActivation); +} + +void Compiler::iLoadNull() +{ + pushInstruction(QScriptInstruction::OP_LoadNull); +} + +void Compiler::iLoadNumber(double number) +{ + QScriptValueImpl arg0(number); + pushInstruction(QScriptInstruction::OP_LoadNumber, arg0); +} + +void Compiler::iLoadString(QScriptNameIdImpl *id) +{ + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + pushInstruction(QScriptInstruction::OP_LoadString, arg0); +} + +void Compiler::iDuplicate() +{ + pushInstruction(QScriptInstruction::OP_Duplicate); +} + +void Compiler::iSwap() +{ + pushInstruction(QScriptInstruction::OP_Swap); +} + +void Compiler::iResolve(QScriptNameIdImpl *id) +{ + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + pushInstruction(QScriptInstruction::OP_Resolve, arg0); +} + +void Compiler::iPutField() +{ + pushInstruction(QScriptInstruction::OP_PutField); +} + +void Compiler::iCall(int argc) +{ + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, argc); + pushInstruction(QScriptInstruction::OP_Call, arg0); +} + +void Compiler::iNew(int argc) +{ + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, argc); + pushInstruction(QScriptInstruction::OP_New, arg0); +} + +void Compiler::iFetchField() +{ + pushInstruction(QScriptInstruction::OP_FetchField); +} + +void Compiler::iLazyArguments() +{ + pushInstruction(QScriptInstruction::OP_LazyArguments); +} + +void Compiler::iRet() +{ + pushInstruction(QScriptInstruction::OP_Ret); +} + +void Compiler::iDeclareLocal(QScriptNameIdImpl *id, bool readOnly) +{ + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + QScriptValueImpl arg1; + m_eng->newInteger(&arg1, readOnly); + pushInstruction(QScriptInstruction::OP_DeclareLocal, arg0, arg1); +} + +void Compiler::iAssign() +{ + pushInstruction(QScriptInstruction::OP_Assign); +} + +void Compiler::iBitAnd() +{ + pushInstruction(QScriptInstruction::OP_BitAnd); +} + +void Compiler::iBitOr() +{ + pushInstruction(QScriptInstruction::OP_BitOr); +} + +void Compiler::iBitXor() +{ + pushInstruction(QScriptInstruction::OP_BitXor); +} + +void Compiler::iLeftShift() +{ + pushInstruction(QScriptInstruction::OP_LeftShift); +} + +void Compiler::iMod() +{ + pushInstruction(QScriptInstruction::OP_Mod); +} + +void Compiler::iRightShift() +{ + pushInstruction(QScriptInstruction::OP_RightShift); +} + +void Compiler::iURightShift() +{ + pushInstruction(QScriptInstruction::OP_URightShift); +} + +void Compiler::iAdd() +{ + pushInstruction(QScriptInstruction::OP_Add); +} + +void Compiler::iDiv() +{ + pushInstruction(QScriptInstruction::OP_Div); +} + +void Compiler::iEqual() +{ + pushInstruction(QScriptInstruction::OP_Equal); +} + +void Compiler::iGreatOrEqual() +{ + pushInstruction(QScriptInstruction::OP_GreatOrEqual); +} + +void Compiler::iGreatThan() +{ + pushInstruction(QScriptInstruction::OP_GreatThan); +} + +void Compiler::iLessOrEqual() +{ + pushInstruction(QScriptInstruction::OP_LessOrEqual); +} + +void Compiler::iLessThan() +{ + pushInstruction(QScriptInstruction::OP_LessThan); +} + +void Compiler::iMul() +{ + pushInstruction(QScriptInstruction::OP_Mul); +} + +void Compiler::iNotEqual() +{ + pushInstruction(QScriptInstruction::OP_NotEqual); +} + +void Compiler::iSub() +{ + pushInstruction(QScriptInstruction::OP_Sub); +} + +void Compiler::iStrictEqual() +{ + pushInstruction(QScriptInstruction::OP_StrictEqual); +} + +void Compiler::iStrictNotEqual() +{ + pushInstruction(QScriptInstruction::OP_StrictNotEqual); +} + +void Compiler::iBranch(int index) +{ + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, index); + pushInstruction(QScriptInstruction::OP_Branch, arg0); +} + +void Compiler::iBranchFalse(int index) +{ + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, index); + pushInstruction(QScriptInstruction::OP_BranchFalse, arg0); +} + +void Compiler::iBranchTrue(int index) +{ + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, index); + pushInstruction(QScriptInstruction::OP_BranchTrue, arg0); +} + +void Compiler::iNewClosure(AST::FunctionExpression *expr) +{ + QScriptValueImpl arg0; + m_eng->newPointer(&arg0, expr); + + pushInstruction(QScriptInstruction::OP_NewClosure, arg0); +} + +void Compiler::iIncr() +{ + pushInstruction(QScriptInstruction::OP_Incr); +} + +void Compiler::iDecr() +{ + pushInstruction(QScriptInstruction::OP_Decr); +} + +void Compiler::iPop() +{ + pushInstruction(QScriptInstruction::OP_Pop); +} + +void Compiler::iFetch(QScriptNameIdImpl *id) +{ + if (m_generateFastArgumentLookup) { + int index = m_formals.indexOf(id); + + if (index != -1) { + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, index); + pushInstruction(QScriptInstruction::OP_Receive, arg0); + return; + } + } + + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + pushInstruction(QScriptInstruction::OP_Fetch, arg0); +} + +void Compiler::iLoadTrue() +{ + pushInstruction(QScriptInstruction::OP_LoadTrue); +} + +void Compiler::iLoadFalse() +{ + pushInstruction(QScriptInstruction::OP_LoadFalse); +} + +void Compiler::iUnaryMinus() +{ + pushInstruction(QScriptInstruction::OP_UnaryMinus); +} + +void Compiler::iUnaryPlus() +{ + pushInstruction(QScriptInstruction::OP_UnaryPlus); +} + +void Compiler::iPostIncr() +{ + pushInstruction(QScriptInstruction::OP_PostIncr); +} + +void Compiler::iPostDecr() +{ + pushInstruction(QScriptInstruction::OP_PostDecr); +} + +void Compiler::iNewArray() +{ + pushInstruction(QScriptInstruction::OP_NewArray); +} + +void Compiler::iNewObject() +{ + pushInstruction(QScriptInstruction::OP_NewObject); +} + +void Compiler::iTypeOf() +{ + pushInstruction(QScriptInstruction::OP_TypeOf); +} + +void Compiler::iDelete() +{ + pushInstruction(QScriptInstruction::OP_Delete); +} + +void Compiler::iInstanceOf() +{ + pushInstruction(QScriptInstruction::OP_InstanceOf); +} + +void Compiler::iInplaceAnd() +{ + pushInstruction(QScriptInstruction::OP_InplaceAnd); +} + +void Compiler::iInplaceSub() +{ + pushInstruction(QScriptInstruction::OP_InplaceSub); +} + +void Compiler::iInplaceDiv() +{ + pushInstruction(QScriptInstruction::OP_InplaceDiv); +} + +void Compiler::iInplaceAdd() +{ + pushInstruction(QScriptInstruction::OP_InplaceAdd); +} + +void Compiler::iInplaceLeftShift() +{ + pushInstruction(QScriptInstruction::OP_InplaceLeftShift); +} + +void Compiler::iInplaceMod() +{ + pushInstruction(QScriptInstruction::OP_InplaceMod); +} + +void Compiler::iInplaceMul() +{ + pushInstruction(QScriptInstruction::OP_InplaceMul); +} + +void Compiler::iInplaceOr() +{ + pushInstruction(QScriptInstruction::OP_InplaceOr); +} + +void Compiler::iInplaceRightShift() +{ + pushInstruction(QScriptInstruction::OP_InplaceRightShift); +} + +void Compiler::iInplaceURightShift() +{ + pushInstruction(QScriptInstruction::OP_InplaceURightShift); +} + +void Compiler::iInplaceXor() +{ + pushInstruction(QScriptInstruction::OP_InplaceXor); +} + +void Compiler::iThrow() +{ + pushInstruction(QScriptInstruction::OP_Throw); +} + +void Compiler::iLine(AST::Node *node) +{ + if (! node) + return; + + QScriptValueImpl arg0; + m_eng->newInteger(&arg0, node->startLine); + + QScriptValueImpl arg1; + m_eng->newInteger(&arg1, node->startColumn); + + pushInstruction(QScriptInstruction::OP_Line, arg0, arg1); +} + +void Compiler::iBitNot() +{ + pushInstruction(QScriptInstruction::OP_BitNot); +} + +void Compiler::iNot() +{ + pushInstruction(QScriptInstruction::OP_Not); +} + +void Compiler::iNewRegExp(QScriptNameIdImpl *pattern) +{ + QScriptValueImpl arg0; + pattern->persistent = true; + m_eng->newNameId(&arg0, pattern); + pushInstruction(QScriptInstruction::OP_NewRegExp, arg0); +} + +void Compiler::iNewRegExp(QScriptNameIdImpl *pattern, int flags) +{ + QScriptValueImpl arg0; + pattern->persistent = true; + m_eng->newNameId(&arg0, pattern); + + QScriptValueImpl arg1; + m_eng->newInteger(&arg1, flags); + + pushInstruction(QScriptInstruction::OP_NewRegExp, arg0, arg1); +} + +void Compiler::iNewEnumeration() +{ + pushInstruction(QScriptInstruction::OP_NewEnumeration); +} + +void Compiler::iToFirstElement() +{ + pushInstruction(QScriptInstruction::OP_ToFirstElement); +} + +void Compiler::iHasNextElement() +{ + pushInstruction(QScriptInstruction::OP_HasNextElement); +} + +void Compiler::iNextElement() +{ + pushInstruction(QScriptInstruction::OP_NextElement); +} + +void Compiler::iEnterWith() +{ + pushInstruction(QScriptInstruction::OP_EnterWith); +} + +void Compiler::iLeaveWith() +{ + pushInstruction(QScriptInstruction::OP_LeaveWith); +} + +void Compiler::iBeginCatch(QScriptNameIdImpl *id) +{ + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + pushInstruction(QScriptInstruction::OP_BeginCatch, arg0); +} + +void Compiler::iEndCatch() +{ + pushInstruction(QScriptInstruction::OP_EndCatch); +} + +void Compiler::iSync() +{ + pushInstruction(QScriptInstruction::OP_Sync); +} + +void Compiler::iHalt() +{ + pushInstruction(QScriptInstruction::OP_Halt); +} + +void Compiler::iMakeReference() +{ + pushInstruction(QScriptInstruction::OP_MakeReference); +} + +void Compiler::iIn() +{ + pushInstruction(QScriptInstruction::OP_In); +} + +void Compiler::iNop() +{ + pushInstruction(QScriptInstruction::OP_Nop); +} + +void Compiler::iNewString(QScriptNameIdImpl *id) +{ + QScriptValueImpl arg0; + id->persistent = true; + m_eng->newNameId(&arg0, id); + pushInstruction(QScriptInstruction::OP_NewString, arg0); +} + +void Compiler::iDebugger() +{ + pushInstruction(QScriptInstruction::OP_Debugger); +} + +Compiler::Loop *Compiler::findLoop(QScriptNameIdImpl *name) +{ + if (! name) + return m_activeLoop; + + QMap<AST::Statement*, Loop>::iterator it = m_loops.begin(); + + for (; it != m_loops.end(); ++it) { + Loop &loop = *it; + + if (loop.name == name) + return &loop; + } + + return 0; +} + + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptcompiler_p.h b/src/script/qscriptcompiler_p.h new file mode 100644 index 0000000..67fa60f --- /dev/null +++ b/src/script/qscriptcompiler_p.h @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** 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 QSCRIPTCOMPILER_P_H +#define QSCRIPTCOMPILER_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/QMap> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/QVector> + +#include "qscriptastvisitor_p.h" +#include "qscriptasm_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; + +namespace QScript { + +class Compiler: protected AST::Visitor +{ +public: + Compiler(QScriptEnginePrivate *eng); + virtual ~Compiler(); + + inline QScriptEnginePrivate *engine() const { return m_eng; } + + bool topLevelCompiler() const; + void setTopLevelCompiler(bool b); + + CompilationUnit compile(AST::Node *node, const QList<QScriptNameIdImpl *> &formals + = QList<QScriptNameIdImpl *>()); + + struct Label { + Label(int o = 0): + offset (o) {} + + int offset; + QVector<int> uses; + }; + +// instruction set + void iAdd(); + void iAssign(); + void iBitAnd(); + void iBitOr(); + void iBitXor(); + void iBitNot(); + void iBranch(int index); + void iBranchTrue(int index); + void iBranchFalse(int index); + void iCall(int argc); + void iDeclareLocal(QScriptNameIdImpl *id, bool readOnly); + void iDecr(); + void iDelete(); + void iDiv(); + void iDuplicate(); + void iEqual(); + void iFetch(QScriptNameIdImpl *id); + void iFetchField(); + void iLazyArguments(); + void iGreatOrEqual(); + void iGreatThan(); + void iIncr(); + void iInplaceAdd(); + void iInplaceAnd(); + void iInplaceDecr(); + void iInplaceDiv(); + void iInplaceLeftShift(); + void iInplaceMod(); + void iInplaceMul(); + void iInplaceOr(); + void iInplaceRightShift(); + void iInplaceSub(); + void iInplaceURightShift(); + void iInstanceOf(); + void iLeftShift(); + void iLessOrEqual(); + void iLessThan(); + void iLoadFalse(); + void iLoadNumber(double number); + void iLoadString(QScriptNameIdImpl *id); + void iNewString(QScriptNameIdImpl *id); + void iLoadThis(); + void iLoadActivation(); + void iLoadNull(); + void iLoadTrue(); + void iLoadUndefined(); + void iMod(); + void iMul(); + void iUnaryPlus(); + void iUnaryMinus(); + void iNew(int argc); + void iNewArray(); + void iNewClosure(AST::FunctionExpression *expr); + void iNewObject(); + void iNewRegExp(QScriptNameIdImpl *pattern); + void iNewRegExp(QScriptNameIdImpl *pattern, int flags); + void iNot(); + void iNotEqual(); + void iPop(); + void iPostDecr(); + void iPostIncr(); + void iPutField(); + void iResolve(QScriptNameIdImpl *id); + void iRet(); + void iRightShift(); + void iSub(); + void iStrictEqual(); + void iStrictNotEqual(); + void iSwap(); + void iThrow(); + void iTypeOf(); + void iURightShift(); + void iInplaceXor(); + void iLine(AST::Node *node); + void iNewEnumeration(); + void iToFirstElement(); + void iHasNextElement(); + void iNextElement(); + void iEnterWith(); + void iLeaveWith(); + void iBeginCatch(QScriptNameIdImpl *id); + void iEndCatch(); + void iSync(); + void iHalt(); + void iMakeReference(); + void iIn(); + void iNop(); + void iDebugger(); + +protected: + virtual bool preVisit(AST::Node *node); + + virtual bool visit(AST::ArrayLiteral *node); + virtual bool visit(AST::ArrayMemberExpression *node); + virtual bool visit(AST::Expression *node); + virtual bool visit(AST::BinaryExpression *node); + virtual bool visit(AST::BreakStatement *node); + virtual bool visit(AST::CallExpression *node); + virtual bool visit(AST::ConditionalExpression *node); + virtual bool visit(AST::ContinueStatement *node); + virtual bool visit(AST::DeleteExpression *node); + virtual bool visit(AST::DoWhileStatement *node); + virtual bool visit(AST::ExpressionStatement *node); + virtual bool visit(AST::FalseLiteral *node); + virtual bool visit(AST::FieldMemberExpression *node); + virtual bool visit(AST::ForEachStatement *node); + virtual bool visit(AST::LocalForEachStatement *node); + virtual bool visit(AST::ForStatement *node); + virtual bool visit(AST::FunctionDeclaration *node); + virtual bool visit(AST::FunctionExpression *node); + virtual bool visit(AST::FunctionSourceElement *node); + virtual bool visit(AST::IdentifierExpression *node); + virtual bool visit(AST::IfStatement *node); + virtual bool visit(AST::LabelledStatement *node); + virtual bool visit(AST::LocalForStatement *node); + virtual bool visit(AST::NewExpression *node); + virtual bool visit(AST::NewMemberExpression *node); + virtual bool visit(AST::NumericLiteral *node); + virtual bool visit(AST::ObjectLiteral *node); + virtual bool visit(AST::PostDecrementExpression *node); + virtual bool visit(AST::PostIncrementExpression *node); + virtual bool visit(AST::PreDecrementExpression *node); + virtual bool visit(AST::PreIncrementExpression *node); + virtual bool visit(AST::RegExpLiteral *node); + virtual bool visit(AST::ReturnStatement *node); + virtual bool visit(AST::SourceElements *node); + virtual bool visit(AST::StatementList *node); + virtual bool visit(AST::StatementSourceElement *node); + virtual bool visit(AST::StringLiteral *node); + virtual bool visit(AST::SwitchStatement *node); + virtual bool visit(AST::ThisExpression *node); + virtual bool visit(AST::NullExpression *node); + virtual bool visit(AST::ThrowStatement *node); + virtual bool visit(AST::TryStatement *node); + virtual bool visit(AST::TrueLiteral *node); + virtual bool visit(AST::VariableStatement *node); + virtual bool visit(AST::VariableDeclaration *node); + virtual bool visit(AST::WhileStatement *node); + virtual bool visit(AST::WithStatement *node); + virtual bool visit(AST::Block *node); + virtual bool visit(AST::TypeOfExpression *node); + virtual bool visit(AST::DebuggerStatement *node); + + virtual void endVisit(AST::BreakStatement *node); + virtual void endVisit(AST::ContinueStatement *node); + virtual void endVisit(AST::ExpressionStatement *node); + virtual void endVisit(AST::NotExpression *node); + virtual void endVisit(AST::ReturnStatement *node); + virtual void endVisit(AST::ThrowStatement *node); + virtual void endVisit(AST::TildeExpression *node); + virtual void endVisit(AST::UnaryPlusExpression *node); + virtual void endVisit(AST::UnaryMinusExpression *node); + virtual void endVisit(AST::VoidExpression *node); + virtual void endVisit(AST::EmptyStatement *node); + + void visitForInternal(AST::Statement *node, AST::ExpressionNode *condition, + AST::Statement *statement, AST::ExpressionNode *expression); + + bool isAssignmentOperator(int op) const; + int inplaceAssignmentOperator(int op) const; + + inline int nextInstructionOffset() const + { return m_instructions.count(); } + + inline void pushInstruction(QScriptInstruction::Operator op) + { + pushInstruction(op, QScriptValueImpl(), QScriptValueImpl()); + } + + inline void pushInstruction(QScriptInstruction::Operator op, + const QScriptValueImpl &arg1) + { + pushInstruction(op, arg1, QScriptValueImpl()); + } + + inline void pushInstruction(QScriptInstruction::Operator op, + const QScriptValueImpl &arg1, + const QScriptValueImpl &arg2) + { + QScriptInstruction i; + i.op = op; + i.operand[0] = arg1; + i.operand[1] = arg2; + m_instructions.append(i); + } + + inline bool generateReferences(bool b) + { + bool was = m_generateReferences; + m_generateReferences = b; + return was; + } + + inline bool generateFastArgumentLookup(bool b) + { + bool was = m_generateFastArgumentLookup; + m_generateFastArgumentLookup= b; + return was; + } + + inline bool iterationStatement(bool b) + { + bool was = m_iterationStatement; + m_iterationStatement = b; + return was; + } + + inline bool switchStatement(bool b) + { + bool was = m_switchStatement; + m_switchStatement = b; + return was; + } + + inline bool changeParseStatements(bool b) + { + bool was = m_parseStatements; + m_parseStatements = b; + return was; + } + + inline bool withStatement(bool b) + { + bool was = m_withStatement; + m_withStatement = b; + return was; + } + + inline bool generateLeaveOnBreak(bool b) + { + bool was = m_generateLeaveWithOnBreak; + m_generateLeaveWithOnBreak = b; + return was; + } + + void patchInstruction(int index, int offset); + +private: + QScriptEnginePrivate *m_eng; + + uint m_generateReferences: 1; + uint m_iterationStatement: 1; + uint m_switchStatement: 1; + uint m_withStatement: 1; + uint m_generateLeaveWithOnBreak: 1; + uint m_generateFastArgumentLookup: 1; + uint m_parseStatements: 1; + uint m_pad: 25; + + bool m_topLevelCompiler; // bit + QVector<QScriptInstruction> m_instructions; + QVector<ExceptionHandlerDescriptor> m_exceptionHandlers; + QList<QScriptNameIdImpl *> m_formals; + + struct Loop { + Loop(QScriptNameIdImpl *n = 0): + name(n) {} + + QScriptNameIdImpl *name; + Label breakLabel; + Label continueLabel; + }; + + inline Loop *changeActiveLoop(Loop *activeLoop) + { + Loop *was = m_activeLoop; + m_activeLoop = activeLoop; + return was; + } + + Loop *findLoop(QScriptNameIdImpl *name = 0); + + Loop *m_activeLoop; + QMap<AST::Statement*, Loop> m_loops; + CompilationUnit m_compilationUnit; +}; + +} // namespace QScript + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptcontext.cpp b/src/script/qscriptcontext.cpp new file mode 100644 index 0000000..020601b --- /dev/null +++ b/src/script/qscriptcontext.cpp @@ -0,0 +1,571 @@ +/**************************************************************************** +** +** 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 "qscriptcontext.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptcontextinfo.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptContext + + \brief The QScriptContext class represents a Qt Script function invocation. + + \ingroup script + \mainclass + + A QScriptContext provides access to the `this' object and arguments + passed to a script function. You typically want to access this + information when you're writing a native (C++) function (see + QScriptEngine::newFunction()) that will be called from script + code. For example, when the script code + + \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 0 + + is evaluated, a QScriptContext will be created, and the context will + carry the arguments as QScriptValues; in this particular case, the + arguments will be one QScriptValue containing the number 20.5, a second + QScriptValue containing the string \c{"hello"}, and a third QScriptValue + containing a Qt Script object. + + Use argumentCount() to get the number of arguments passed to the + function, and argument() to get an argument at a certain index. The + argumentsObject() function returns a Qt Script array object + containing all the arguments; you can use the QScriptValueIterator + to iterate over its elements, or pass the array on as arguments to + another script function using QScriptValue::call(). + + Use thisObject() to get the `this' object associated with the function call, + and setThisObject() to set the `this' object. If you are implementing a + native "instance method", you typically fetch the thisObject() and access + one or more of its properties: + + \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 1 + + Use isCalledAsConstructor() to determine if the function was called + as a constructor (e.g. \c{"new foo()"} (as constructor) or just + \c{"foo()"}). When a function is called as a constructor, the + thisObject() contains the newly constructed object that the function + is expected to initialize. + + Use throwValue() or throwError() to throw an exception. + + Use callee() to obtain the QScriptValue that represents the function being + called. This can for example be used to call the function recursively. + + Use parentContext() to get a pointer to the context that precedes + this context in the activation stack. This is mostly useful for + debugging purposes (e.g. when constructing some form of backtrace). + + The activationObject() function returns the object that is used to + hold the local variables associated with this function call. You can + replace the activation object by calling setActivationObject(). A + typical usage of these functions is when you want script code to be + evaluated in the context of the parent context, e.g. to implement an + include() function: + + \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 2 + + Use backtrace() to get a human-readable backtrace associated with + this context. This can be useful for debugging purposes when + implementing native functions. The toString() function provides a + string representation of the context. (QScriptContextInfo provides + more detailed debugging-related information about the + QScriptContext.) + + Use engine() to obtain a pointer to the QScriptEngine that this context + resides in. + + \sa QScriptContextInfo, QScriptEngine::newFunction(), QScriptable +*/ + +/*! + \enum QScriptContext::ExecutionState + + This enum specifies the execution state of the context. + + \value NormalState The context is in a normal state. + + \value ExceptionState The context is in an exceptional state. +*/ + +/*! + \enum QScriptContext::Error + + This enum specifies types of error. + + \value ReferenceError A reference error. + + \value SyntaxError A syntax error. + + \value TypeError A type error. + + \value RangeError A range error. + + \value URIError A URI error. + + \value UnknownError An unknown error. +*/ + +/*! + Throws an exception with the given \a value. + Returns the value thrown (the same as the argument). + + \sa throwError(), state() +*/ +QScriptValue QScriptContext::throwValue(const QScriptValue &value) +{ + Q_D(QScriptContext); + d->m_result = d->engine()->toImpl(value); + d->m_state = QScriptContext::ExceptionState; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + d->engine()->notifyException(d); +#endif + return value; +} + +/*! + Throws an \a error with the given \a text. + Returns the created error object. + + The \a text will be stored in the \c{message} property of the error + object. + + The error object will be initialized to contain information about + the location where the error occurred; specifically, it will have + properties \c{lineNumber}, \c{fileName} and \c{stack}. These + properties are described in \l {QtScript Extensions to ECMAScript}. + + \sa throwValue(), state() +*/ +QScriptValue QScriptContext::throwError(Error error, const QString &text) +{ + Q_D(QScriptContext); + return d->engine()->toPublic(d->throwError(error, text)); +} + +/*! + \overload + + Throws an error with the given \a text. + Returns the created error object. + + \sa throwValue(), state() +*/ +QScriptValue QScriptContext::throwError(const QString &text) +{ + Q_D(QScriptContext); + return d->engine()->toPublic(d->throwError(text)); +} + +/*! + \internal +*/ +QScriptContext::QScriptContext(): + d_ptr(new QScriptContextPrivate()) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys this QScriptContext. +*/ +QScriptContext::~QScriptContext() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Returns the QScriptEngine that this QScriptContext belongs to. +*/ +QScriptEngine *QScriptContext::engine() const +{ + Q_D(const QScriptContext); + return QScriptEnginePrivate::get(d->engine()); +} + +/*! + Returns the function argument at the given \a index. + + If \a index >= argumentCount(), a QScriptValue of + the primitive type Undefined is returned. + + \sa argumentCount() +*/ +QScriptValue QScriptContext::argument(int index) const +{ + Q_D(const QScriptContext); + if (index < 0) + return QScriptValue(); + return d->engine()->toPublic(d->argument(index)); +} + +/*! + Returns the callee. The callee is the function object that this + QScriptContext represents an invocation of. +*/ +QScriptValue QScriptContext::callee() const +{ + Q_D(const QScriptContext); + return d->engine()->toPublic(d->m_callee); +} + +/*! + Returns the arguments object of this QScriptContext. + + The arguments object has properties \c callee (equal to callee()) + and \c length (equal to argumentCount()), and properties \c 0, \c 1, + ..., argumentCount() - 1 that provide access to the argument + values. Initially, property \c P (0 <= \c P < argumentCount()) has + the same value as argument(\c P). In the case when \c P is less + than the number of formal parameters of the function, \c P shares + its value with the corresponding property of the activation object + (activationObject()). This means that changing this property changes + the corresponding property of the activation object and vice versa. + + \sa argument(), activationObject() +*/ +QScriptValue QScriptContext::argumentsObject() const +{ + Q_D(const QScriptContext); + return d->engine()->toPublic(d->argumentsObject()); +} + +/*! + Returns true if the function was called as a constructor + (e.g. \c{"new foo()"}); otherwise returns false. + + When a function is called as constructor, the thisObject() + contains the newly constructed object to be initialized. +*/ +bool QScriptContext::isCalledAsConstructor() const +{ + Q_D(const QScriptContext); + return d->m_calledAsConstructor; +} + +/*! + Returns the parent context of this QScriptContext. +*/ +QScriptContext *QScriptContext::parentContext() const +{ + Q_D(const QScriptContext); + return QScriptContextPrivate::get(d->previous); +} + +/*! + Returns the number of arguments passed to the function + in this invocation. + + Note that the argument count can be different from the + formal number of arguments (the \c{length} property of + callee()). + + \sa argument() +*/ +int QScriptContext::argumentCount() const +{ + Q_D(const QScriptContext); + return d->argc; +} + +/*! + \internal +*/ +QScriptValue QScriptContext::returnValue() const +{ + Q_D(const QScriptContext); + return d->engine()->toPublic(d->m_result); +} + +/*! + \internal +*/ +void QScriptContext::setReturnValue(const QScriptValue &result) +{ + Q_D(QScriptContext); + d->m_result = d->engine()->toImpl(result); +} + +/*! + Returns the activation object of this QScriptContext. The activation + object provides access to the local variables associated with this + context. + + \sa argument(), argumentsObject() +*/ +QScriptValue QScriptContext::activationObject() const +{ + Q_D(const QScriptContext); + return d->engine()->toPublic(d->activationObject()); +} + +/*! + Sets the activation object of this QScriptContext to be the given \a + activation. + + If \a activation is not an object, this function does nothing. +*/ +void QScriptContext::setActivationObject(const QScriptValue &activation) +{ + Q_D(QScriptContext); + if (!activation.isObject()) { + return; + } else if (activation.engine() != engine()) { + qWarning("QScriptContext::setActivationObject() failed: " + "cannot set an object created in " + "a different engine"); + } else { + d->m_activation = d->engine()->toImpl(activation); + } +} + +/*! + Returns the `this' object associated with this QScriptContext. +*/ +QScriptValue QScriptContext::thisObject() const +{ + Q_D(const QScriptContext); + return d->engine()->toPublic(d->m_thisObject); +} + +/*! + Sets the `this' object associated with this QScriptContext to be + \a thisObject. + + If \a thisObject is not an object, this function does nothing. +*/ +void QScriptContext::setThisObject(const QScriptValue &thisObject) +{ + Q_D(QScriptContext); + if (!thisObject.isObject()) { + } else if (thisObject.engine() != engine()) { + qWarning("QScriptContext::setThisObject() failed: " + "cannot set an object created in " + "a different engine"); + } else { + d->m_thisObject = d->engine()->toImpl(thisObject); + } +} + +/*! + Returns the execution state of this QScriptContext. +*/ +QScriptContext::ExecutionState QScriptContext::state() const +{ + Q_D(const QScriptContext); + return d->m_state; +} + +/*! + Returns a human-readable backtrace of this QScriptContext. + + Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}. + + To access individual pieces of debugging-related information (for + example, to construct your own backtrace representation), use + QScriptContextInfo. + + \sa QScriptEngine::uncaughtExceptionBacktrace(), QScriptContextInfo, toString() +*/ +QStringList QScriptContext::backtrace() const +{ + Q_D(const QScriptContext); + return d->backtrace(); +} + +static QString safeValueToString(const QScriptValue &value) +{ + if (value.isObject()) + return QLatin1String("[object Object]"); + else + return value.toString(); +} + +/*! + \since 4.4 + + Returns a string representation of this context. + This is useful for debugging. + + \sa backtrace() +*/ +QString QScriptContext::toString() const +{ + QScriptContextInfo info(this); + QString result; + + QString functionName = info.functionName(); + if (functionName.isEmpty()) { + if (parentContext()) { + if (info.functionType() == QScriptContextInfo::ScriptFunction) + result.append(QLatin1String("<anonymous>")); + else + result.append(QLatin1String("<native>")); + } else { + result.append(QLatin1String("<global>")); + } + } else { + result.append(functionName); + } + + QStringList parameterNames = info.functionParameterNames(); + result.append(QLatin1String(" (")); + for (int i = 0; i < argumentCount(); ++i) { + if (i > 0) + result.append(QLatin1String(", ")); + if (i < parameterNames.count()) { + result.append(parameterNames.at(i)); + result.append(QLatin1Char('=')); + } + QScriptValue arg = argument(i); + result.append(safeValueToString(arg)); + } + result.append(QLatin1String(")")); + + QString fileName = info.fileName(); + int lineNumber = info.lineNumber(); + result.append(QLatin1String(" at ")); + if (!fileName.isEmpty()) { + result.append(fileName); + result.append(QLatin1Char(':')); + } + result.append(QString::number(lineNumber)); + return result; +} + +/*! + \internal + \since 4.5 + + Returns the scope chain of this QScriptContext. +*/ +QScriptValueList QScriptContext::scopeChain() const +{ + Q_D(const QScriptContext); + // make sure arguments properties are initialized + const QScriptContextPrivate *ctx = d; + while (ctx) { + (void)ctx->activationObject(); + ctx = ctx->previous; + } + QScriptValueList result; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine()); + QScriptValueImpl scope = d->m_scopeChain; + while (scope.isObject()) { + if (scope.classInfo() == eng_p->m_class_with) + result.append(eng_p->toPublic(scope.prototype())); + else + result.append(eng_p->toPublic(scope)); + scope = scope.scope(); + } + return result; +} + +/*! + \internal + \since 4.5 + + Adds the given \a object to the front of this context's scope chain. + + If \a object is not an object, this function does nothing. +*/ +void QScriptContext::pushScope(const QScriptValue &object) +{ + Q_D(QScriptContext); + if (!object.isObject()) { + return; + } else if (object.engine() != engine()) { + qWarning("QScriptContext::pushScope() failed: " + "cannot push an object created in " + "a different engine"); + return; + } + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine()); + if (!d->m_scopeChain.isValid()) { + d->m_scopeChain = eng_p->toImpl(object); + } else { + QScriptValueImpl withObject; + eng_p->newObject(&withObject, eng_p->toImpl(object), eng_p->m_class_with); + withObject.m_object_value->m_scope = d->m_scopeChain; + withObject.setInternalValue(1); // to differentiate from with-statement objects + d->m_scopeChain = withObject; + } +} + +/*! + \internal + \since 4.5 + + Removes the front object from this context's scope chain, and + returns the removed object. + + If the scope chain is already empty, this function returns an + invalid QScriptValue. +*/ +QScriptValue QScriptContext::popScope() +{ + Q_D(QScriptContext); + if (!d->m_scopeChain.isObject()) + return QScriptValue(); + QScriptValueImpl result; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine()); + if (d->m_scopeChain.classInfo() != eng_p->m_class_with) + result = d->m_scopeChain; + else + result = d->m_scopeChain.prototype(); + d->m_scopeChain = d->m_scopeChain.m_object_value->m_scope; + return eng_p->toPublic(result); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptcontext.h b/src/script/qscriptcontext.h new file mode 100644 index 0000000..1e1f987 --- /dev/null +++ b/src/script/qscriptcontext.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 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 QSCRIPTCONTEXT_H +#define QSCRIPTCONTEXT_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptContextPrivate; + +class Q_SCRIPT_EXPORT QScriptContext +{ +public: + enum ExecutionState { + NormalState, + ExceptionState + }; + + enum Error { + UnknownError, + ReferenceError, + SyntaxError, + TypeError, + RangeError, + URIError + }; + + ~QScriptContext(); + + QScriptContext *parentContext() const; + QScriptEngine *engine() const; + + ExecutionState state() const; + QScriptValue callee() const; + + int argumentCount() const; + QScriptValue argument(int index) const; + QScriptValue argumentsObject() const; + + QScriptValueList scopeChain() const; + void pushScope(const QScriptValue &object); + QScriptValue popScope(); + + QScriptValue returnValue() const; + void setReturnValue(const QScriptValue &result); + + QScriptValue activationObject() const; + void setActivationObject(const QScriptValue &activation); + + QScriptValue thisObject() const; + void setThisObject(const QScriptValue &thisObject); + + bool isCalledAsConstructor() const; + + QScriptValue throwValue(const QScriptValue &value); + QScriptValue throwError(Error error, const QString &text); + QScriptValue throwError(const QString &text); + + QStringList backtrace() const; + + QString toString() const; + +private: + QScriptContext(); + + QScriptContextPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptContext) + Q_DISABLE_COPY(QScriptContext) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif diff --git a/src/script/qscriptcontext_p.cpp b/src/script/qscriptcontext_p.cpp new file mode 100644 index 0000000..199c9d4 --- /dev/null +++ b/src/script/qscriptcontext_p.cpp @@ -0,0 +1,2598 @@ +/**************************************************************************** +** +** 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> + +#ifndef QT_NO_SCRIPT + +#include "qscriptcontext_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptprettypretty_p.h" +#include "qscriptast_p.h" +#include "qscriptnodepool_p.h" +#include "qscriptcompiler_p.h" +#include "qscriptextenumeration_p.h" + +#include <math.h> // floor & friends... + +QT_BEGIN_NAMESPACE + +#define Q_SCRIPT_NO_PRINT_GENERATED_CODE + +#define Q_SCRIPT_NO_JOINED_FUNCTION + +#define CHECK_TEMPSTACK(needed) do { \ + if (stackPtr + needed >= eng->tempStackEnd) { \ + throwError(QLatin1String("out of memory")); \ + HandleException(); \ + } \ +} while (0) + +#ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE +static QTextStream qout(stderr, QIODevice::WriteOnly); +#endif + +static inline void qscript_uint_to_string_helper(uint i, QString &s) +{ + switch (i) { + case 0: case 1: case 2: case 3: case 4: + case 5: case 6: case 7: case 8: case 9: + s += QLatin1Char('0' + i); + break; + + default: + qscript_uint_to_string_helper(i / 10, s); + s += QLatin1Char('0' + (i % 10)); + } +} + +static inline void qscript_uint_to_string(qsreal i, QString &s) +{ + if ((i < 0) || (i > 0xFFFFFFFF)) + return; // nothing to do + + qsreal x = ::fmod(i, 10); + + if (x != 0.0 && x != 1.0 + && x != 2.0 && x != 3.0 + && x != 4.0 && x != 5.0 + && x != 6.0 && x != 7.0 + && x != 8.0 && x != 9.0) + return; // nothing to do + + qscript_uint_to_string_helper(uint(i), s); +} + +static inline quint32 toArrayIndex(const QScriptValueImpl &v) +{ + if (v.isNumber()) { + quint32 ui = v.toUInt32(); + if (qsreal(ui) == v.m_number_value) + return ui; + } else if (v.isString()) { + QByteArray bytes = v.m_string_value->s.toUtf8(); + char *eptr; + quint32 pos = strtoul(bytes.constData(), &eptr, 10); + if ((eptr == bytes.constData() + bytes.size()) + && (QByteArray::number(pos) == bytes)) { + return pos; + } + } + return 0xFFFFFFFF; +} + +#define CREATE_MEMBER(__obj__, __name__, __member__, __flags__) do { \ + (__obj__).createMember(__name__, __member__, __flags__); \ + eng->adjustBytesAllocated(sizeof(QScript::Member) + sizeof(QScriptValueImpl)); \ +} while (0) + +#define BEGIN_PREFIX_OPERATOR \ + QScriptValue::ResolveFlags mode; \ + mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) \ + | QScriptValue::ResolvePrototype; \ + --stackPtr; \ + QScriptValueImpl object = eng->toObject(stackPtr[-1]); \ + if (!object.isObject()) { \ + stackPtr -= 2; \ + throwTypeError(QLatin1String("not an object")); \ + HandleException(); \ + } \ + QScriptNameIdImpl *memberName = 0; \ + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) \ + memberName = stackPtr[0].m_string_value; \ + else \ + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); \ + QScript::Member member; \ + QScriptValueImpl base; \ + QScriptValueImpl value; \ + QScriptValueImpl getter; \ + QScriptValueImpl setter; \ + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \ + if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) { \ + base.get(member, &value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + HandleException(); \ + } else if (member.isGetterOrSetter()) { \ + if (member.isGetter()) { \ + getter = value; \ + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \ + stackPtr -= 2; \ + throwError(QLatin1String("No setter defined")); \ + HandleException(); \ + } \ + base.get(member, &setter); \ + } else { \ + setter = value; \ + QScript::Member tmp = member; \ + if (!base.m_object_value->findGetter(&member)) { \ + stackPtr -= 2; \ + throwError(QLatin1String("No getter defined")); \ + HandleException(); \ + } \ + base.get(member, &getter); \ + member = tmp; \ + } \ + value = getter.call(object); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + Done(); \ + } \ + } \ + } else if (!isMemberAssignment) { \ + stackPtr -= 2; \ + throwNotDefined(memberName); \ + HandleException(); \ + } else { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + value = undefined; \ + } + +#define END_PREFIX_OPERATOR \ + if (member.isSetter()) { \ + setter.call(object, QScriptValueImplList() << value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + Done(); \ + } \ + } else { \ + if (member.isWritable()) { \ + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + } \ + base.put(member, value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + HandleException(); \ + } \ + } \ + } \ + *--stackPtr = value; \ + ++iPtr; + +#define BEGIN_INPLACE_OPERATOR \ + if (! stackPtr[-1].isReference()) { \ + stackPtr -= 2; \ + throwSyntaxError(QLatin1String("invalid assignment lvalue")); \ + HandleException(); \ + } \ + QScriptValue::ResolveFlags mode; \ + mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value) \ + | QScriptValue::ResolvePrototype; \ + QScriptValueImpl object = eng->toObject(stackPtr[-3]); \ + if (! object.isValid()) { \ + stackPtr -= 4; \ + throwTypeError(QLatin1String("not an object")); \ + HandleException(); \ + } \ + QScriptNameIdImpl *memberName = 0; \ + if (stackPtr[-2].isString() && stackPtr[-2].m_string_value->unique) \ + memberName = stackPtr[-2].m_string_value; \ + else \ + memberName = eng->nameId(stackPtr[-2].toString(), /*persistent=*/false); \ + QScriptValueImpl lhs; \ + QScriptValueImpl base; \ + QScript::Member member; \ + QScriptValueImpl getter; \ + QScriptValueImpl setter; \ + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \ + if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) { \ + base.get(member, &lhs); \ + if (hasUncaughtException()) { \ + stackPtr -= 4; \ + HandleException(); \ + } else if (member.isGetterOrSetter()) { \ + if (member.isGetter()) { \ + getter = lhs; \ + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \ + stackPtr -= 4; \ + throwError(QLatin1String("No setter defined")); \ + HandleException(); \ + } \ + base.get(member, &setter); \ + } else { \ + setter = lhs; \ + QScript::Member tmp = member; \ + if (!base.m_object_value->findGetter(&member)) { \ + stackPtr -= 4; \ + throwError(QLatin1String("No getter defined")); \ + HandleException(); \ + } \ + base.get(member, &getter); \ + member = tmp; \ + } \ + lhs = getter.call(object); \ + if (hasUncaughtException()) { \ + stackPtr -= 4; \ + Done(); \ + } \ + } \ + } else if (!isMemberAssignment) { \ + stackPtr -= 4; \ + throwNotDefined(memberName); \ + HandleException(); \ + } else { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + lhs = undefined; \ + } \ + QScriptValueImpl rhs = stackPtr[0]; + +#define END_INPLACE_OPERATOR \ + if (member.isSetter()) { \ + setter.call(object, QScriptValueImplList() << *stackPtr); \ + if (hasUncaughtException()) { \ + stackPtr -= 1; \ + Done(); \ + } \ + } else { \ + if (member.isWritable()) { \ + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + } \ + base.put(member, *stackPtr); \ + if (hasUncaughtException()) { \ + stackPtr -= 1; \ + HandleException(); \ + } \ + } \ + } \ + ++iPtr; + +namespace QScript { + +void ScriptFunction::execute(QScriptContextPrivate *context) +{ + if (! m_compiledCode) { + QScriptEnginePrivate *eng = context->engine(); + Compiler compiler(eng); + + CompilationUnit unit = compiler.compile(m_definition->body, formals); + if (! unit.isValid()) { + context->throwError(unit.errorMessage()); + return; + } + + m_compiledCode = m_astPool->createCompiledCode(m_definition->body, unit); + } + + context->execute(m_compiledCode); +} + +QString ScriptFunction::toString(QScriptContextPrivate *) const +{ + QString str; + QTextStream out(&str, QIODevice::WriteOnly); + PrettyPretty pp(out); + pp(m_definition, /*indent=*/ 0); + return str; +} + +QString ScriptFunction::fileName() const +{ + return m_astPool->fileName(); +} + +QString ScriptFunction::functionName() const +{ + if (!m_definition->name) + return QString(); + return m_definition->name->s; +} + +int ScriptFunction::startLineNumber() const +{ + return m_definition->startLine; +} + +int ScriptFunction::endLineNumber() const +{ + return m_definition->endLine; +} + +} // namespace QScript + +/*! + \internal + + Resolves and gets the value specified by \a stackPtr. + stackPtr[0] contains the member specifier, stackPtr[-1] contains the object. + If the member can be resolved, sets \a value to the value of that member, + otherwise returns false. +*/ +bool QScriptContextPrivate::resolveField(QScriptEnginePrivate *eng, + QScriptValueImpl *stackPtr, + QScriptValueImpl *value) +{ + const QScriptValueImpl &m = stackPtr[0]; + QScriptValueImpl &object = stackPtr[-1]; + + if (! object.isObject()) + object = eng->toObject(object); + + if (! object.isValid()) + return false; + + if (QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object)) { + quint32 pos = toArrayIndex(m); + if (pos != 0xFFFFFFFF) { + *value = arrayInstance->value.at(pos); + + if (! value->isValid()) + *value = eng->undefinedValue(); + + return true; + } + } + + QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0; + + if (! nameId || ! nameId->unique) + nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false); // ### slow! + + QScript::Member member; + QScriptValueImpl base; + + if (! object.resolve(nameId, &member, &base, QScriptValue::ResolveFull, QScript::Read)) // ### ... + return false; + + if (QScriptEnginePrivate::strictlyEquals(base, eng->m_globalObject)) + stackPtr[-1] = base; + else if (object.classInfo() == eng->m_class_with) + stackPtr[-1] = object.prototype(); + + base.get(member, value); + + if (member.isGetterOrSetter()) { + // call the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *value; + } else { + if (!base.m_object_value->findGetter(&member)) { + *value = eng->undefinedValue(); + return true; + } + base.get(member, &getter); + } + *value = getter.call(object); + } + + return true; +} + +void QScriptContextPrivate::execute(QScript::Code *code) +{ + int oldCurrentLine = currentLine; + int oldCurrentColumn = currentColumn; + QScript::Code *oldCode = m_code; + m_code = code; + +#ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE + qout << QLatin1String("function:") << endl; + for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) { + qout << int(current - code->firstInstruction) << QLatin1String(":\t"); + current->print(qout); + qout << endl; + } + qout << endl; +#endif + + QScriptEnginePrivate *eng = engine(); + + bool wasEvaluating = eng->m_evaluating; + if (!wasEvaluating) { + eng->setupProcessEvents(); + eng->resetAbortFlag(); + } + eng->m_evaluating = true; + + // set up the temp stack + if (! tempStack) + stackPtr = tempStack = eng->tempStackBegin; + + QScriptValueImpl undefined(eng->undefinedValue()); + + catching = false; + m_state = QScriptContext::NormalState; + m_result = undefined; + firstInstruction = code->firstInstruction; + lastInstruction = code->lastInstruction; + iPtr = code->firstInstruction; + + if (!m_scopeChain.isValid()) + m_scopeChain = m_activation; + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionEntry(this); +#endif + +#ifndef Q_SCRIPT_DIRECT_CODE + +# define I(opc) case QScriptInstruction::OP_##opc +# define Next() goto Lfetch +# define Done() goto Ldone +# define HandleException() goto Lhandle_exception +# define Abort() goto Labort + +Lfetch: + + +#else + +# define I(opc) qscript_execute_##opc +# define Next() goto *iPtr->code +# define Done() goto Ldone +# define HandleException() goto Lhandle_exception +# define Abort() goto Labort + + static void * const jump_table[] = { + +# define Q_SCRIPT_DEFINE_OPERATOR(op) &&I(op), +# include "instruction.table" +# undef Q_SCRIPT_DEFINE_OPERATOR + }; // jump_table + + + if (!code->optimized) { + for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) { + current->code = jump_table[current->op]; + } + + code->optimized = true; + } + +#endif +Ltop: + +#ifndef Q_SCRIPT_DIRECT_CODE + switch (iPtr->op) { +#else + goto *iPtr->code; +#endif + + I(Nop): + { + ++iPtr; + } Next(); + + I(LoadUndefined): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = undefined; + ++iPtr; + } Next(); + + I(LoadTrue): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = QScriptValueImpl(true); + ++iPtr; + } Next(); + + I(LoadFalse): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = QScriptValueImpl(false); + ++iPtr; + } Next(); + + I(LoadThis): + { + CHECK_TEMPSTACK(1); + Q_ASSERT(m_thisObject.isObject()); + *++stackPtr = m_thisObject; + ++iPtr; + } Next(); + + I(LoadActivation): + { + CHECK_TEMPSTACK(1); + *++stackPtr = m_activation; + ++iPtr; + } Next(); + + I(LoadNull): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = eng->nullValue(); + ++iPtr; + } Next(); + + I(LoadNumber): + { + CHECK_TEMPSTACK(1); + *++stackPtr = iPtr->operand[0]; + ++iPtr; + } Next(); + + + I(LoadString): + { + CHECK_TEMPSTACK(1); + *++stackPtr = iPtr->operand[0]; + ++iPtr; + } Next(); + + I(NewString): + { + CHECK_TEMPSTACK(1); + eng->newNameId(++stackPtr, iPtr->operand[0].m_string_value); + ++iPtr; + } Next(); + + I(Duplicate): + { + CHECK_TEMPSTACK(1); + ++stackPtr; + *stackPtr = stackPtr[-1]; + ++iPtr; + } Next(); + + I(Swap): + { + QScriptValueImpl tmp = stackPtr[0]; + *stackPtr = stackPtr[-1]; + stackPtr[-1] = tmp; + ++iPtr; + } Next(); + + + I(Receive): + { + int n = iPtr->operand[0].m_int_value; + + if (n >= argc) { + throwError(QLatin1String("invalid argument")); + HandleException(); + } + + CHECK_TEMPSTACK(1); + *++stackPtr = argument(n); + ++iPtr; + } Next(); + + I(Fetch): + { + CHECK_TEMPSTACK(1); + + QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value; + + QScriptValueImpl base; + QScript::Member member; + + QScriptObject *instance = m_scopeChain.m_object_value; + if (instance->findMember(memberName, &member)) { + instance->get(member, ++stackPtr); + base = m_scopeChain; + } else { + if (m_scopeChain.resolve_helper(memberName, &member, &base, QScriptValue::ResolveFull, QScript::Read)) { + base.get(member, ++stackPtr); + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } else { + throwNotDefined(memberName); + HandleException(); + } + } + if (member.isGetterOrSetter()) { + // locate the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *stackPtr; + } else { + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + } + // decide the this-object. This is the object that actually + // has the getter (in its prototype chain). + QScriptValueImpl object = m_scopeChain; + while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) + object = object.scope(); + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + + *stackPtr = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } + ++iPtr; + } Next(); + + I(Resolve): + { + Q_ASSERT(iPtr->operand[0].isString()); + + CHECK_TEMPSTACK(2); + *++stackPtr = m_scopeChain; + *++stackPtr = iPtr->operand[0]; + eng->newReference(++stackPtr, QScriptValue::ResolveScope); + ++iPtr; + } Next(); + + I(PutField): + { + Q_ASSERT(stackPtr[-1].isReference()); + + const QScriptValueImpl &object = stackPtr[-3]; + QScriptNameIdImpl *memberName = stackPtr[-2].m_string_value; + const QScriptValueImpl &value = stackPtr[0]; + + QScript::Member member; + QScriptValueImpl base; + + if (! object.resolve(memberName, &member, &base, QScriptValue::ResolveLocal, QScript::Write)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + + base.put(member, value); + stackPtr -= 4; + if (hasUncaughtException()) + HandleException(); + ++iPtr; + } Next(); + + I(Call): + { + int argc = iPtr->operand[0].m_int_value; + QScriptValueImpl *argp = stackPtr - argc; + + QScriptValueImpl base; + QScriptValueImpl callee; + + bool isReference = argp[0].isReference(); + + if (! isReference) { // we have a value + base = eng->m_globalObject; + callee = argp[0]; + } else if (resolveField(eng, &argp[-1], &callee)) { + if (hasUncaughtException()) { + stackPtr = argp - 3; + HandleException(); + } + base = argp[-2]; + } else { + QScriptValueImpl member = argp[-1]; + stackPtr = argp - 1; + Q_ASSERT(isReference); + stackPtr -= 2; + + if (member.isString()) + throwNotDefined(member.toString()); + else + throwNotDefined(QLatin1String("function")); + HandleException(); + } + + Q_ASSERT(base.isValid()); + Q_ASSERT(callee.isValid()); + + QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee); + if (! function) { + QScriptValueImpl member = argp[-1]; + QString message; + if (member.isString()) { + message = QString::fromLatin1("%0 is not a function") + .arg(member.toString()); + } else { + message = QLatin1String("not a function"); + } + throwTypeError(message); + HandleException(); + } + + if (++eng->m_callDepth == eng->m_maxCallDepth) { + throwError(QLatin1String("call stack overflow")); + HandleException(); + } + + QScriptContextPrivate *nested_data = eng->pushContext(); + nested_data->m_thisObject = base; + nested_data->m_callee = callee; + + // create the activation + eng->newActivation(&nested_data->m_activation); + QScriptObject *activation_data = nested_data->m_activation.m_object_value; + + int formalCount = function->formals.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx); + activation_data->m_values.resize(mx); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId = 0; + if (i < formalCount) + nameId = function->formals.at(i); + + activation_data->m_members[i].object(nameId, i, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined; + } + + nested_data->argc = argc; + if (callee.m_object_value->m_scope.isValid()) + activation_data->m_scope = callee.m_object_value->m_scope; + else + activation_data->m_scope = eng->m_globalObject; + nested_data->tempStack = stackPtr; + nested_data->args = &argp[1]; + + function->execute(nested_data); + + --eng->m_callDepth; + + stackPtr = argp - 1; + if (isReference) + stackPtr -= 2; + + if (nested_data->m_state == QScriptContext::ExceptionState) { + eng->popContext(); + if (eng->shouldAbort()) + Abort(); + else + Done(); + } + + CHECK_TEMPSTACK(1); + *++stackPtr = nested_data->m_result; + + eng->popContext(); + + if (eng->shouldAbort()) + Abort(); + + if (eng->m_processEventsInterval > 0) + eng->processEvents(); + + ++iPtr; + } Next(); + + + I(NewArray): + { + CHECK_TEMPSTACK(1); + eng->arrayConstructor->newArray(++stackPtr, QScript::Array(eng)); + ++iPtr; + } Next(); + + I(NewRegExp): + { + CHECK_TEMPSTACK(1); + + QString pattern = eng->toString(iPtr->operand[0].m_string_value); +#ifndef QT_NO_REGEXP + QString literal = pattern; +#endif + int flags = 0; + if (iPtr->operand[1].isValid()) { + flags = iPtr->operand[1].m_int_value; +#ifndef QT_NO_REGEXP + if (flags != 0) { + literal += QLatin1String("/"); + literal += QString::number(flags); + } +#endif + } + +#ifndef QT_NO_REGEXP + QRegExp rx; + // lazy compilation of regexp literals + QHash<QString, QRegExp>::const_iterator it; + it = eng->m_regExpLiterals.constFind(literal); + if (it == eng->m_regExpLiterals.constEnd()) { + rx = QScript::Ecma::RegExp::toRegExp(pattern, flags); + eng->m_regExpLiterals.insert(literal, rx); + } else { + rx = *it; + } + eng->regexpConstructor->newRegExp(++stackPtr, rx, flags); +#else + eng->regexpConstructor->newRegExp(++stackPtr, pattern, flags); +#endif + ++iPtr; + } Next(); + + I(NewObject): + { + CHECK_TEMPSTACK(1); + eng->objectConstructor->newObject(++stackPtr); + ++iPtr; + } Next(); + + I(New): + { + int argc = iPtr->operand[0].m_int_value; + QScriptValueImpl *argp = stackPtr - argc; + + // QScriptValueImpl base; + QScriptValueImpl callee; + + bool isReference = argp[0].isReference(); + + if (! isReference) { // we have a value + // base = eng->globalObject; + callee = argp[0]; + } else if (resolveField(eng, &argp[-1], &callee)) { + // base = argp[-2]; + if (hasUncaughtException()) { + stackPtr = argp - 3; + HandleException(); + } + } else { + QScriptValueImpl member = argp[-1]; + stackPtr = argp - 1; + Q_ASSERT(isReference); + stackPtr -= 2; + + if (member.isString()) + throwNotDefined(member.toString()); + else + throwNotDefined(QLatin1String("constructor")); + HandleException(); + } + + // Q_ASSERT(base.isValid()); + Q_ASSERT(callee.isValid()); + + QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee); + if (! function) { + QScriptValueImpl member = argp[-1]; + QString message; + if (member.isString()) { + message = QString::fromLatin1("%0 is not a constructor") + .arg(member.toString()); + } else { + message = QLatin1String("not a constructor"); + } + throwTypeError(message); + HandleException(); + } + + if (++eng->m_callDepth == eng->m_maxCallDepth) { + throwError(QLatin1String("call stack overflow")); + HandleException(); + } + + QScriptContextPrivate *nested_data = eng->pushContext(); + nested_data->m_callee = callee; + nested_data->m_calledAsConstructor = true; + + // create the activation + eng->newActivation(&nested_data->m_activation); + QScriptObject *activation_data = nested_data->m_activation.m_object_value; + + int formalCount = function->formals.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx); + activation_data->m_values.resize(mx); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId = 0; + if (i < formalCount) + nameId = function->formals.at(i); + + activation_data->m_members[i].object(nameId, i, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined; + } + + eng->objectConstructor->newObject(&nested_data->m_thisObject); + nested_data->argc = argc; + if (callee.m_object_value->m_scope.isValid()) + activation_data->m_scope = callee.m_object_value->m_scope; + else + activation_data->m_scope = eng->m_globalObject; + nested_data->tempStack = stackPtr; + nested_data->args = &argp[1]; + nested_data->m_result = undefined; + + QScriptObject *instance = nested_data->m_thisObject.m_object_value; + + // set [[prototype]] + QScriptValueImpl dummy; + QScript::Member proto; + if (callee.resolve(eng->idTable()->id_prototype, &proto, &dummy, QScriptValue::ResolveLocal, QScript::Read)) + callee.get(proto, &instance->m_prototype); + if (!instance->m_prototype.isObject()) + instance->m_prototype = eng->objectConstructor->publicPrototype; + + function->execute(nested_data); + + --eng->m_callDepth; + + stackPtr = argp - 1; + if (isReference) + stackPtr -= 2; + + if (! nested_data->m_result.isValid()) + nested_data->m_result = undefined; + else if (! nested_data->m_result.isObject()) + nested_data->m_result = nested_data->m_thisObject; + + if (nested_data->m_state == QScriptContext::ExceptionState) { + eng->popContext(); + if (eng->shouldAbort()) + Abort(); + else + Done(); + } + + CHECK_TEMPSTACK(1); + + *++stackPtr = nested_data->m_result; + + eng->popContext(); + + if (eng->shouldAbort()) + Abort(); + + if (eng->m_processEventsInterval > 0) + eng->processEvents(); + + ++iPtr; + } Next(); + + I(FetchField): + { + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (! object.isValid()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptValueImpl m = stackPtr[0]; + + QScript::Ecma::Array::Instance *arrayInstance = 0; + if (object.classInfo() == eng->arrayConstructor->classInfo()) + arrayInstance = static_cast<QScript::Ecma::Array::Instance *> (object.m_object_value->m_data); + + if (arrayInstance) { + quint32 pos = toArrayIndex(m); + if (pos != 0xFFFFFFFF) { + QScriptValueImpl val = arrayInstance->value.at(pos); + if (val.isValid()) { + *--stackPtr = val; + ++iPtr; + Next(); + } + } + } + + QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0; + + if (! nameId || ! nameId->unique) { + QString str; + + if (m.isNumber()) + qscript_uint_to_string(m.m_number_value, str); + + if (str.isEmpty()) + str = QScriptEnginePrivate::convertToNativeString(m); + + nameId = eng->nameId(str, /*persistent=*/false); + } + + QScript::Member member; + QScriptValueImpl base; + + if (object.resolve(nameId, &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) { + base.get(member, --stackPtr); + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } else if (member.isGetterOrSetter()) { + // call the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *stackPtr; + } else { + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + } + *stackPtr = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } + } else { + *(--stackPtr) = undefined; + } + + ++iPtr; + } Next(); + + I(LazyArguments): + { + QScript::Member member; + QScriptValueImpl base; + QScriptNameIdImpl *arguments = eng->idTable()->id_arguments; + if (!m_activation.resolve(arguments, &member, &base, QScriptValue::ResolveLocal, QScript::Read)) { + CREATE_MEMBER(m_activation, arguments, &member, QScriptValue::Undeletable); + if (!m_arguments.isValid()) { + if (eng->strictlyEquals(m_activation, eng->globalObject())) + m_arguments = undefined; + else + eng->newArguments(&m_arguments, m_activation, argc, m_callee); + } + m_activation.put(member, m_arguments); + } + ++iPtr; + } Next(); + + I(DeclareLocal): + { + QScriptValueImpl &act = m_activation; + + QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value; + bool readOnly = iPtr->operand[1].m_int_value != 0; + QScript::Member member; + QScriptValueImpl object; + + if (! act.resolve(memberName, &member, &object, QScriptValue::ResolveLocal, QScript::ReadWrite)) { + uint flags = QScriptValue::Undeletable; + if (readOnly) + flags |= QScript::Member::UninitializedConst | QScriptValue::ReadOnly; + CREATE_MEMBER(act, memberName, &member, flags); + act.put(member, undefined); + } + ++iPtr; + } Next(); + + I(Assign): + { + if (! stackPtr[-1].isReference()) { + stackPtr -= 2; + throwSyntaxError(QLatin1String("invalid assignment lvalue")); + HandleException(); + } + + QScriptValue::ResolveFlags mode; + mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value) + | QScriptValue::ResolvePrototype; + + QScriptValueImpl object = eng->toObject(stackPtr[-3]); + if (! object.isValid()) { + stackPtr -= 4; + throwTypeError(QLatin1String("invalid assignment lvalue")); + HandleException(); + } + + QScriptValueImpl m = stackPtr[-2]; + QScriptValueImpl value = stackPtr[0]; + + quint32 pos = 0xFFFFFFFF; + + QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object); + if (arrayInstance) + pos = toArrayIndex(m); + + stackPtr -= 3; + + if (pos != 0xFFFFFFFF) + arrayInstance->value.assign(pos, value); + + else { + QScriptNameIdImpl *memberName; + + if (m.isString() && m.m_string_value->unique) + memberName = m.m_string_value; + else + memberName = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false); + + QScriptValueImpl base; + QScript::Member member; + + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); + if (! object.resolve(memberName, &member, &base, mode, QScript::Write)) { + if (isMemberAssignment) + base = object; + else + base = eng->m_globalObject; + + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + + if (value.isString() && ! value.m_string_value->unique) + eng->newNameId(&value, value.m_string_value->s); + + if (member.isGetterOrSetter()) { + // find and call setter(value) + QScriptValueImpl setter; + if (!member.isSetter()) { + if (!base.m_object_value->findSetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("no setter defined")); + HandleException(); + } + } + base.get(member, &setter); + + if (!isMemberAssignment) { + // decide the this-object. This is the object that actually + // has the setter (in its prototype chain). + while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Write)) + object = object.scope(); + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + } + + value = setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } else { + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + + if (member.isWritable()) { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + base.put(member, value); + } else if (member.isUninitializedConst()) { + base.put(member, value); + if (member.isObjectProperty()) { + base.m_object_value->m_members[member.id()] + .unsetFlags(QScript::Member::UninitializedConst); + } + } + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } + } + + *stackPtr = value; + ++iPtr; + } Next(); + + I(BitAnd): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 & v2); + ++iPtr; + } Next(); + + I(BitOr): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 | v2); + ++iPtr; + } Next(); + + I(BitXor): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 ^ v2); + ++iPtr; + } Next(); + + I(BitNot): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *stackPtr = QScriptValueImpl(~v1); + ++iPtr; + } Next(); + + I(Not): + { + bool v1 = QScriptEnginePrivate::convertToNativeBoolean(stackPtr[0]); + *stackPtr = QScriptValueImpl(!v1); + ++iPtr; + } Next(); + + I(LeftShift): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 << v2); + ++iPtr; + } Next(); + + I(Mod): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + + *(--stackPtr) = QScriptValueImpl(::fmod(v1, v2)); + ++iPtr; + } Next(); + + I(RightShift): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + quint32 v2 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[0])) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 >> v2); + ++iPtr; + } Next(); + + I(URightShift): + { + quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[-1])); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 >> v2); + ++iPtr; + } Next(); + + I(InstanceOf): + { + QScriptValueImpl object = stackPtr[-1]; + QScriptValueImpl ctor = stackPtr[0]; + + if (!ctor.isObject() || !ctor.implementsHasInstance()) { + stackPtr -= 2; + throwTypeError(QLatin1String("invalid 'instanceof' operand")); + HandleException(); + } + + bool result = ctor.hasInstance(object); + if (eng->hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + + *(--stackPtr) = QScriptValueImpl(result); + ++iPtr; + } Next(); + + I(In): + { + QScriptValueImpl object = stackPtr[0]; + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("invalid 'in' operand")); + HandleException(); + } + QString propertyName = QScriptEnginePrivate::convertToNativeString(stackPtr[-1]); + bool result = object.property(propertyName, QScriptValue::ResolvePrototype).isValid(); // ### hasProperty() + *(--stackPtr) = QScriptValueImpl(result); + ++iPtr; + } Next(); + + I(Add): + { + QScriptValueImpl lhs = eng->toPrimitive(stackPtr[-1], QScriptValueImpl::NoTypeHint); + QScriptValueImpl rhs = eng->toPrimitive(stackPtr[0], QScriptValueImpl::NoTypeHint); + + if (lhs.isString() || rhs.isString()) { + QString tmp = QScriptEnginePrivate::convertToNativeString(lhs); + tmp += QScriptEnginePrivate::convertToNativeString(rhs); + eng->newString(--stackPtr, tmp); + } else { + qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs); + tmp += QScriptEnginePrivate::convertToNativeDouble(rhs); + *(--stackPtr) = QScriptValueImpl(tmp); + } + + ++iPtr; + } Next(); + + I(Div): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 / v2); + ++iPtr; + } Next(); + + I(Equal): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(eq_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(GreatOrEqual): + { + QScriptValueImpl v1 = stackPtr[0]; + QScriptValueImpl v2 = stackPtr[-1]; + *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(GreatThan): + { + QScriptValueImpl v1 = stackPtr[0]; + QScriptValueImpl v2 = stackPtr[-1]; + *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(LessOrEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(LessThan): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(NotEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(!eq_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(Mul): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 * v2); + ++iPtr; + } Next(); + + I(StrictEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = strict_eq_cmp(v1, v2); + ++iPtr; + } Next(); + + I(StrictNotEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = ! strict_eq_cmp(v1, v2); + ++iPtr; + } Next(); + + I(Sub): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 - v2); + ++iPtr; + } Next(); + + I(UnaryMinus): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr); + *stackPtr = QScriptValueImpl(-v1); + ++iPtr; + } Next(); + + I(UnaryPlus): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr); + *stackPtr = QScriptValueImpl(+v1); + ++iPtr; + } Next(); + + I(Branch): + { + eng->maybeProcessEvents(); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + iPtr += iPtr->operand[0].m_int_value; + } Next(); + + I(BranchFalse): + { + if (! QScriptEnginePrivate::convertToNativeBoolean(*stackPtr--)) + iPtr += iPtr->operand[0].m_int_value; + else + ++iPtr; + } Next(); + + I(BranchTrue): + { + if (eng->convertToNativeBoolean(*stackPtr--)) + iPtr += iPtr->operand[0].m_int_value; + else + ++iPtr; + } Next(); + + I(NewClosure): + { + CHECK_TEMPSTACK(1); + + QScript::AST::FunctionExpression *expr = static_cast<QScript::AST::FunctionExpression *> (iPtr->operand[0].m_ptr_value); + +#ifndef Q_SCRIPT_NO_JOINED_FUNCTION + if (QScript::Code *code = eng->findCode(functionBody)) { + QScriptValueImpl value = code->value; + + if (isValid(value)) { + QScriptObject *instance = value.m_object_value; + Q_ASSERT(instance != 0); + + if (instance->m_scope.m_object_value == m_scopeChain.m_object_value) + { + *++stackPtr = value; + ++iPtr; + Next(); + } + } + } +#endif + + QScript::ScriptFunction *function = new QScript::ScriptFunction(expr, code->astPool); + + // update the formals + for (QScript::AST::FormalParameterList *it = expr->formals; it != 0; it = it->next) { + function->formals.append(it->name); + } + function->length = function->formals.count(); + + eng->functionConstructor->newFunction(++stackPtr, function); + + QScriptObject *instance = stackPtr->m_object_value; + // initialize [[scope]] + instance->m_scope = m_scopeChain; + + // create and initialize `prototype' + QScriptValueImpl proto; + eng->objectConstructor->newObject(&proto); + + QScript::Member member; + CREATE_MEMBER(proto, eng->idTable()->id_constructor, &member, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + proto.put(member, *stackPtr); + + stackPtr->createMember(eng->idTable()->id_prototype, &member, + QScriptValue::Undeletable); + stackPtr->put(member, proto); + + ++iPtr; + } Next(); + + I(Incr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid increment operand")); + HandleException(); + } + + BEGIN_PREFIX_OPERATOR + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + value = QScriptValueImpl(x + 1); + + END_PREFIX_OPERATOR + } Next(); + + I(Decr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid decrement operand")); + HandleException(); + } + + BEGIN_PREFIX_OPERATOR + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + value = QScriptValueImpl(x - 1); + + END_PREFIX_OPERATOR + } Next(); + + I(PostIncr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid increment operand")); + HandleException(); + } + + QScriptValue::ResolveFlags mode; + mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) + | QScriptValue::ResolvePrototype; + + --stackPtr; + + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptNameIdImpl *memberName = 0; + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) + memberName = stackPtr[0].m_string_value; + else + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl value; + QScriptObject *instance = object.m_object_value; + const bool isMemberAssignment = (instance != m_scopeChain.m_object_value); + if (instance->findMember(memberName, &member)) { + if (!member.isGetterOrSetter()) { + QScriptValueImpl &r = instance->reference(member); + if (r.isNumber()) { + *(--stackPtr) = QScriptValueImpl(r.m_number_value); + r.incr(); + ++iPtr; + Next(); + } + } + base = object; + } else if (!object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) { + if (!isMemberAssignment) { + stackPtr -= 2; + throwNotDefined(memberName); + HandleException(); + } + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + base.put(member, undefined); + } + + QScriptValueImpl getter; + QScriptValueImpl setter; + base.get(member, &value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } else if (member.isGetterOrSetter()) { + if (member.isGetter()) { + getter = value; + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No setter defined")); + HandleException(); + } + base.get(member, &setter); + } else { + setter = value; + QScript::Member tmp = member; + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + member = tmp; + } + value = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + + value = QScriptValueImpl(x + 1); + + if (member.isSetter()) { + setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } else { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + if (member.isWritable()) { + base.put(member, value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + } + } + + *(--stackPtr) = QScriptValueImpl(x); + + ++iPtr; + } Next(); + + I(PostDecr): + { + // ### most of the code is duplicated from PostIncr -- try to merge + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid decrement operand")); + HandleException(); + } + + QScriptValue::ResolveFlags mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) + | QScriptValue::ResolvePrototype; + + --stackPtr; + + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptNameIdImpl *memberName = 0; + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) + memberName = stackPtr[0].m_string_value; + else + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl value; + QScriptObject *instance = object.m_object_value; + const bool isMemberAssignment = (instance != m_scopeChain.m_object_value); + if (instance->findMember(memberName, &member)) { + if (!member.isGetterOrSetter()) { + QScriptValueImpl &r = instance->reference(member); + if (r.isNumber()) { + *(--stackPtr) = QScriptValueImpl(r.m_number_value); + r.decr(); + ++iPtr; + Next(); + } + } + base = object; + } else if (! object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) { + if (!isMemberAssignment) { + stackPtr -= 2; + throwNotDefined(memberName); + HandleException(); + } + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + base.put(member, undefined); + } + + QScriptValueImpl getter; + QScriptValueImpl setter; + base.get(member, &value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } else if (member.isGetterOrSetter()) { + if (member.isGetter()) { + getter = value; + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No setter defined")); + HandleException(); + } + base.get(member, &setter); + } else { + setter = value; + QScript::Member tmp = member; + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + member = tmp; + } + value = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + + value = QScriptValueImpl(x - 1); + + if (member.isSetter()) { + setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } else { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + if (member.isWritable()) { + base.put(member, value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + } + } + + *(--stackPtr) = QScriptValueImpl(x); + + ++iPtr; + } Next(); + + I(InplaceAdd): + { + BEGIN_INPLACE_OPERATOR + + lhs = eng->toPrimitive(lhs); + rhs = eng->toPrimitive(rhs); + if (lhs.isString() || rhs.isString()) { + if (lhs.isString() && !lhs.m_string_value->unique) { + lhs.m_string_value->s += QScriptEnginePrivate::convertToNativeString(rhs); + stackPtr -= 3; + *stackPtr = lhs; + } else { + QString tmp = QScriptEnginePrivate::convertToNativeString(lhs); + tmp += QScriptEnginePrivate::convertToNativeString(rhs); + stackPtr -= 3; + eng->newString(stackPtr, tmp); + } + } else { + qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs); + tmp += QScriptEnginePrivate::convertToNativeDouble(rhs); + stackPtr -= 3; + *stackPtr = QScriptValueImpl(tmp); + } + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceSub): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 - v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceAnd): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 & v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceDiv): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 / v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceLeftShift): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 << v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceMod): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(::fmod (v1, v2)); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceMul): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 * v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceOr): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 | v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceRightShift): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 >> v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceURightShift): + { + BEGIN_INPLACE_OPERATOR + + quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(lhs)); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 >> v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceXor): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 ^ v2); + + END_INPLACE_OPERATOR + } Next(); + + I(MakeReference): + { + CHECK_TEMPSTACK(1); + eng->newReference(++stackPtr, QScriptValue::ResolveLocal); + ++iPtr; + } Next(); + + I(TypeOf): + { + QScriptValueImpl value; + + bool isReference = stackPtr[0].isReference(); + + if (! isReference) { // we have a value + value = stackPtr[0]; + } else if (resolveField(eng, &stackPtr[-1], &value)) { + stackPtr -= 2; + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } else { + value = undefined; + stackPtr -= 2; + } + + QString typeName; + + switch (value.type()) { + case QScript::InvalidType: + typeName = QLatin1String("invalid"); + break; + + case QScript::UndefinedType: + typeName = QLatin1String("undefined"); + break; + + case QScript::NullType: + typeName = QLatin1String("object"); + break; + + case QScript::BooleanType: + typeName = QLatin1String("boolean"); + break; + + case QScript::IntegerType: + case QScript::NumberType: + typeName = QLatin1String("number"); + break; + + case QScript::StringType: + case QScript::LazyStringType: + typeName = QLatin1String("string"); + break; + + case QScript::ReferenceType: + typeName = QLatin1String("reference"); + break; + + case QScript::PointerType: + typeName = QLatin1String("pointer"); + break; + + case QScript::ObjectType: + if (value.isFunction()) + typeName = QLatin1String("function"); + else + typeName = QLatin1String("object"); + break; + } + + eng->newString(stackPtr, typeName); + ++iPtr; + } Next(); + + I(Line): + { + eng->maybeGC(); + eng->maybeProcessEvents(); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + currentLine = iPtr->operand[0].m_int_value; + currentColumn = iPtr->operand[1].m_int_value; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + if (eng->shouldNotify()) { + eng->notifyPositionChange(this); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + } +#endif + ++iPtr; + } Next(); + + I(Delete): + { + bool result; + if (! stackPtr[0].isReference()) + result = true; + + else { + QScriptValueImpl object = stackPtr[-2]; + if (!object.isObject()) + object = eng->toObject(object); + + QScriptNameIdImpl *nameId = 0; + if (stackPtr[-1].isString() && stackPtr[-1].m_string_value->unique) { + nameId = stackPtr[-1].m_string_value; + } else { + nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(stackPtr[-1]), + /*persistent=*/false); + } + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + result = object.deleteProperty(nameId, QScriptValue::ResolveScope); + stackPtr -= 2; + } + + *stackPtr = QScriptValueImpl(result); + + ++iPtr; + } Next(); + + + I(NewEnumeration): { + QScriptValueImpl e; + QScriptValueImpl object = eng->toObject(stackPtr[0]); + eng->enumerationConstructor->newEnumeration(&e, object); + *stackPtr = e; + ++iPtr; + } Next(); + + + I(ToFirstElement): { + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]); + Q_ASSERT(e != 0); + e->toFront(); + --stackPtr; + ++iPtr; + } Next(); + + + I(HasNextElement): { + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]); + Q_ASSERT(e != 0); + e->hasNext(this, stackPtr); + ++iPtr; + } Next(); + + + I(NextElement): { + // the Enumeration should be located below the result of I(Resolve) + if (! stackPtr[0].isReference()) { + throwTypeError(QLatin1String("QScript.VM.NextElement")); + HandleException(); + } + + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[-3]); + if (! e) { + throwTypeError(QLatin1String("QScript.VM.NextElement")); + HandleException(); + } + e->next(this, ++stackPtr); + ++iPtr; + } Next(); + + + I(Pop): + { + --stackPtr; + ++iPtr; + } Next(); + + I(Sync): + { + m_result = *stackPtr; + --stackPtr; + ++iPtr; + } Next(); + + I(Throw): + { + Q_ASSERT(stackPtr->isValid()); + m_result = *stackPtr--; + if (!m_result.isError() && !exceptionHandlerContext()) + eng->m_exceptionBacktrace = backtrace(); + m_state = QScriptContext::ExceptionState; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyException(this); +#endif + } HandleException(); + + I(Ret): + { + Q_ASSERT(stackPtr->isValid()); + m_result = *stackPtr--; + ++iPtr; + } Done(); + + I(Halt): + { + ++iPtr; + } Done(); + + I(EnterWith): + { + QScriptValueImpl object = eng->toObject(*stackPtr--); + if (! object.isValid()) { + throwTypeError(QLatin1String("value has no properties")); + HandleException(); + } + QScriptValueImpl withObject; + eng->newObject(&withObject, object, eng->m_class_with); + withObject.m_object_value->m_scope = m_scopeChain; + m_scopeChain = withObject; + ++iPtr; + } Next(); + + I(LeaveWith): + { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + ++iPtr; + } Next(); + + I(BeginCatch): + { + // result contains the thrown object + QScriptValueImpl object; + eng->newObject(&object, undefined); // ### prototype + QScript::Member member; + CREATE_MEMBER(object, iPtr->operand[0].m_string_value, &member, /*flags=*/0); + object.put(member, m_result); + // make catch-object head of scopechain + object.m_object_value->m_scope = m_scopeChain; + m_scopeChain = object; + + catching = true; + ++iPtr; + } Next(); + + I(EndCatch): + { + // remove catch-object from scopechain + QScriptValueImpl object = m_scopeChain; + m_scopeChain = object.m_object_value->m_scope; + + catching = false; + ++iPtr; + } Next(); + + I(Debugger): + { +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyDebugger(this); +#endif + ++iPtr; + } Next(); + +#ifndef Q_SCRIPT_DIRECT_CODE + I(Dummy): + { ; } + + } // end switch +#endif + +Lhandle_exception: + errorLineNumber = currentLine; + +Ldone: + Q_ASSERT(m_result.isValid()); + + if (m_state == QScriptContext::ExceptionState) { + if (catching) { + // exception thrown in catch -- clean up scopechain + QScriptValueImpl object = m_scopeChain; + m_scopeChain = object.m_object_value->m_scope; + catching = false; + } + + // see if we have an exception handler in this context + const QScriptInstruction *exPtr = findExceptionHandler(iPtr); + if (exPtr) { + if (m_scopeChain.classInfo() == eng->m_class_with) { + // clean up effects of with-statements if necessary + int withLevel = 0; + for (++iPtr; iPtr != exPtr; ++iPtr) { + if (iPtr->op == QScriptInstruction::OP_EnterWith) { + ++withLevel; + } else if (iPtr->op == QScriptInstruction::OP_LeaveWith) { + --withLevel; + if (withLevel < 0) { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + } + } + } + } else { + iPtr = exPtr; + } + // go to the handler + recover(); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyExceptionCatch(this); +#endif + goto Ltop; + } else { + if (!parentContext()) { + // pop all the top-level with-objects + while ((m_scopeChain.classInfo() == eng->m_class_with) + && !m_scopeChain.internalValue().isValid()) { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + } + } + } + } + +Labort: +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionExit(this); +#endif + + eng->maybeGC(); + + currentLine = oldCurrentLine; + currentColumn = oldCurrentColumn; + m_code = oldCode; + + eng->m_evaluating = wasEvaluating; +} + +QScriptValueImpl QScriptContextPrivate::throwError(QScriptContext::Error error, const QString &text) +{ + QScriptEnginePrivate *eng_p = engine(); + QScript::Ecma::Error *ctor = eng_p->errorConstructor; + m_result.invalidate(); + switch (error) { + case QScriptContext::ReferenceError: + ctor->newReferenceError(&m_result, text); + break; + case QScriptContext::SyntaxError: + ctor->newSyntaxError(&m_result, text); + break; + case QScriptContext::TypeError: + ctor->newTypeError(&m_result, text); + break; + case QScriptContext::RangeError: + ctor->newRangeError(&m_result, text); + break; + case QScriptContext::URIError: + ctor->newURIError(&m_result, text); + break; + case QScriptContext::UnknownError: + default: + ctor->newError(&m_result, text); + } + setDebugInformation(&m_result); + m_state = QScriptContext::ExceptionState; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyException(this); +#endif + return m_result; +} + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY +qint64 QScriptContextPrivate::scriptId() const +{ + if (!m_code) + return -1; + return m_code->astPool->id(); +} +#endif + +QString QScriptContextPrivate::fileName() const +{ + if (!m_code) + return QString(); + return m_code->astPool->fileName(); +} + +QString QScriptContextPrivate::functionName() const +{ + if (!m_callee.isValid()) + return QString(); + QScriptFunction *fun = m_callee.toFunction(); + if (fun) + return fun->functionName(); + return QString(); +} + +void QScriptContextPrivate::setDebugInformation(QScriptValueImpl *error) const +{ + QScriptEnginePrivate *eng_p = engine(); + error->setProperty(QLatin1String("lineNumber"), QScriptValueImpl(currentLine)); + if (!fileName().isEmpty()) + error->setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, fileName())); + + const QScriptContextPrivate *ctx = this; + QScriptValueImpl stackArray = eng_p->newArray(); + int i = 0; + while (ctx) { + QScriptValueImpl obj = eng_p->newObject(); + obj.setProperty(QLatin1String("frame"), ctx->activationObject()); + obj.setProperty(QLatin1String("lineNumber"), QScriptValueImpl(ctx->currentLine)); + if (!ctx->fileName().isEmpty()) + obj.setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, ctx->fileName())); + if (!ctx->functionName().isEmpty()) + obj.setProperty(QLatin1String("functionName"), QScriptValueImpl(eng_p, ctx->functionName())); + stackArray.setProperty(i, obj); + ctx = ctx->parentContext(); + ++i; + } + error->setProperty(QLatin1String("stack"), stackArray); +} + +QStringList QScriptContextPrivate::backtrace() const +{ + QStringList result; + const QScriptContextPrivate *ctx = this; + while (ctx) { + QString s; + QString functionName = ctx->functionName(); + if (!functionName.isEmpty()) + s += functionName; + else { + if (ctx->parentContext()) { + if (ctx->callee().isFunction() + && ctx->callee().toFunction()->type() != QScriptFunction::Script) { + s += QLatin1String("<native>"); + } else { + s += QLatin1String("<anonymous>"); + } + } else { + s += QLatin1String("<global>"); + } + } + s += QLatin1String("("); + for (int i = 0; i < ctx->argc; ++i) { + if (i > 0) + s += QLatin1String(","); + QScriptValueImpl arg = ctx->args[i]; + if (arg.isObject()) + s += QLatin1String("[object Object]"); // don't do a function call + else + s += arg.toString(); + } + s += QLatin1String(")@"); + s += ctx->fileName(); + s += QString::fromLatin1(":%0").arg(ctx->currentLine); + result.append(s); + ctx = ctx->parentContext(); + } + return result; +} + +QScriptValueImpl QScriptContextPrivate::throwError(const QString &text) +{ + return throwError(QScriptContext::UnknownError, text); +} + +QScriptValueImpl QScriptContextPrivate::throwNotImplemented(const QString &name) +{ + return throwTypeError(QString::fromUtf8("%1 is not implemented").arg(name)); +} + +QScriptValueImpl QScriptContextPrivate::throwNotDefined(const QString &name) +{ + return throwError(QScriptContext::ReferenceError, + QString::fromUtf8("%1 is not defined").arg(name)); +} + +QScriptValueImpl QScriptContextPrivate::throwNotDefined(QScriptNameIdImpl *nameId) +{ + return throwNotDefined(QScriptEnginePrivate::toString(nameId)); +} + +bool QScriptContextPrivate::eq_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if (lhs.isNull() && rhs.isUndefined()) + return true; + + else if (lhs.isUndefined() && rhs.isNull()) + return true; + + else if (isNumerical(lhs) && rhs.isString()) + return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs); + + else if (lhs.isString() && isNumerical(rhs)) + return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs); + + else if (lhs.isBoolean()) + return eq_cmp(QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(lhs)), rhs); + + else if (rhs.isBoolean()) + return eq_cmp(lhs, QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(rhs))); + + else if (lhs.isObject() && ! rhs.isNull()) { + lhs = lhs.engine()->toPrimitive(lhs); + + if (lhs.isValid() && ! lhs.isObject()) + return eq_cmp(lhs, rhs); + } + + else if (rhs.isObject() && ! lhs.isNull()) { + rhs = rhs.engine()->toPrimitive(rhs); + + if (rhs.isValid() && ! rhs.isObject()) + return eq_cmp(lhs, rhs); + } + + return false; +} + +#if defined(Q_CC_GNU) && __GNUC__ <= 3 +bool QScriptContextPrivate::lt_cmp(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if (lhs.type() == rhs.type()) { + switch (lhs.type()) { + case QScript::InvalidType: + case QScript::UndefinedType: + case QScript::NullType: + return false; + + case QScript::NumberType: + return lhs.m_number_value < rhs.m_number_value; + + case QScript::IntegerType: + return lhs.m_int_value < rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value < rhs.m_bool_value; + + default: + break; + } // switch + } +#else +bool QScriptContextPrivate::lt_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ +#endif + if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType)) + return lhs.m_string_value->s < rhs.m_string_value->s; + + if (lhs.isObject()) + lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint); + + if (rhs.isObject()) + rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint); + + if (lhs.isString() && rhs.isString()) + return QScriptEnginePrivate::convertToNativeString(lhs) < QScriptEnginePrivate::convertToNativeString(rhs); + + qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs); +#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET + if (qIsNaN(n1) || qIsNaN(n2)) + return false; +#endif + return n1 < n2; +} + +bool QScriptContextPrivate::le_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType)) + return lhs.m_string_value->s <= rhs.m_string_value->s; + + if (lhs.isObject()) + lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint); + + if (rhs.isObject()) + rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint); + + if (lhs.isString() && rhs.isString()) + return QScriptEnginePrivate::convertToNativeString(lhs) <= QScriptEnginePrivate::convertToNativeString(rhs); + + qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + return n1 <= n2; +} + +const QScriptInstruction *QScriptContextPrivate::findExceptionHandler( + const QScriptInstruction *ip) const +{ + Q_ASSERT(m_code); + int offset = ip - m_code->firstInstruction; + for (int i = 0; i < m_code->exceptionHandlers.count(); ++i) { + QScript::ExceptionHandlerDescriptor e = m_code->exceptionHandlers.at(i); + if (offset >= e.startInstruction() && offset <= e.endInstruction()) { + return m_code->firstInstruction + e.handlerInstruction(); + } + } + return 0; +} + +const QScriptInstruction *QScriptContextPrivate::findExceptionHandlerRecursive( + const QScriptInstruction *ip, QScriptContextPrivate **handlerContext) const +{ + const QScriptContextPrivate *ctx = this; + const QScriptInstruction *iip = ip; + while (ctx) { + if (ctx->m_code) { + const QScriptInstruction *ep = ctx->findExceptionHandler(iip); + if (ep) { + Q_ASSERT(handlerContext); + *handlerContext = const_cast<QScriptContextPrivate*>(ctx); + return ep; + } + } + ctx = ctx->parentContext(); + if (ctx) + iip = ctx->iPtr; + } + return 0; +} + +/*! + Requires that iPtr in current context is in sync +*/ +QScriptContextPrivate *QScriptContextPrivate::exceptionHandlerContext() const +{ + QScriptContextPrivate *handlerContext; + if (findExceptionHandlerRecursive(iPtr, &handlerContext)) + return handlerContext; + return 0; +} + +QScriptContext *QScriptContextPrivate::get(QScriptContextPrivate *d) +{ + if (d) + return d->q_func(); + return 0; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptcontext_p.h b/src/script/qscriptcontext_p.h new file mode 100644 index 0000000..b5be471 --- /dev/null +++ b/src/script/qscriptcontext_p.h @@ -0,0 +1,361 @@ +/**************************************************************************** +** +** 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 QSCRIPTCONTEXT_P_H +#define QSCRIPTCONTEXT_P_H + +#include "qscriptcontextfwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptenginefwd_p.h" +#include "qscriptnameid_p.h" + +#include <QtCore/qnumeric.h> + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +inline QScriptContextPrivate::QScriptContextPrivate() + : previous(0), + argc(0), + m_state(QScriptContext::NormalState), + args(0), + tempStack(0), + stackPtr(0), + m_code(0), + iPtr(0), + firstInstruction(0), + lastInstruction(0), + currentLine(0), + currentColumn(0), + errorLineNumber(0), + catching(false), + m_calledAsConstructor(false), + calleeMetaIndex(0), + q_ptr(0) +{ +} + +inline QScriptContextPrivate *QScriptContextPrivate::get(QScriptContext *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline const QScriptContextPrivate *QScriptContextPrivate::get(const QScriptContext *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline QScriptContext *QScriptContextPrivate::create() +{ + return new QScriptContext; +} + +inline QScriptEnginePrivate *QScriptContextPrivate::engine() const +{ + return m_activation.engine(); +} + +inline QScriptContextPrivate *QScriptContextPrivate::parentContext() const +{ + return previous; +} + +inline void QScriptContextPrivate::init(QScriptContextPrivate *parent) +{ + m_state = QScriptContext::NormalState; + previous = parent; + args = 0; + argc = 0; + m_code = 0; + iPtr = firstInstruction = lastInstruction = 0; + stackPtr = tempStack = (parent != 0) ? parent->stackPtr : 0; + m_activation.invalidate(); + m_thisObject.invalidate(); + m_result.invalidate(); + m_scopeChain.invalidate(); + m_callee.invalidate(); + m_arguments.invalidate(); + currentLine = -1; + currentColumn = -1; + errorLineNumber = -1; + m_calledAsConstructor = false; +} + +inline QScriptValueImpl QScriptContextPrivate::argument(int index) const +{ + if (index >= argc) + return engine()->undefinedValue(); + + Q_ASSERT(args != 0); + return args[index]; +} + +inline int QScriptContextPrivate::argumentCount() const +{ + return argc; +} + +inline QScriptValueImpl QScriptContextPrivate::argumentsObject() const +{ + if (!m_arguments.isValid() && m_activation.isValid()) { + QScriptContextPrivate *dd = const_cast<QScriptContextPrivate*>(this); + engine()->newArguments(&dd->m_arguments, m_activation, + argc, m_callee); + } + return m_arguments; +} + +inline void QScriptContextPrivate::throwException() +{ + m_state = QScriptContext::ExceptionState; +} + +inline bool QScriptContextPrivate::hasUncaughtException() const +{ + return m_state == QScriptContext::ExceptionState; +} + +inline void QScriptContextPrivate::recover() +{ + m_state = QScriptContext::NormalState; + errorLineNumber = -1; +} + +inline bool QScriptContextPrivate::isNumerical(const QScriptValueImpl &v) +{ + switch (v.type()) { + case QScript::BooleanType: + case QScript::IntegerType: + case QScript::NumberType: + return true; + + default: + return false; + } +} + +inline bool QScriptContextPrivate::eq_cmp(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + if (lhs.type() == rhs.type()) { + switch (lhs.type()) { + case QScript::InvalidType: + case QScript::UndefinedType: + case QScript::NullType: + return true; + + case QScript::NumberType: + return lhs.m_number_value == rhs.m_number_value; + + case QScript::ReferenceType: + case QScript::IntegerType: + return lhs.m_int_value == rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value == rhs.m_bool_value; + + case QScript::StringType: + if (lhs.m_string_value->unique && rhs.m_string_value->unique) + return lhs.m_string_value == rhs.m_string_value; + return lhs.m_string_value->s == rhs.m_string_value->s; + + case QScript::PointerType: + return lhs.m_ptr_value == rhs.m_ptr_value; + + case QScript::ObjectType: + if (lhs.isVariant()) + return lhs.m_object_value == rhs.m_object_value || lhs.toVariant() == rhs.toVariant(); +#ifndef QT_NO_QOBJECT + else if (lhs.isQObject()) + return lhs.m_object_value == rhs.m_object_value || lhs.toQObject() == rhs.toQObject(); +#endif + else + return lhs.m_object_value == rhs.m_object_value; + + case QScript::LazyStringType: + return *lhs.m_lazy_string_value == *rhs.m_lazy_string_value; + } + } + + return eq_cmp_helper(lhs, rhs); +} + +inline bool QScriptContextPrivate::strict_eq_cmp( const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + if (lhs.type() != rhs.type()) + return false; + + switch (lhs.type()) { + case QScript::InvalidType: + case QScript::UndefinedType: + case QScript::NullType: + return true; + + case QScript::NumberType: + if (qIsNaN(lhs.m_number_value) || qIsNaN(rhs.m_number_value)) + return false; + return lhs.m_number_value == rhs.m_number_value; + + case QScript::IntegerType: + return lhs.m_int_value == rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value == rhs.m_bool_value; + + case QScript::StringType: + if (lhs.m_string_value->unique && rhs.m_string_value->unique) + return lhs.m_string_value == rhs.m_string_value; + return lhs.m_string_value->s == rhs.m_string_value->s; + + case QScript::ObjectType: + return lhs.m_object_value == rhs.m_object_value; + + case QScript::ReferenceType: + return lhs.m_int_value == rhs.m_int_value; + + case QScript::PointerType: + return lhs.m_ptr_value == rhs.m_ptr_value; + + case QScript::LazyStringType: + return *lhs.m_lazy_string_value == *rhs.m_lazy_string_value; + } + + return false; +} + +inline QScriptValueImpl QScriptContextPrivate::throwTypeError(const QString &text) +{ + return throwError(QScriptContext::TypeError, text); +} + +inline QScriptValueImpl QScriptContextPrivate::throwSyntaxError(const QString &text) +{ + return throwError(QScriptContext::SyntaxError, text); +} + +inline QScriptValueImpl QScriptContextPrivate::thisObject() const +{ + return m_thisObject; +} + +inline void QScriptContextPrivate::setThisObject(const QScriptValueImpl &object) +{ + m_thisObject = object; +} + +inline QScriptValueImpl QScriptContextPrivate::callee() const +{ + return m_callee; +} + +inline bool QScriptContextPrivate::isCalledAsConstructor() const +{ + return m_calledAsConstructor; +} + +inline QScriptValueImpl QScriptContextPrivate::returnValue() const +{ + return m_result; +} + +inline void QScriptContextPrivate::setReturnValue(const QScriptValueImpl &value) +{ + m_result = value; +} + +inline QScriptValueImpl QScriptContextPrivate::activationObject() const +{ + if (previous && !m_activation.property(QLatin1String("arguments")).isValid()) { + QScriptContextPrivate *dd = const_cast<QScriptContextPrivate*>(this); + dd->m_activation.setProperty(QLatin1String("arguments"), argumentsObject()); + } + return m_activation; +} + +inline void QScriptContextPrivate::setActivationObject(const QScriptValueImpl &activation) +{ + m_activation = activation; +} + +inline const QScriptInstruction *QScriptContextPrivate::instructionPointer() +{ + return iPtr; +} + +inline void QScriptContextPrivate::setInstructionPointer(const QScriptInstruction *instructionPointer) +{ + iPtr = instructionPointer; +} + +inline const QScriptValueImpl *QScriptContextPrivate::baseStackPointer() const +{ + return tempStack; +} + +inline const QScriptValueImpl *QScriptContextPrivate::currentStackPointer() const +{ + return stackPtr; +} + +inline QScriptContext::ExecutionState QScriptContextPrivate::state() const +{ + return m_state; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif diff --git a/src/script/qscriptcontextfwd_p.h b/src/script/qscriptcontextfwd_p.h new file mode 100644 index 0000000..9b486d6 --- /dev/null +++ b/src/script/qscriptcontextfwd_p.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** 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 QSCRIPTCONTEXTFWD_P_H +#define QSCRIPTCONTEXTFWD_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 "qscriptvalueimplfwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptcontext.h" + +#include <QtCore/qobjectdefs.h> + +#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET +#include <QtCore/qnumeric.h> +#endif + +QT_BEGIN_NAMESPACE + +namespace QScript { + namespace AST { + class Node; + } +class Code; +} + +class QScriptInstruction; + +class QScriptContextPrivate +{ + Q_DECLARE_PUBLIC(QScriptContext) +public: + inline QScriptContextPrivate(); + + static inline QScriptContextPrivate *get(QScriptContext *q); + static inline const QScriptContextPrivate *get(const QScriptContext *q); + static QScriptContext *get(QScriptContextPrivate *d); + + static inline QScriptContext *create(); + + inline QScriptEnginePrivate *engine() const; + inline QScriptContextPrivate *parentContext() const; + + inline void init(QScriptContextPrivate *parent); + inline QScriptValueImpl argument(int index) const; + inline int argumentCount() const; + inline QScriptValueImpl argumentsObject() const; + + inline void throwException(); + inline bool hasUncaughtException() const; + const QScriptInstruction *findExceptionHandler(const QScriptInstruction *ip) const; + const QScriptInstruction *findExceptionHandlerRecursive( + const QScriptInstruction *ip, QScriptContextPrivate **handlerContext) const; + QScriptContextPrivate *exceptionHandlerContext() const; + inline void recover(); + QStringList backtrace() const; + + static inline bool isNumerical(const QScriptValueImpl &v); + + static inline bool eq_cmp(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs); + + static bool eq_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs); + +#if defined(Q_CC_GNU) && __GNUC__ <= 3 + static bool lt_cmp(QScriptValueImpl lhs, QScriptValueImpl rhs); +#else + static bool lt_cmp(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) + { + if (lhs.type() == rhs.type()) { + switch (lhs.type()) { + case QScript::UndefinedType: + case QScript::NullType: + return false; + + case QScript::NumberType: +#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET + if (qIsNaN(lhs.m_number_value) || qIsNaN(rhs.m_number_value)) + return false; +#endif + return lhs.m_number_value < rhs.m_number_value; + + case QScript::IntegerType: + return lhs.m_int_value < rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value < rhs.m_bool_value; + + default: + break; + } // switch + } + + return lt_cmp_helper(lhs, rhs); + } + + static bool lt_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs); +#endif + + static bool le_cmp(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) + { + if (lhs.type() == rhs.type()) { + switch (lhs.type()) { + case QScript::UndefinedType: + case QScript::NullType: + return true; + + case QScript::NumberType: + return lhs.m_number_value <= rhs.m_number_value; + + case QScript::IntegerType: + return lhs.m_int_value <= rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value <= rhs.m_bool_value; + + default: + break; + } // switch + } + + return le_cmp_helper(lhs, rhs); + } + + static bool le_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs); + + static inline bool strict_eq_cmp(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs); + + bool resolveField(QScriptEnginePrivate *eng, QScriptValueImpl *stackPtr, + QScriptValueImpl *value); + + void execute(QScript::Code *code); + + QScriptValueImpl throwError(QScriptContext::Error error, const QString &text); + QScriptValueImpl throwError(const QString &text); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + qint64 scriptId() const; +#endif + QString fileName() const; + QString functionName() const; + void setDebugInformation(QScriptValueImpl *error) const; + + QScriptValueImpl throwNotImplemented(const QString &name); + QScriptValueImpl throwNotDefined(const QString &name); + QScriptValueImpl throwNotDefined(QScriptNameIdImpl *nameId); + + inline QScriptValueImpl throwTypeError(const QString &text); + inline QScriptValueImpl throwSyntaxError(const QString &text); + + inline QScriptValueImpl thisObject() const; + inline void setThisObject(const QScriptValueImpl &object); + + inline QScriptValueImpl callee() const; + inline bool isCalledAsConstructor() const; + + inline QScriptValueImpl returnValue() const; + inline void setReturnValue(const QScriptValueImpl &value); + + inline QScriptValueImpl activationObject() const; + inline void setActivationObject(const QScriptValueImpl &activation); + + inline const QScriptInstruction *instructionPointer(); + inline void setInstructionPointer(const QScriptInstruction *instructionPointer); + + inline const QScriptValueImpl *baseStackPointer() const; + inline const QScriptValueImpl *currentStackPointer() const; + + inline QScriptContext::ExecutionState state() const; + +public: + QScriptContextPrivate *previous; + int argc; + QScriptContext::ExecutionState m_state; + + QScriptValueImpl m_activation; + QScriptValueImpl m_thisObject; + QScriptValueImpl m_result; + QScriptValueImpl m_scopeChain; + QScriptValueImpl m_callee; + QScriptValueImpl m_arguments; + + QScriptValueImpl *args; + QScriptValueImpl *tempStack; + QScriptValueImpl *stackPtr; + + QScript::Code *m_code; + const QScriptInstruction *iPtr; + const QScriptInstruction *firstInstruction; + const QScriptInstruction *lastInstruction; + + int currentLine; + int currentColumn; + + int errorLineNumber; + + bool catching; + bool m_calledAsConstructor; + + int calleeMetaIndex; + + QScriptContext *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif diff --git a/src/script/qscriptcontextinfo.cpp b/src/script/qscriptcontextinfo.cpp new file mode 100644 index 0000000..260d19f --- /dev/null +++ b/src/script/qscriptcontextinfo.cpp @@ -0,0 +1,553 @@ +/**************************************************************************** +** +** 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 "qscriptcontextinfo.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptcontextinfo_p.h" +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include <QtCore/qdatastream.h> + +QT_BEGIN_NAMESPACE + +/*! + \since 4.4 + \class QScriptContextInfo + + \brief The QScriptContextInfo class provides additional information about a QScriptContext. + + \ingroup script + \mainclass + + QScriptContextInfo is typically used for debugging purposes. It can + provide information about the code being executed, such as the type + of the called function, and the original source code location of the + current statement. + + If the called function is executing Qt Script code, you can obtain + the script location with the functions fileName(), lineNumber() and + columnNumber(). + + You can obtain the starting line number and ending line number of a + Qt Script function definition with functionStartLineNumber() and + functionEndLineNumber(), respectively. + + For Qt Script functions and Qt methods (e.g. slots), you can call + functionParameterNames() to get the names of the formal parameters of the + function. + + For Qt methods and Qt property accessors, you can obtain the index + of the underlying QMetaMethod or QMetaProperty by calling + functionMetaIndex(). + + \sa QScriptContext, QScriptEngineAgent +*/ + +/*! + \enum QScriptContextInfo::FunctionType + + This enum specifies the type of function being called. + + \value ScriptFunction The function is a Qt Script function, i.e. it was defined through a call to QScriptEngine::evaluate(). + \value QtFunction The function is a Qt function (a signal, slot or method). + \value QtPropertyFunction The function is a Qt property getter or setter. + \value NativeFunction The function is a built-in Qt Script function, or it was defined through a call to QScriptEngine::newFunction(). +*/ + +/*! + \internal +*/ +QScriptContextInfoPrivate::QScriptContextInfoPrivate() + : q_ptr(0) +{ + ref = 0; + functionType = QScriptContextInfo::NativeFunction; + functionMetaIndex = -1; + functionStartLineNumber = -1; + functionEndLineNumber = -1; + scriptId = -1; + lineNumber = -1; + columnNumber = -1; +} + +/*! + \internal +*/ +QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *context) + : q_ptr(0) +{ + Q_ASSERT(context); + ref = 0; + functionType = QScriptContextInfo::NativeFunction; + functionMetaIndex = -1; + functionStartLineNumber = -1; + functionEndLineNumber = -1; + + const QScriptContextPrivate *ctx_p = QScriptContextPrivate::get(context); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + scriptId = ctx_p->scriptId(); +#endif + fileName = ctx_p->fileName(); + lineNumber = ctx_p->currentLine; + columnNumber = ctx_p->currentColumn; + + QScriptValueImpl callee = ctx_p->engine()->toImpl(context->callee()); + QScriptFunction *fun = callee.toFunction(); + if (fun) { + functionName = fun->functionName(); + functionStartLineNumber = fun->startLineNumber(); + functionEndLineNumber = fun->endLineNumber(); + + switch (fun->type()) { + case QScriptFunction::Unknown: + functionType = QScriptContextInfo::NativeFunction; + break; + + case QScriptFunction::Script: + functionType = QScriptContextInfo::ScriptFunction; + for (int i = 0; i < fun->formals.count(); ++i) + parameterNames.append(fun->formals.at(i)->s); + break; + + case QScriptFunction::C: + functionType = QScriptContextInfo::NativeFunction; + break; + + case QScriptFunction::C2: + functionType = QScriptContextInfo::NativeFunction; + break; + + case QScriptFunction::C3: + functionType = QScriptContextInfo::NativeFunction; + break; + + case QScriptFunction::Qt: { + functionType = QScriptContextInfo::QtFunction; + functionMetaIndex = ctx_p->calleeMetaIndex; + +#ifndef QT_NO_QOBJECT + const QMetaObject *meta; + meta = static_cast<QScript::QtFunction*>(fun)->metaObject(); + if (meta) { + QMetaMethod method = meta->method(functionMetaIndex); + QList<QByteArray> formals = method.parameterNames(); + for (int i = 0; i < formals.count(); ++i) + parameterNames.append(QLatin1String(formals.at(i))); + } +#endif + } break; + + case QScriptFunction::QtProperty: + functionType = QScriptContextInfo::QtPropertyFunction; + functionMetaIndex = ctx_p->calleeMetaIndex; + break; + } + } +} + +/*! + \internal +*/ +QScriptContextInfoPrivate::~QScriptContextInfoPrivate() +{ +} + +/*! + Constructs a new QScriptContextInfo from the given \a context. + + The relevant information is extracted from the \a context at + construction time; i.e. if you continue script execution in the \a + context, the new state of the context will not be reflected in a + previously created QScriptContextInfo. +*/ +QScriptContextInfo::QScriptContextInfo(const QScriptContext *context) +{ + if (context) { + d_ptr = new QScriptContextInfoPrivate(context); + d_ptr->q_ptr = this; + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + Constructs a new QScriptContextInfo from the \a other info. +*/ +QScriptContextInfo::QScriptContextInfo(const QScriptContextInfo &other) + : d_ptr(other.d_ptr) +{ + if (d_ptr) + d_ptr->ref.ref(); +} + +/*! + Constructs a null QScriptContextInfo. + + \sa isNull() +*/ +QScriptContextInfo::QScriptContextInfo() + : d_ptr(0) +{ +} + +/*! + Destroys the QScriptContextInfo. +*/ +QScriptContextInfo::~QScriptContextInfo() +{ + if (d_ptr && !d_ptr->ref.deref()) { + delete d_ptr; + d_ptr = 0; + } +} + +/*! + Assigns the \a other info to this QScriptContextInfo, + and returns a reference to this QScriptContextInfo. +*/ +QScriptContextInfo &QScriptContextInfo::operator=(const QScriptContextInfo &other) +{ + if (d_ptr == other.d_ptr) + return *this; + if (d_ptr && !d_ptr->ref.deref()) { + delete d_ptr; + d_ptr = 0; + } + d_ptr = other.d_ptr; + if (d_ptr) + d_ptr->ref.ref(); + return *this; +} + +/*! + Returns the ID of the script where the code being executed was + defined, or -1 if the ID is not available (i.e. a native function is + being executed). + + \sa QScriptEngineAgent::scriptLoad() +*/ +qint64 QScriptContextInfo::scriptId() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->scriptId; +} + +/*! + Returns the name of the file where the code being executed was + defined, if available; otherwise returns an empty string. + + For Qt Script code, this function returns the fileName argument + that was passed to QScriptEngine::evaluate(). + + \sa lineNumber(), functionName() +*/ +QString QScriptContextInfo::fileName() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return QString(); + return d->fileName; +} + +/*! + Returns the line number corresponding to the statement being + executed, or -1 if the line number is not available. + + The line number is only available if Qt Script code is being + executed. + + \sa columnNumber(), fileName() +*/ +int QScriptContextInfo::lineNumber() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->lineNumber; +} + +/*! + Returns the column number corresponding to the statement being + executed, or -1 if the column number is not available. + + The column number is only available if Qt Script code is being + executed. + + \sa lineNumber(), fileName() +*/ +int QScriptContextInfo::columnNumber() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->columnNumber; +} + +/*! + Returns the name of the called function, or an empty string if + the name is not available. + + For script functions of type QtPropertyFunction, this function + always returns the name of the property; you can use + QScriptContext::argumentCount() to differentiate between reads and + writes. + + \sa fileName(), functionType() +*/ +QString QScriptContextInfo::functionName() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return QString(); + return d->functionName; +} + +/*! + Returns the type of the called function. + + \sa functionName(), QScriptContext::callee() +*/ +QScriptContextInfo::FunctionType QScriptContextInfo::functionType() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return NativeFunction; + return d->functionType; +} + +/*! + Returns the line number where the definition of the called function + starts, or -1 if the line number is not available. + + The starting line number is only available if the functionType() is + ScriptFunction. + + \sa functionEndLineNumber(), fileName() +*/ +int QScriptContextInfo::functionStartLineNumber() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->functionStartLineNumber; +} + +/*! + Returns the line number where the definition of the called function + ends, or -1 if the line number is not available. + + The ending line number is only available if the functionType() is + ScriptFunction. + + \sa functionStartLineNumber() +*/ +int QScriptContextInfo::functionEndLineNumber() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->functionEndLineNumber; +} + +/*! + Returns the names of the formal parameters of the called function, + or an empty QStringList if the parameter names are not available. + + \sa QScriptContext::argument() +*/ +QStringList QScriptContextInfo::functionParameterNames() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return QStringList(); + return d->parameterNames; +} + +/*! + Returns the meta index of the called function, or -1 if the meta + index is not available. + + The meta index is only available if the functionType() is QtFunction + or QtPropertyFunction. For QtFunction, the meta index can be passed + to QMetaObject::method() to obtain the corresponding method + definition; for QtPropertyFunction, the meta index can be passed to + QMetaObject::property() to obtain the corresponding property + definition. + + \sa QScriptContext::thisObject() +*/ +int QScriptContextInfo::functionMetaIndex() const +{ + Q_D(const QScriptContextInfo); + if (!d) + return -1; + return d->functionMetaIndex; +} + +/*! + Returns true if this QScriptContextInfo is null, i.e. does not + contain any information. +*/ +bool QScriptContextInfo::isNull() const +{ + Q_D(const QScriptContextInfo); + return (d == 0); +} + +/*! + Returns true if this QScriptContextInfo is equal to the \a other + info, otherwise returns false. +*/ +bool QScriptContextInfo::operator==(const QScriptContextInfo &other) const +{ + Q_D(const QScriptContextInfo); + const QScriptContextInfoPrivate *od = other.d_func(); + if (d == od) + return true; + if (!d || !od) + return false; + return ((d->scriptId == od->scriptId) + && (d->lineNumber == od->lineNumber) + && (d->columnNumber == od->columnNumber) + && (d->fileName == od->fileName) + && (d->functionName == od->functionName) + && (d->functionType == od->functionType) + && (d->functionStartLineNumber == od->functionStartLineNumber) + && (d->functionEndLineNumber == od->functionEndLineNumber) + && (d->functionMetaIndex == od->functionMetaIndex) + && (d->parameterNames == od->parameterNames)); +} + +/*! + Returns true if this QScriptContextInfo is not equal to the \a other + info, otherwise returns false. +*/ +bool QScriptContextInfo::operator!=(const QScriptContextInfo &other) const +{ + return !(*this == other); +} + +#ifndef QT_NO_DATASTREAM +/*! + \fn QDataStream &operator<<(QDataStream &stream, const QScriptContextInfo &info) + \since 4.4 + \relates QScriptContextInfo + + Writes the given \a info to the specified \a stream. +*/ +QDataStream &operator<<(QDataStream &out, const QScriptContextInfo &info) +{ + out << info.scriptId(); + out << (qint32)info.lineNumber(); + out << (qint32)info.columnNumber(); + + out << (quint32)info.functionType(); + out << (qint32)info.functionStartLineNumber(); + out << (qint32)info.functionEndLineNumber(); + out << (qint32)info.functionMetaIndex(); + + out << info.fileName(); + out << info.functionName(); + out << info.functionParameterNames(); + + return out; +} + +/*! + \fn QDataStream &operator>>(QDataStream &stream, QScriptContextInfo &info) + \since 4.4 + \relates QScriptContextInfo + + Reads a QScriptContextInfo from the specified \a stream into the + given \a info. +*/ +Q_SCRIPT_EXPORT QDataStream &operator>>(QDataStream &in, QScriptContextInfo &info) +{ + if (!info.d_ptr) { + info.d_ptr = new QScriptContextInfoPrivate(); + info.d_ptr->ref.ref(); + } + + in >> info.d_ptr->scriptId; + + qint32 line; + in >> line; + info.d_ptr->lineNumber = line; + + qint32 column; + in >> column; + info.d_ptr->columnNumber = column; + + quint32 ftype; + in >> ftype; + info.d_ptr->functionType = QScriptContextInfo::FunctionType(ftype); + + qint32 startLine; + in >> startLine; + info.d_ptr->functionStartLineNumber = startLine; + + qint32 endLine; + in >> endLine; + info.d_ptr->functionEndLineNumber = endLine; + + qint32 metaIndex; + in >> metaIndex; + info.d_ptr->functionMetaIndex = metaIndex; + + in >> info.d_ptr->fileName; + in >> info.d_ptr->functionName; + in >> info.d_ptr->parameterNames; + + return in; +} +#endif + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptcontextinfo.h b/src/script/qscriptcontextinfo.h new file mode 100644 index 0000000..a683733 --- /dev/null +++ b/src/script/qscriptcontextinfo.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 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 QSCRIPTCONTEXTINFO_H +#define QSCRIPTCONTEXTINFO_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qlist.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptContext; +#ifndef QT_NO_DATASTREAM +class QDataStream; +#endif + +class QScriptContextInfoPrivate; +class Q_SCRIPT_EXPORT QScriptContextInfo +{ +public: +#ifndef QT_NO_DATASTREAM + friend Q_SCRIPT_EXPORT QDataStream &operator<<(QDataStream &, const QScriptContextInfo &); + friend Q_SCRIPT_EXPORT QDataStream &operator>>(QDataStream &, QScriptContextInfo &); +#endif + + enum FunctionType { + ScriptFunction, + QtFunction, + QtPropertyFunction, + NativeFunction + }; + + QScriptContextInfo(const QScriptContext *context); + QScriptContextInfo(const QScriptContextInfo &other); + QScriptContextInfo(); + ~QScriptContextInfo(); + + QScriptContextInfo &operator=(const QScriptContextInfo &other); + + bool isNull() const; + + qint64 scriptId() const; + QString fileName() const; + int lineNumber() const; + int columnNumber() const; + + QString functionName() const; + FunctionType functionType() const; + + QStringList functionParameterNames() const; + + int functionStartLineNumber() const; + int functionEndLineNumber() const; + + int functionMetaIndex() const; + + bool operator==(const QScriptContextInfo &other) const; + bool operator!=(const QScriptContextInfo &other) const; + +private: + QScriptContextInfoPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptContextInfo) +}; + +typedef QList<QScriptContextInfo> QScriptContextInfoList; + +#ifndef QT_NO_DATASTREAM +Q_SCRIPT_EXPORT QDataStream &operator<<(QDataStream &, const QScriptContextInfo &); +Q_SCRIPT_EXPORT QDataStream &operator>>(QDataStream &, QScriptContextInfo &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptcontextinfo_p.h b/src/script/qscriptcontextinfo_p.h new file mode 100644 index 0000000..775a81c --- /dev/null +++ b/src/script/qscriptcontextinfo_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 QSCRIPTCONTEXTINFO_P_H +#define QSCRIPTCONTEXTINFO_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 "qscriptcontextinfo.h" + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qatomic.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +class QScriptContext; + +class QScriptContextInfo; +class QScriptContextInfoPrivate +{ + Q_DECLARE_PUBLIC(QScriptContextInfo) +public: + QScriptContextInfoPrivate(); + QScriptContextInfoPrivate(const QScriptContext *context); + ~QScriptContextInfoPrivate(); + + qint64 scriptId; + int lineNumber; + int columnNumber; + QString fileName; + + QString functionName; + QScriptContextInfo::FunctionType functionType; + + int functionStartLineNumber; + int functionEndLineNumber; + int functionMetaIndex; + + QStringList parameterNames; + + QBasicAtomicInt ref; + + QScriptContextInfo *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptecmaarray.cpp b/src/script/qscriptecmaarray.cpp new file mode 100644 index 0000000..d068ba6 --- /dev/null +++ b/src/script/qscriptecmaarray.cpp @@ -0,0 +1,777 @@ +/**************************************************************************** +** +** 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 "qscriptecmaarray_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptclassdata_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class ArrayClassData: public QScriptClassData +{ + QScriptClassInfo *m_classInfo; + +public: + ArrayClassData(QScriptClassInfo *classInfo); + virtual ~ArrayClassData(); + + inline QScriptClassInfo *classInfo() const + { return m_classInfo; } + + virtual void mark(const QScriptValueImpl &object, int generation); + virtual bool resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, + QScriptValueImpl *base, + QScript::AccessMode mode); + virtual bool get(const QScriptValueImpl &obj, const Member &m, + QScriptValueImpl *out_value); + virtual bool put(QScriptValueImpl *object, const Member &member, + const QScriptValueImpl &value); + virtual bool removeMember(const QScriptValueImpl &object, + const QScript::Member &member); + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object); +}; + +class ArrayClassDataIterator: public QScriptClassDataIterator +{ +public: + ArrayClassDataIterator(Array::Instance *instance); + virtual ~ArrayClassDataIterator(); + + virtual bool hasNext() const; + virtual void next(QScript::Member *member); + + virtual bool hasPrevious() const; + virtual void previous(QScript::Member *member); + + virtual void toFront(); + virtual void toBack(); + +private: + Array::Instance *m_instance; + QList<uint> m_keys; + quint32 m_pos; +}; + +ArrayClassData::ArrayClassData(QScriptClassInfo *classInfo): + m_classInfo(classInfo) +{ +} + +ArrayClassData::~ArrayClassData() +{ +} + +void ArrayClassData::mark(const QScriptValueImpl &object, int generation) +{ + Array::Instance *instance = Array::Instance::get(object, classInfo()); + if (! instance) + return; + + instance->value.mark(generation); +} + +bool ArrayClassData::resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, + QScriptValueImpl *base, + QScript::AccessMode access) +{ + QScriptEnginePrivate *eng_p = object.engine(); + + Array::Instance *instance = Array::Instance::get(object, classInfo()); + if (!instance) + return false; + + if (nameId == eng_p->idTable()->id_length) { + member->native(nameId, /*id=*/ 0, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + *base = object; + return true; + } + + QString propertyName = eng_p->toString(nameId); + bool isNumber; + quint32 pos = propertyName.toUInt(&isNumber); + + if (!isNumber || (pos == 0xFFFFFFFF) + || (QScriptValueImpl(pos).toString() != propertyName)) { // ### improve me + return false; + } + + if ((access == QScript::Read) && ((pos >= instance->value.count()) || !instance->value.at(pos).isValid())) + return false; + + member->native(0, pos, /*flags=*/0); + *base = object; + return true; +} + +bool ArrayClassData::get(const QScriptValueImpl &object, + const QScript::Member &member, + QScriptValueImpl *result) +{ + Q_ASSERT(member.isValid()); + + if (! member.isNativeProperty()) + return false; + + QScriptEnginePrivate *eng = object.engine(); + + Array::Instance *instance = Array::Instance::get(object, classInfo()); + if (! instance) + return false; + + if (member.nameId() == eng->idTable()->id_length) + *result = QScriptValueImpl(instance->value.count()); + + else { + quint32 pos = quint32 (member.id()); + + if (pos < instance->value.count()) + *result = instance->value.at(pos); + else + *result = eng->undefinedValue(); + } + + return true; +} + +bool ArrayClassData::put(QScriptValueImpl *object, + const QScript::Member &member, + const QScriptValueImpl &value) +{ + Q_ASSERT(object != 0); + Q_ASSERT(member.isValid()); + + if (! member.isNativeProperty()) + return false; + + Array::Instance *instance = Array::Instance::get(*object, classInfo()); + if (! instance) + return false; + + QScriptEnginePrivate *eng_p = object->engine(); + + if (member.nameId() == eng_p->idTable()->id_length) { + qsreal length = value.toNumber(); + quint32 len = eng_p->toUint32(length); + instance->value.resize(len); + } + + else if (member.nameId() == 0) { + quint32 pos = quint32 (member.id()); + instance->value.assign(pos, value); + } + + return true; +} + +bool ArrayClassData::removeMember(const QScriptValueImpl &object, + const QScript::Member &member) +{ + if (!member.isNativeProperty() || !member.isDeletable() || (member.nameId() != 0)) + return false; + + Array::Instance *instance = Array::Instance::get(object, classInfo()); + if (! instance) + return false; + + quint32 pos = quint32 (member.id()); + if (instance->value.at(pos).isValid()) + instance->value.assign(pos, QScriptValueImpl()); + return true; +} + +QScriptClassDataIterator *ArrayClassData::newIterator(const QScriptValueImpl &object) +{ + Array::Instance *instance = Array::Instance::get(object, classInfo()); + return new ArrayClassDataIterator(instance); +} + +ArrayClassDataIterator::ArrayClassDataIterator(Array::Instance *instance) +{ + m_instance = instance; + toFront(); +} + +ArrayClassDataIterator::~ArrayClassDataIterator() +{ +} + +bool ArrayClassDataIterator::hasNext() const +{ + quint32 limit = m_keys.isEmpty() ? m_instance->value.size() : quint32(m_keys.size()); + for (quint32 i = m_pos; i < limit; ++i) { + quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i); + if (m_instance->value.at(realI).isValid()) + return true; + } + return false; +} + +void ArrayClassDataIterator::next(QScript::Member *member) +{ + quint32 limit = m_keys.isEmpty() ? m_instance->value.size() : quint32(m_keys.size()); + for (quint32 i = m_pos; i < limit; ++i) { + quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i); + if (m_instance->value.at(realI).isValid()) { + member->native(/*nameId=*/0, realI, /*flags=*/0); + m_pos = i + 1; + return; + } + } + member->invalidate(); +} + +bool ArrayClassDataIterator::hasPrevious() const +{ + for (quint32 i = m_pos - 1; i != 0xFFFFFFFF; --i) { + quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i); + if (m_instance->value.at(realI).isValid()) + return true; + } + return false; +} + +void ArrayClassDataIterator::previous(QScript::Member *member) +{ + for (quint32 i = m_pos - 1; i != 0xFFFFFFFF; --i) { + quint32 realI = m_keys.isEmpty() ? i : m_keys.at(i); + if (m_instance->value.at(realI).isValid()) { + member->native(/*nameId=*/ 0, realI, /*flags=*/0); + m_pos = i; + return; + } + } + member->invalidate(); +} + +void ArrayClassDataIterator::toFront() +{ + m_keys = m_instance->value.keys(); + m_pos = 0; +} + +void ArrayClassDataIterator::toBack() +{ + m_keys = m_instance->value.keys(); + m_pos = m_keys.isEmpty() ? m_instance->value.count() : m_keys.size(); +} + + + +Array::Array(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("Array"), QScriptClassInfo::ArrayType) +{ + classInfo()->setData(new ArrayClassData(classInfo())); + + newArray(&publicPrototype, QScript::Array(eng)); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("toLocaleString"), method_toLocaleString, 0); + addPrototypeFunction(QLatin1String("concat"), method_concat, 1); + addPrototypeFunction(QLatin1String("join"), method_join, 1); + addPrototypeFunction(QLatin1String("pop"), method_pop, 0); + addPrototypeFunction(QLatin1String("push"), method_push, 1); + addPrototypeFunction(QLatin1String("reverse"), method_reverse, 0); + addPrototypeFunction(QLatin1String("shift"), method_shift, 0); + addPrototypeFunction(QLatin1String("slice"), method_slice, 2); + addPrototypeFunction(QLatin1String("sort"), method_sort, 1); + addPrototypeFunction(QLatin1String("splice"), method_splice, 2); + addPrototypeFunction(QLatin1String("unshift"), method_unshift, 1); +} + +Array::~Array() +{ +} + +void Array::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + QScript::Array value(engine()); + + if (context->argumentCount() == 1 && context->argument(0).isNumber()) { + qsreal size = context->argument(0).toNumber(); + quint32 isize = QScriptEnginePrivate::toUint32(size); + + if (size != qsreal(isize)) { + context->throwError(QScriptContext::RangeError, QLatin1String("invalid array length")); + return; + } + + value.resize(isize); + } else { + for (int i = 0; i < context->argumentCount(); ++i) { + value.assign(i, context->argument(i)); + } + } + + if (context->isCalledAsConstructor()) { + QScriptValueImpl &object = context->m_thisObject; + object.setClassInfo(classInfo()); + object.setPrototype(publicPrototype); + initArray(&object, value); + } else { + newArray(&context->m_result, value); + } + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Array::newArray(QScriptValueImpl *result, const QScript::Array &value) +{ + engine()->newObject(result, publicPrototype, classInfo()); + initArray(result, value); +} + +void Array::initArray(QScriptValueImpl *result, const QScript::Array &value) +{ + Instance *instance = new Instance(engine()); + instance->value = value; + result->setObjectData(instance); +} + +QScriptValueImpl Array::method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + return method_join(context, eng, classInfo); // ### fixme +} + +QScriptValueImpl Array::method_toLocaleString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + return method_toString(context, eng, classInfo); +} + +QScriptValueImpl Array::method_concat(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + QScript::Array result(eng); + + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) + result = instance->value; + + else { + QString v = context->thisObject().toString(); + result.assign(0, QScriptValueImpl(eng, v)); + } + + for (int i = 0; i < context->argumentCount(); ++i) { + quint32 k = result.size(); + QScriptValueImpl arg = context->argument(i); + + if (Instance *elt = Instance::get(arg, classInfo)) + result.concat(elt->value); + + else + result.assign(k, QScriptValueImpl(eng, arg.toString())); + } + + return eng->newArray(result); +} + +QScriptValueImpl Array::method_join(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl arg = context->argument(0); + + QString r4; + if (arg.isUndefined()) + r4 = QLatin1String(","); + else + r4 = arg.toString(); + + QScriptValueImpl self = context->thisObject(); + + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + QScriptValueImpl length = self.property(id_length); + qsreal r1 = length.isValid() ? length.toNumber() : 0; + quint32 r2 = QScriptEnginePrivate::toUint32(r1); + + if (! r2) + return QScriptValueImpl(eng, QString()); + + if (eng->visitedArrayElements.contains(self.objectValue())) { + // avoid infinite recursion + return QScriptValueImpl(eng, QString()); + } + eng->visitedArrayElements.insert(self.objectValue()); + + QString R; + + QScriptValueImpl r6 = self.property(QLatin1String("0")); + if (r6.isValid() && !(r6.isUndefined() || r6.isNull())) + R = r6.toString(); + + for (quint32 k = 1; k < r2; ++k) { + R += r4; + + QScriptNameIdImpl *name = eng->nameId(QScriptValueImpl(k).toString()); + QScriptValueImpl r12 = self.property(name); + + if (r12.isValid() && ! (r12.isUndefined() || r12.isNull())) + R += r12.toString(); + } + + eng->visitedArrayElements.remove(self.objectValue()); + return QScriptValueImpl(eng, R); +} + +QScriptValueImpl Array::method_pop(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (Instance *instance = Instance::get(self, classInfo)) { + QScriptValueImpl elt = instance->value.pop(); + if (! elt.isValid()) + elt = eng->undefinedValue(); + + return elt; + } + + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + + QScriptValueImpl r1 = self.property(id_length); + quint32 r2 = r1.toUInt32(); + if (! r2) { + self.setProperty(id_length, QScriptValueImpl(0)); + return eng->undefinedValue(); + } + QScriptNameIdImpl *r6 = eng->nameId(QScriptValueImpl(r2 - 1).toString()); + QScriptValueImpl r7 = self.property(r6); + self.deleteProperty(r6); + self.setProperty(id_length, QScriptValueImpl(r2 - 1)); + if (!r7.isValid()) + return eng->undefinedValue(); + return r7; +} + +QScriptValueImpl Array::method_push(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (Instance *instance = Instance::get(self, classInfo)) { + uint pos = instance->value.size(); + for (int i = 0; i < context->argumentCount(); ++i) { + QScriptValueImpl val = context->argument(i); + if (pos == 0xFFFFFFFF) { + self.setProperty(pos++, val); + self.setProperty(eng->idTable()->id_length, 0); + } else { + instance->value.assign(pos++, val); + } + } + return QScriptValueImpl(pos); + } + + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + QScriptValueImpl r1 = self.property(id_length); + quint32 n = r1.toUInt32(); + for (int index = 0; index < context->argumentCount(); ++index, ++n) { + QScriptValueImpl r3 = context->argument(index); + QScriptNameIdImpl *name = eng->nameId(QScriptValueImpl(n).toString()); + self.setProperty(name, r3); + } + QScriptValueImpl r(n); + self.setProperty(id_length, r); + return r; +} + +QScriptValueImpl Array::method_reverse(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (Instance *instance = Instance::get(self, classInfo)) { + int lo = 0, hi = instance->value.count () - 1; + + for (; lo < hi; ++lo, --hi) { + QScriptValueImpl tmp = instance->value.at(lo); + instance->value.assign(lo, instance->value.at(hi)); + instance->value.assign(hi, tmp); + } + + } else { + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + + QScriptValueImpl lengthValue = self.property(id_length); + quint32 length = 0; + if (lengthValue.isValid()) + length = QScriptEnginePrivate::toUint32(lengthValue.toNumber()); + const quint32 m = length / 2; + for (quint32 i = 0; i < m; ++i) { + quint32 j = length - i - 1; + + QScriptNameIdImpl *iid = eng->nameId(QScriptValueImpl(i).toString()); + QScriptNameIdImpl *jid = eng->nameId(QScriptValueImpl(j).toString()); + + QScript::Member imember; + QScriptValueImpl ibase; + QScriptValueImpl ival; + bool iok = self.resolve(iid, &imember, &ibase, QScriptValue::ResolvePrototype, QScript::ReadWrite); + if (iok) + ibase.get(iid, &ival); + else + ival = eng->undefinedValue(); + + QScript::Member jmember; + QScriptValueImpl jbase; + QScriptValueImpl jval; + bool jok = self.resolve(jid, &jmember, &jbase, QScriptValue::ResolvePrototype, QScript::ReadWrite); + if (jok) + jbase.get(jid, &jval); + else + jval = eng->undefinedValue(); + + if (!jok) { + if (iok) { + if (eng->strictlyEquals(ibase, self)) + ibase.removeMember(imember); + self.setProperty(jid, ival); + } + } else if (!iok) { + self.setProperty(iid, jval); + if (eng->strictlyEquals(jbase, self)) + jbase.removeMember(jmember); + } else { + if (eng->strictlyEquals(self, ibase)) + self.put(imember, jval); + else + self.setProperty(iid, jval); + if (eng->strictlyEquals(self, jbase)) + self.put(jmember, ival); + else + self.setProperty(jid, ival); + } + } + } + + return context->thisObject(); +} + +QScriptValueImpl Array::method_shift(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + + QScriptValueImpl self = context->thisObject(); + quint32 length = self.property(id_length).toUInt32(); + if (length == 0) { + self.setProperty(id_length, QScriptValueImpl(0)); + return eng->undefinedValue(); + } + + QScript::Member member; + QScriptValueImpl base; + + QScriptValueImpl result = self.property(QLatin1String("0")); + if (! result.isValid()) + result = eng->undefinedValue(); + + for (quint32 index = 1; index < length; ++index) { + QScriptNameIdImpl *k = eng->nameId(QScriptValueImpl(index).toString()); + QScriptNameIdImpl *k1 = eng->nameId(QScriptValueImpl(index - 1).toString()); + + QScriptValueImpl v = self.property(k); + QScriptValueImpl v1 = self.property(k1); + + if (v.isValid()) + self.setProperty(k1, v); + + else if (v1.isValid() && self.resolve(k1, &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite)) + self.removeMember(member); + } + + QScriptValueImpl len = QScriptValueImpl(length - 1); + + if (self.resolve(eng->nameId(len.toString()), &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite)) + self.removeMember(member); + + self.setProperty(id_length, len); + return (result); +} + +QScriptValueImpl Array::method_slice(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScript::Array result(eng); + + QScriptValueImpl start = context->argument(0); + QScriptValueImpl end = context->argument(1); + + QScriptValueImpl self = context->thisObject(); + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + qsreal r2 = self.property(id_length).toNumber(); + quint32 r3 = QScriptEnginePrivate::toUint32(r2); + qint32 r4 = qint32 (start.toInteger()); + quint32 r5 = r4 < 0 ? qMax(quint32(r3 + r4), quint32(0)) : qMin(quint32(r4), r3); + quint32 k = r5; + qint32 r7 = end.isUndefined() ? r3 : qint32 (end.toInteger()); + quint32 r8 = r7 < 0 ? qMax(quint32(r3 + r7), quint32(0)) : qMin(quint32(r7), r3); + quint32 n = 0; + for (; k < r8; ++k) { + QString r11 = QScriptValueImpl(k).toString(); + QScriptValueImpl v = self.property(r11); + if (v.isValid()) + result.assign(n++, v); + } + return eng->newArray(result); +} + +QScriptValueImpl Array::method_sort(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + QScriptValueImpl comparefn = context->argument(0); + if (Instance *instance = Instance::get(self, classInfo)) { + instance->value.sort(comparefn); + return context->thisObject(); + } + return context->throwNotImplemented(QLatin1String("Array.prototype.sort")); +} + +QScriptValueImpl Array::method_splice(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + if (context->argumentCount() < 2) + return eng->undefinedValue(); + + QScriptValueImpl self = context->thisObject(); + + qsreal start = context->argument(0).toInteger(); + qsreal deleteCount = context->argument(1).toInteger(); + + QScriptValueImpl arrayCtor = eng->globalObject().property(QLatin1String("Array")); + QScriptValueImpl a = arrayCtor.construct(); + + if (Instance *instance = Instance::get(self, classInfo)) { + QVector<QScriptValueImpl> items; + for (int i = 2; i < context->argumentCount(); ++i) + items << context->argument(i); + Instance *otherInstance = Instance::get(a, classInfo); + Q_ASSERT(otherInstance); + instance->value.splice(start, deleteCount, items, otherInstance->value); + return a; + } + + return context->throwNotImplemented(QLatin1String("Array.prototype.splice")); +} + +QScriptValueImpl Array::method_unshift(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl self = context->thisObject(); + + QScriptNameIdImpl *id_length = eng->idTable()->id_length; + QScriptValueImpl r1 = self.property(id_length); + quint32 r2 = r1.isValid() ? QScriptEnginePrivate::toUint32(r1.toNumber()) : 0; + quint32 r3 = quint32 (context->argumentCount()); + quint32 k = r2; + for (; k != 0; --k) { + QScriptNameIdImpl *r6 = eng->nameId(QScriptValueImpl(k - 1).toString()); + QScriptNameIdImpl *r7 = eng->nameId(QScriptValueImpl(k + r3 - 1).toString()); + QScriptValueImpl r8 = self.property(r6); + if (r8.isValid()) + self.setProperty(r7, r8); + + else { + QScript::Member member; + QScriptValueImpl base; + + if (self.resolve(r7, &member, &base, QScriptValue::ResolveLocal, QScript::ReadWrite)) + self.removeMember(member); + } + } + + for (k = 0; k < r3; ++k) { + QScriptValueImpl r16 = context->argument(k); + QScriptNameIdImpl *r17 = eng->nameId(QScriptValueImpl(k).toString()); + self.setProperty(r17, r16); + } + QScriptValueImpl r(r2 + r3); + self.setProperty(id_length, r); + return (r); +} + +Array::Instance *Array::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaarray_p.h b/src/script/qscriptecmaarray_p.h new file mode 100644 index 0000000..7230a92 --- /dev/null +++ b/src/script/qscriptecmaarray_p.h @@ -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 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 QSCRIPTECMAARRAY_P_H +#define QSCRIPTECMAARRAY_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 "qscriptarray_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptecmacore_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Array: public Core +{ +public: + Array(QScriptEnginePrivate *engine); + virtual ~Array(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptObjectData { + public: + Instance(QScriptEnginePrivate *engine) + : value(QScript::Array(engine)) {} + virtual ~Instance() {} + + static Instance *get(const QScriptValueImpl &object, + QScriptClassInfo *klass); + + public: // attributes + QScript::Array value; + }; + + inline Instance *get(const QScriptValueImpl &object) const + { return Instance::get(object, classInfo()); } + + void newArray(QScriptValueImpl *result, + const QScript::Array &value); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_concat(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_join(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_pop(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_push(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_reverse(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_shift(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_slice(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_sort(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_splice(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_unshift(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + +private: + void initArray(QScriptValueImpl *result, const QScript::Array &value); +}; + +} } // namespace QScript::Ecma + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptecmaboolean.cpp b/src/script/qscriptecmaboolean.cpp new file mode 100644 index 0000000..08cad66 --- /dev/null +++ b/src/script/qscriptecmaboolean.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** 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 "qscriptecmaboolean_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +Boolean::Boolean(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("Boolean"), QScriptClassInfo::BooleanType) +{ + newBoolean(&publicPrototype, false); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); +} + +Boolean::~Boolean() +{ +} + +void Boolean::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + bool value; + if (context->argumentCount() > 0) + value = context->argument(0).toBoolean(); + else + value = false; + + QScriptValueImpl boolean(value); + if (!context->isCalledAsConstructor()) { + context->setReturnValue(boolean); + } else { + QScriptValueImpl &obj = context->m_thisObject; + obj.setClassInfo(classInfo()); + obj.setInternalValue(boolean); + obj.setPrototype(publicPrototype); + context->setReturnValue(obj); + } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Boolean::newBoolean(QScriptValueImpl *result, bool value) +{ + engine()->newObject(result, publicPrototype, classInfo()); + result->setInternalValue(QScriptValueImpl(value)); +} + +QScriptValueImpl Boolean::method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Boolean.prototype.toString")); + } + const QScript::IdTable *t = eng->idTable(); + bool v = self.internalValue().toBoolean(); + QScriptValueImpl result; + eng->newNameId(&result, v ? t->id_true : t->id_false); + return result; +} + +QScriptValueImpl Boolean::method_valueOf(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Boolean.prototype.valueOf")); + } + return self.internalValue(); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaboolean_p.h b/src/script/qscriptecmaboolean_p.h new file mode 100644 index 0000000..4dbaa27 --- /dev/null +++ b/src/script/qscriptecmaboolean_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 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 QSCRIPTECMABOOLEAN_P_H +#define QSCRIPTECMABOOLEAN_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 "qscriptecmacore_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SCRIPT + +namespace QScript { namespace Ecma { + +class Boolean: public Core +{ +public: + Boolean(QScriptEnginePrivate *engine); + virtual ~Boolean(); + + virtual void execute(QScriptContextPrivate *context); + + void newBoolean(QScriptValueImpl *result, bool value = false); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptecmacore.cpp b/src/script/qscriptecmacore.cpp new file mode 100644 index 0000000..ed0fce1 --- /dev/null +++ b/src/script/qscriptecmacore.cpp @@ -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 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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +Core::Core(QScriptEnginePrivate *engine, const QString &className, + QScriptClassInfo::Type type) + : m_engine(engine) +{ + m_classInfo = engine->registerClass(className, type); + this->length = 1; +} + +Core::Core(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo) + : m_engine(engine), m_classInfo(classInfo) +{ + this->length = 1; +} + +Core::~Core() +{ +} + +void Core::addPrototypeFunction(const QString &name, QScriptInternalFunctionSignature fun, + int length, const QScriptValue::PropertyFlags flags) +{ + addFunction(publicPrototype, name, fun, length, flags); +} + +void Core::addConstructorFunction(const QString &name, QScriptInternalFunctionSignature fun, + int length, const QScriptValue::PropertyFlags flags) +{ + addFunction(ctor, name, fun, length, flags); +} + +void Core::addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags) +{ + QScriptValueImpl val = engine()->createFunction(fun, length, m_classInfo, name); + object.setProperty(name, val, flags); +} + +QString Core::functionName() const +{ + return m_classInfo->name(); +} + +void Core::mark(QScriptEnginePrivate *eng, int generation) +{ + QScriptFunction::mark(eng, generation); + eng->markObject(ctor, generation); + eng->markObject(publicPrototype, generation); +} + +QScriptValueImpl Core::throwThisObjectTypeError(QScriptContextPrivate *context, + const QString &functionName) +{ + return context->throwError(QScriptContext::TypeError, + QString::fromLatin1("%0 called on incompatible object") + .arg(functionName)); +} + +} // namespace Ecma + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmacore_p.h b/src/script/qscriptecmacore_p.h new file mode 100644 index 0000000..b4c1780 --- /dev/null +++ b/src/script/qscriptecmacore_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 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 QSCRIPTECMACORE_P_H +#define QSCRIPTECMACORE_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 "qscriptfunction_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalueimplfwd_p.h" +#include "qscriptclassinfo_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Core: public QScriptFunction +{ +public: + Core(QScriptEnginePrivate *engine, const QString &className, + QScriptClassInfo::Type type); + Core(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo); + virtual ~Core(); + + inline QScriptEnginePrivate *engine() const + { return m_engine; } + + inline QScriptClassInfo *classInfo() const + { return m_classInfo; } + + void addPrototypeFunction( + const QString &name, QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration); + void addConstructorFunction( + const QString &name, QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration); + + QString functionName() const; + + virtual void mark(QScriptEnginePrivate *eng, int generation); + +public: // attributes + QScriptValueImpl ctor; + QScriptValueImpl publicPrototype; + +protected: + static QScriptValueImpl throwThisObjectTypeError( + QScriptContextPrivate *context, const QString &functionName); + +private: + void addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags); + + QScriptEnginePrivate *m_engine; + QScriptClassInfo *m_classInfo; +}; + +} } // namespace QScript::Ecma + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptecmadate.cpp b/src/script/qscriptecmadate.cpp new file mode 100644 index 0000000..cc80383 --- /dev/null +++ b/src/script/qscriptecmadate.cpp @@ -0,0 +1,1281 @@ +/**************************************************************************** +** +** 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 "qscriptecmadate_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QDateTime> +#include <QtCore/QRegExp> +#include <QtCore/QtDebug> +#include <QtCore/QLocale> +#include <QtCore/qnumeric.h> + +#include <math.h> + +#ifndef Q_WS_WIN +# include <time.h> +# include <sys/time.h> +#else +# include <windows.h> +#endif + +QT_BEGIN_NAMESPACE + +namespace QScript { + +static const qsreal HoursPerDay = 24.0; +static const qsreal MinutesPerHour = 60.0; +static const qsreal SecondsPerMinute = 60.0; +static const qsreal msPerSecond = 1000.0; +static const qsreal msPerMinute = 60000.0; +static const qsreal msPerHour = 3600000.0; +static const qsreal msPerDay = 86400000.0; + +static qsreal LocalTZA = 0.0; // initialized at startup + +static inline qsreal TimeWithinDay(qsreal t) +{ + qsreal r = ::fmod(t, msPerDay); + return (r >= 0) ? r : r + msPerDay; +} + +static inline int HourFromTime(qsreal t) +{ + int r = int(::fmod(::floor(t / msPerHour), HoursPerDay)); + return (r >= 0) ? r : r + int(HoursPerDay); +} + +static inline int MinFromTime(qsreal t) +{ + int r = int(::fmod(::floor(t / msPerMinute), MinutesPerHour)); + return (r >= 0) ? r : r + int(MinutesPerHour); +} + +static inline int SecFromTime(qsreal t) +{ + int r = int(::fmod(::floor(t / msPerSecond), SecondsPerMinute)); + return (r >= 0) ? r : r + int(SecondsPerMinute); +} + +static inline int msFromTime(qsreal t) +{ + int r = int(::fmod(t, msPerSecond)); + return (r >= 0) ? r : r + int(msPerSecond); +} + +static inline qsreal Day(qsreal t) +{ + return ::floor(t / msPerDay); +} + +static inline qsreal DaysInYear(qsreal y) +{ + if (::fmod(y, 4)) + return 365; + + else if (::fmod(y, 100)) + return 366; + + else if (::fmod(y, 400)) + return 365; + + return 366; +} + +static inline qsreal DayFromYear(qsreal y) +{ + return 365 * (y - 1970) + + ::floor((y - 1969) / 4) + - ::floor((y - 1901) / 100) + + ::floor((y - 1601) / 400); +} + +static inline qsreal TimeFromYear(qsreal y) +{ + return msPerDay * DayFromYear(y); +} + +static inline qsreal YearFromTime(qsreal t) +{ + int y = 1970; + y += (int) ::floor(t / (msPerDay * 365.2425)); + + qsreal t2 = TimeFromYear(y); + return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y; +} + +static inline bool InLeapYear(qsreal t) +{ + qsreal x = DaysInYear(YearFromTime(t)); + if (x == 365) + return 0; + + Q_ASSERT (x == 366); + return 1; +} + +static inline qsreal DayWithinYear(qsreal t) +{ + return Day(t) - DayFromYear(YearFromTime(t)); +} + +static inline qsreal MonthFromTime(qsreal t) +{ + qsreal d = DayWithinYear(t); + qsreal l = InLeapYear(t); + + if (d < 31.0) + return 0; + + else if (d < 59.0 + l) + return 1; + + else if (d < 90.0 + l) + return 2; + + else if (d < 120.0 + l) + return 3; + + else if (d < 151.0 + l) + return 4; + + else if (d < 181.0 + l) + return 5; + + else if (d < 212.0 + l) + return 6; + + else if (d < 243.0 + l) + return 7; + + else if (d < 273.0 + l) + return 8; + + else if (d < 304.0 + l) + return 9; + + else if (d < 334.0 + l) + return 10; + + else if (d < 365.0 + l) + return 11; + + return qSNaN(); // ### assert? +} + +static inline qsreal DateFromTime(qsreal t) +{ + int m = (int) QScriptEnginePrivate::toInteger(MonthFromTime(t)); + qsreal d = DayWithinYear(t); + qsreal l = InLeapYear(t); + + switch (m) { + case 0: return d + 1.0; + case 1: return d - 30.0; + case 2: return d - 58.0 - l; + case 3: return d - 89.0 - l; + case 4: return d - 119.0 - l; + case 5: return d - 150.0 - l; + case 6: return d - 180.0 - l; + case 7: return d - 211.0 - l; + case 8: return d - 242.0 - l; + case 9: return d - 272.0 - l; + case 10: return d - 303.0 - l; + case 11: return d - 333.0 - l; + } + + return qSNaN(); // ### assert +} + +static inline qsreal WeekDay(qsreal t) +{ + qsreal r = ::fmod (Day(t) + 4.0, 7.0); + return (r >= 0) ? r : r + 7.0; +} + + +static inline qsreal MakeTime(qsreal hour, qsreal min, qsreal sec, qsreal ms) +{ + return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; +} + +static inline qsreal DayFromMonth(qsreal month, qsreal leap) +{ + switch ((int) month) { + case 0: return 0; + case 1: return 31.0; + case 2: return 59.0 + leap; + case 3: return 90.0 + leap; + case 4: return 120.0 + leap; + case 5: return 151.0 + leap; + case 6: return 181.0 + leap; + case 7: return 212.0 + leap; + case 8: return 243.0 + leap; + case 9: return 273.0 + leap; + case 10: return 304.0 + leap; + case 11: return 334.0 + leap; + } + + return qSNaN(); // ### assert? +} + +static qsreal MakeDay(qsreal year, qsreal month, qsreal day) +{ + year += ::floor(month / 12.0); + + month = ::fmod(month, 12.0); + if (month < 0) + month += 12.0; + + qsreal t = TimeFromYear(year); + qsreal leap = InLeapYear(t); + + day += ::floor(t / msPerDay); + day += DayFromMonth(month, leap); + + return day - 1; +} + +static inline qsreal MakeDate(qsreal day, qsreal time) +{ + return day * msPerDay + time; +} + +static inline qsreal DaylightSavingTA(double t) +{ +#ifndef Q_WS_WIN + long int tt = (long int)(t / msPerSecond); + struct tm *tmtm = localtime((const time_t*)&tt); + if (! tmtm) + return 0; + return (tmtm->tm_isdst > 0) ? msPerHour : 0; +#else + Q_UNUSED(t); + /// ### implement me + return 0; +#endif +} + +static inline qsreal LocalTime(qsreal t) +{ + return t + LocalTZA + DaylightSavingTA(t); +} + +static inline qsreal UTC(qsreal t) +{ + return t - LocalTZA - DaylightSavingTA(t - LocalTZA); +} + +static inline qsreal currentTime() +{ +#ifndef Q_WS_WIN + struct timeval tv; + + gettimeofday(&tv, 0); + return ::floor(tv.tv_sec * msPerSecond + (tv.tv_usec / 1000.0)); +#else + SYSTEMTIME st; + GetSystemTime(&st); + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + LARGE_INTEGER li; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + return double(li.QuadPart - Q_INT64_C(116444736000000000)) / 10000.0; +#endif +} + +static inline qsreal TimeClip(qsreal t) +{ + if (! qIsFinite(t) || fabs(t) > 8.64e15) + return qSNaN(); + return QScriptEnginePrivate::toInteger(t); +} + +static inline qsreal FromDateTime(const QDateTime &dt) +{ + if (!dt.isValid()) + return qSNaN(); + QDate date = dt.date(); + QTime taim = dt.time(); + int year = date.year(); + int month = date.month() - 1; + int day = date.day(); + int hours = taim.hour(); + int mins = taim.minute(); + int secs = taim.second(); + int ms = taim.msec(); + double t = MakeDate(MakeDay(year, month, day), + MakeTime(hours, mins, secs, ms)); + if (dt.timeSpec() == Qt::LocalTime) + t = UTC(t); + return TimeClip(t); +} + +static inline qsreal ParseString(const QString &s) +{ + QDateTime dt = QDateTime::fromString(s, Qt::TextDate); + if (!dt.isValid()) + dt = QDateTime::fromString(s, Qt::ISODate); + if (!dt.isValid()) { + QStringList formats; + formats << QLatin1String("M/d/yyyy") + << QLatin1String("M/d/yyyy hh:mm") + << QLatin1String("M/d/yyyy hh:mm A") + + << QLatin1String("M/d/yyyy, hh:mm") + << QLatin1String("M/d/yyyy, hh:mm A") + + << QLatin1String("MMM d yyyy") + << QLatin1String("MMM d yyyy hh:mm") + << QLatin1String("MMM d yyyy hh:mm:ss") + << QLatin1String("MMM d yyyy, hh:mm") + << QLatin1String("MMM d yyyy, hh:mm:ss") + + << QLatin1String("MMMM d yyyy") + << QLatin1String("MMMM d yyyy hh:mm") + << QLatin1String("MMMM d yyyy hh:mm:ss") + << QLatin1String("MMMM d yyyy, hh:mm") + << QLatin1String("MMMM d yyyy, hh:mm:ss") + + << QLatin1String("MMM d, yyyy") + << QLatin1String("MMM d, yyyy hh:mm") + << QLatin1String("MMM d, yyyy hh:mm:ss") + + << QLatin1String("MMMM d, yyyy") + << QLatin1String("MMMM d, yyyy hh:mm") + << QLatin1String("MMMM d, yyyy hh:mm:ss") + + << QLatin1String("d MMM yyyy") + << QLatin1String("d MMM yyyy hh:mm") + << QLatin1String("d MMM yyyy hh:mm:ss") + << QLatin1String("d MMM yyyy, hh:mm") + << QLatin1String("d MMM yyyy, hh:mm:ss") + + << QLatin1String("d MMMM yyyy") + << QLatin1String("d MMMM yyyy hh:mm") + << QLatin1String("d MMMM yyyy hh:mm:ss") + << QLatin1String("d MMMM yyyy, hh:mm") + << QLatin1String("d MMMM yyyy, hh:mm:ss") + + << QLatin1String("d MMM, yyyy") + << QLatin1String("d MMM, yyyy hh:mm") + << QLatin1String("d MMM, yyyy hh:mm:ss") + + << QLatin1String("d MMMM, yyyy") + << QLatin1String("d MMMM, yyyy hh:mm") + << QLatin1String("d MMMM, yyyy hh:mm:ss"); + + for (int i = 0; i < formats.size(); ++i) { + dt = QDateTime::fromString(s, formats.at(i)); + if (dt.isValid()) + break; + } + } + return FromDateTime(dt); +} + +/*! + \internal + + Converts the ECMA Date value \tt (in UTC form) to QDateTime + according to \a spec. +*/ +static inline QDateTime ToDateTime(qsreal t, Qt::TimeSpec spec) +{ + if (qIsNaN(t)) + return QDateTime(); + if (spec == Qt::LocalTime) + t = LocalTime(t); + int year = int(YearFromTime(t)); + int month = int(MonthFromTime(t) + 1); + int day = int(DateFromTime(t)); + int hours = HourFromTime(t); + int mins = MinFromTime(t); + int secs = SecFromTime(t); + int ms = msFromTime(t); + return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec); +} + +static inline QString ToString(qsreal t) +{ + if (qIsNaN(t)) + return QLatin1String("Invalid Date"); + QString str = ToDateTime(t, Qt::LocalTime).toString() + QLatin1String(" GMT"); + qsreal tzoffset = LocalTZA + DaylightSavingTA(t); + if (tzoffset) { + int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60); + int mins = int(::fabs(tzoffset) / 1000 / 60) % 60; + str.append(QLatin1Char((tzoffset > 0) ? '+' : '-')); + if (hours < 10) + str.append(QLatin1Char('0')); + str.append(QString::number(hours)); + if (mins < 10) + str.append(QLatin1Char('0')); + str.append(QString::number(mins)); + } + return str; +} + +static inline QString ToUTCString(qsreal t) +{ + if (qIsNaN(t)) + return QLatin1String("Invalid Date"); + return ToDateTime(t, Qt::UTC).toString() + QLatin1String(" GMT"); +} + +static inline QString ToDateString(qsreal t) +{ + return ToDateTime(t, Qt::LocalTime).date().toString(); +} + +static inline QString ToTimeString(qsreal t) +{ + return ToDateTime(t, Qt::LocalTime).time().toString(); +} + +static inline QString ToLocaleString(qsreal t) +{ + return ToDateTime(t, Qt::LocalTime).toString(Qt::LocaleDate); +} + +static inline QString ToLocaleDateString(qsreal t) +{ + return ToDateTime(t, Qt::LocalTime).date().toString(Qt::LocaleDate); +} + +static inline QString ToLocaleTimeString(qsreal t) +{ + return ToDateTime(t, Qt::LocalTime).time().toString(Qt::LocaleDate); +} + +static qsreal getLocalTZA() +{ +#ifndef Q_WS_WIN + struct tm* t; + time_t curr; + time(&curr); + t = localtime(&curr); + time_t locl = mktime(t); + t = gmtime(&curr); + time_t globl = mktime(t); + return double(locl - globl) * 1000.0; +#else + TIME_ZONE_INFORMATION tzInfo; + GetTimeZoneInformation(&tzInfo); + return -tzInfo.Bias * 60.0 * 1000.0; +#endif +} + +namespace Ecma { + +Date::Date(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("Date"), QScriptClassInfo::DateType) +{ + LocalTZA = getLocalTZA(); + + newDate(&publicPrototype, qSNaN()); + + eng->newConstructor(&ctor, this, publicPrototype); + addConstructorFunction(QLatin1String("parse"), method_parse, 1); + addConstructorFunction(QLatin1String("UTC"), method_UTC, 7); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("toDateString"), method_toDateString, 0); + addPrototypeFunction(QLatin1String("toTimeString"), method_toTimeString, 0); + addPrototypeFunction(QLatin1String("toLocaleString"), method_toLocaleString, 0); + addPrototypeFunction(QLatin1String("toLocaleDateString"), method_toLocaleDateString, 0); + addPrototypeFunction(QLatin1String("toLocaleTimeString"), method_toLocaleTimeString, 0); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); + addPrototypeFunction(QLatin1String("getTime"), method_getTime, 0); + addPrototypeFunction(QLatin1String("getYear"), method_getYear, 0); + addPrototypeFunction(QLatin1String("getFullYear"), method_getFullYear, 0); + addPrototypeFunction(QLatin1String("getUTCFullYear"), method_getUTCFullYear, 0); + addPrototypeFunction(QLatin1String("getMonth"), method_getMonth, 0); + addPrototypeFunction(QLatin1String("getUTCMonth"), method_getUTCMonth, 0); + addPrototypeFunction(QLatin1String("getDate"), method_getDate, 0); + addPrototypeFunction(QLatin1String("getUTCDate"), method_getUTCDate, 0); + addPrototypeFunction(QLatin1String("getDay"), method_getDay, 0); + addPrototypeFunction(QLatin1String("getUTCDay"), method_getUTCDay, 0); + addPrototypeFunction(QLatin1String("getHours"), method_getHours, 0); + addPrototypeFunction(QLatin1String("getUTCHours"), method_getUTCHours, 0); + addPrototypeFunction(QLatin1String("getMinutes"), method_getMinutes, 0); + addPrototypeFunction(QLatin1String("getUTCMinutes"), method_getUTCMinutes, 0); + addPrototypeFunction(QLatin1String("getSeconds"), method_getSeconds, 0); + addPrototypeFunction(QLatin1String("getUTCSeconds"), method_getUTCSeconds, 0); + addPrototypeFunction(QLatin1String("getMilliseconds"), method_getMilliseconds, 0); + addPrototypeFunction(QLatin1String("getUTCMilliseconds"), method_getUTCMilliseconds, 0); + addPrototypeFunction(QLatin1String("getTimezoneOffset"), method_getTimezoneOffset, 0); + addPrototypeFunction(QLatin1String("setTime"), method_setTime, 1); + addPrototypeFunction(QLatin1String("setMilliseconds"), method_setMilliseconds, 1); + addPrototypeFunction(QLatin1String("setUTCMilliseconds"), method_setUTCMilliseconds, 1); + addPrototypeFunction(QLatin1String("setSeconds"), method_setSeconds, 2); + addPrototypeFunction(QLatin1String("setUTCSeconds"), method_setUTCSeconds, 2); + addPrototypeFunction(QLatin1String("setMinutes"), method_setMinutes, 3); + addPrototypeFunction(QLatin1String("setUTCMinutes"), method_setUTCMinutes, 3); + addPrototypeFunction(QLatin1String("setHours"), method_setHours, 4); + addPrototypeFunction(QLatin1String("setUTCHours"), method_setUTCHours, 4); + addPrototypeFunction(QLatin1String("setDate"), method_setDate, 1); + addPrototypeFunction(QLatin1String("setUTCDate"), method_setUTCDate, 1); + addPrototypeFunction(QLatin1String("setMonth"), method_setMonth, 2); + addPrototypeFunction(QLatin1String("setUTCMonth"), method_setUTCMonth, 2); + addPrototypeFunction(QLatin1String("setYear"), method_setYear, 1); + addPrototypeFunction(QLatin1String("setFullYear"), method_setFullYear, 3); + addPrototypeFunction(QLatin1String("setUTCFullYear"), method_setUTCFullYear, 3); + addPrototypeFunction(QLatin1String("toUTCString"), method_toUTCString, 0); + addPrototypeFunction(QLatin1String("toGMTString"), method_toUTCString, 0); +} + +Date::~Date() +{ +} + +void Date::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + if (!context->isCalledAsConstructor()) { + double t = currentTime(); + context->setReturnValue(QScriptValueImpl(engine(), ToString(t))); + } else { + // called as constructor + qsreal t; + + if (context->argumentCount() == 0) + t = currentTime(); + + else if (context->argumentCount() == 1) { + QScriptValueImpl arg = context->argument(0); + if (arg.isDate()) + arg = arg.internalValue(); + else + arg = engine()->toPrimitive(arg); + if (arg.isString()) + t = ParseString(arg.toString()); + else + t = TimeClip(arg.toNumber()); + } + + else { // context->argumentCount() > 1 + qsreal year = context->argument(0).toNumber(); + qsreal month = context->argument(1).toNumber(); + qsreal day = context->argumentCount() >= 3 ? context->argument(2).toNumber() : 1; + qsreal hours = context->argumentCount() >= 4 ? context->argument(3).toNumber() : 0; + qsreal mins = context->argumentCount() >= 5 ? context->argument(4).toNumber() : 0; + qsreal secs = context->argumentCount() >= 6 ? context->argument(5).toNumber() : 0; + qsreal ms = context->argumentCount() >= 7 ? context->argument(6).toNumber() : 0; + if (year >= 0 && year <= 99) + year += 1900; + t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); + t = TimeClip(UTC(t)); + } + + QScriptValueImpl &obj = context->m_thisObject; + obj.setClassInfo(classInfo()); + obj.setInternalValue(QScriptValueImpl(t)); + obj.setPrototype(publicPrototype); + context->setReturnValue(obj); + } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Date::newDate(QScriptValueImpl *result, qsreal t) +{ + engine()->newObject(result, publicPrototype, classInfo()); + result->setInternalValue(QScriptValueImpl(t)); +} + +void Date::newDate(QScriptValueImpl *result, const QDateTime &dt) +{ + newDate(result, FromDateTime(dt)); +} + +void Date::newDate(QScriptValueImpl *result, const QDate &d) +{ + newDate(result, QDateTime(d)); +} + +QDateTime Date::toDateTime(const QScriptValueImpl &date) const +{ + Q_ASSERT(date.classInfo() == classInfo()); + qsreal t = date.internalValue().toNumber(); + return ToDateTime(t, Qt::LocalTime); +} + +QScriptValueImpl Date::method_parse(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + return QScriptValueImpl(ParseString(context->argument(0).toString())); +} + +QScriptValueImpl Date::method_UTC(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + const int numArgs = context->argumentCount(); + if (numArgs >= 2) { + qsreal year = context->argument(0).toNumber(); + qsreal month = context->argument(1).toNumber(); + qsreal day = numArgs >= 3 ? context->argument(2).toNumber() : 1; + qsreal hours = numArgs >= 4 ? context->argument(3).toNumber() : 0; + qsreal mins = numArgs >= 5 ? context->argument(4).toNumber() : 0; + qsreal secs = numArgs >= 6 ? context->argument(5).toNumber() : 0; + qsreal ms = numArgs >= 7 ? context->argument(6).toNumber() : 0; + if (year >= 0 && year <= 99) + year += 1900; + qsreal t = MakeDate(MakeDay(year, month, day), + MakeTime(hours, mins, secs, ms)); + return QScriptValueImpl(TimeClip(t)); + } + return (eng->undefinedValue()); +} + +QScriptValueImpl Date::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toString")); +} + +QScriptValueImpl Date::method_toDateString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToDateString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toDateString")); +} + +QScriptValueImpl Date::method_toTimeString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToTimeString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toTimeString")); +} + +QScriptValueImpl Date::method_toLocaleString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToLocaleString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toLocaleString")); +} + +QScriptValueImpl Date::method_toLocaleDateString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToLocaleDateString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toLocaleDateString")); +} + +QScriptValueImpl Date::method_toLocaleTimeString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToLocaleTimeString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toLocaleTimeString")); +} + +QScriptValueImpl Date::method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) + return QScriptValueImpl(self.internalValue().toNumber()); + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.valueOf")); +} + +QScriptValueImpl Date::method_getTime(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) + return QScriptValueImpl(self.internalValue().toNumber()); + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getTime")); +} + +QScriptValueImpl Date::method_getYear(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = YearFromTime(LocalTime(t)) - 1900; + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getYear")); +} + +QScriptValueImpl Date::method_getFullYear(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = YearFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getFullYear")); +} + +QScriptValueImpl Date::method_getUTCFullYear(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = YearFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCFullYear")); +} + +QScriptValueImpl Date::method_getMonth(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = MonthFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getMonth")); +} + +QScriptValueImpl Date::method_getUTCMonth(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = MonthFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCMonth")); +} + +QScriptValueImpl Date::method_getDate(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = DateFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getDate")); +} + +QScriptValueImpl Date::method_getUTCDate(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = DateFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCDate")); +} + +QScriptValueImpl Date::method_getDay(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = WeekDay(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getDay")); +} + +QScriptValueImpl Date::method_getUTCDay(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = WeekDay(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCDay")); +} + +QScriptValueImpl Date::method_getHours(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = HourFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getHours")); +} + +QScriptValueImpl Date::method_getUTCHours(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = HourFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCHours")); +} + +QScriptValueImpl Date::method_getMinutes(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = MinFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getMinutes")); +} + +QScriptValueImpl Date::method_getUTCMinutes(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = MinFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCMinutes")); +} + +QScriptValueImpl Date::method_getSeconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = SecFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getSeconds")); +} + +QScriptValueImpl Date::method_getUTCSeconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = SecFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCSeconds")); +} + +QScriptValueImpl Date::method_getMilliseconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = msFromTime(LocalTime(t)); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getMilliseconds")); +} + +QScriptValueImpl Date::method_getUTCMilliseconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = msFromTime(t); + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getUTCMilliseconds")); +} + +QScriptValueImpl Date::method_getTimezoneOffset(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (! qIsNaN(t)) + t = (t - LocalTime(t)) / msPerMinute; + return QScriptValueImpl(t); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.getTimezoneOffset")); +} + +QScriptValueImpl Date::method_setTime(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = TimeClip(context->argument(0).toNumber()); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setTime")); +} + +QScriptValueImpl Date::method_setMilliseconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal ms = context->argument(0).toNumber(); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setMilliseconds")); +} + +QScriptValueImpl Date::method_setUTCMilliseconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal ms = context->argument(0).toNumber(); + t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCMilliseconds")); +} + +QScriptValueImpl Date::method_setSeconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal sec = context->argument(0).toNumber(); + qsreal ms = (context->argumentCount() < 2) ? msFromTime(t) : context->argument(1).toNumber(); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setSeconds")); +} + +QScriptValueImpl Date::method_setUTCSeconds(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal sec = context->argument(0).toNumber(); + qsreal ms = (context->argumentCount() < 2) ? msFromTime(t) : context->argument(1).toNumber(); + t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCSeconds")); +} + +QScriptValueImpl Date::method_setMinutes(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal min = context->argument(0).toNumber(); + qsreal sec = (context->argumentCount() < 2) ? SecFromTime(t) : context->argument(1).toNumber(); + qsreal ms = (context->argumentCount() < 3) ? msFromTime(t) : context->argument(2).toNumber(); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setMinutes")); +} + +QScriptValueImpl Date::method_setUTCMinutes(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal min = context->argument(0).toNumber(); + qsreal sec = (context->argumentCount() < 2) ? SecFromTime(t) : context->argument(1).toNumber(); + qsreal ms = (context->argumentCount() < 3) ? msFromTime(t) : context->argument(2).toNumber(); + t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCMinutes")); +} + +QScriptValueImpl Date::method_setHours(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal hour = context->argument(0).toNumber(); + qsreal min = (context->argumentCount() < 2) ? MinFromTime(t) : context->argument(1).toNumber(); + qsreal sec = (context->argumentCount() < 3) ? SecFromTime(t) : context->argument(2).toNumber(); + qsreal ms = (context->argumentCount() < 4) ? msFromTime(t) : context->argument(3).toNumber(); + t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setHours")); +} + +QScriptValueImpl Date::method_setUTCHours(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal hour = context->argument(0).toNumber(); + qsreal min = (context->argumentCount() < 2) ? MinFromTime(t) : context->argument(1).toNumber(); + qsreal sec = (context->argumentCount() < 3) ? SecFromTime(t) : context->argument(2).toNumber(); + qsreal ms = (context->argumentCount() < 4) ? msFromTime(t) : context->argument(3).toNumber(); + t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCHours")); +} + +QScriptValueImpl Date::method_setDate(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal date = context->argument(0).toNumber(); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setDate")); +} + +QScriptValueImpl Date::method_setUTCDate(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal date = context->argument(0).toNumber(); + t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCDate")); +} + +QScriptValueImpl Date::method_setMonth(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal month = context->argument(0).toNumber(); + qsreal date = (context->argumentCount() < 2) ? DateFromTime(t) : context->argument(1).toNumber(); + t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setMonth")); +} + +QScriptValueImpl Date::method_setUTCMonth(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal month = context->argument(0).toNumber(); + qsreal date = (context->argumentCount() < 2) ? DateFromTime(t) : context->argument(1).toNumber(); + t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCMonth")); +} + +QScriptValueImpl Date::method_setFullYear(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = LocalTime(self.internalValue().toNumber()); + qsreal year = context->argument(0).toNumber(); + qsreal month = (context->argumentCount() < 2) ? MonthFromTime(t) : context->argument(1).toNumber(); + qsreal date = (context->argumentCount() < 3) ? DateFromTime(t) : context->argument(2).toNumber(); + t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setFullYear")); +} + +QScriptValueImpl Date::method_setUTCFullYear(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + qsreal year = context->argument(0).toNumber(); + qsreal month = (context->argumentCount() < 2) ? MonthFromTime(t) : context->argument(1).toNumber(); + qsreal date = (context->argumentCount() < 3) ? DateFromTime(t) : context->argument(2).toNumber(); + t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))); + QScriptValueImpl r(t); + self.setInternalValue(r); + return r; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setUTCFullYear")); +} + +QScriptValueImpl Date::method_setYear(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + Q_UNUSED(eng); + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + if (qIsNaN(t)) + t = 0; + else + t = LocalTime(t); + qsreal year = context->argument(0).toNumber(); + qsreal r; + if (qIsNaN(year)) { + r = qSNaN(); + } else { + if ((eng->toInteger(year) >= 0) && (eng->toInteger(year) <= 99)) + year += 1900; + r = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + r = UTC(MakeDate(r, TimeWithinDay(t))); + r = TimeClip(r); + } + QScriptValueImpl v = QScriptValueImpl(r); + self.setInternalValue(v); + return v; + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.setYear")); +} + +QScriptValueImpl Date::method_toUTCString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() == classInfo) { + qsreal t = self.internalValue().toNumber(); + return QScriptValueImpl(eng, ToUTCString(t)); + } + return throwThisObjectTypeError( + context, QLatin1String("Date.prototype.toUTCString")); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmadate_p.h b/src/script/qscriptecmadate_p.h new file mode 100644 index 0000000..4d705a5 --- /dev/null +++ b/src/script/qscriptecmadate_p.h @@ -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 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 QSCRIPTECMADATE_P_H +#define QSCRIPTECMADATE_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +class QDate; +class QDateTime; + +namespace QScript { namespace Ecma { + +class Date: public Core +{ +public: + Date(QScriptEnginePrivate *engine); + virtual ~Date(); + + virtual void execute(QScriptContextPrivate *context); + + void newDate(QScriptValueImpl *result, double t); + void newDate(QScriptValueImpl *result, const QDateTime &dt); + void newDate(QScriptValueImpl *result, const QDate &d); + + QDateTime toDateTime(const QScriptValueImpl &date) const; + +protected: + static QScriptValueImpl method_MakeTime(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_MakeDate(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_TimeClip(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_parse(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_UTC(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toDateString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toTimeString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleDateString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleTimeString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getTime(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getFullYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCFullYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getMonth(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCMonth(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getDate(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCDate(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getDay(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCDay(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getHours(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCHours(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getMinutes(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCMinutes(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getSeconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCSeconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getMilliseconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getUTCMilliseconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_getTimezoneOffset(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setTime(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setMilliseconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCMilliseconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setSeconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCSeconds(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setMinutes(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCMinutes(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setHours(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCHours(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setDate(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCDate(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setMonth(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCMonth(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setFullYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_setUTCFullYear(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toUTCString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptecmaerror.cpp b/src/script/qscriptecmaerror.cpp new file mode 100644 index 0000000..fc39bf9 --- /dev/null +++ b/src/script/qscriptecmaerror.cpp @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** 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 "qscriptecmaerror_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +static QString getMessage(QScriptContextPrivate *context) +{ + if (context->argumentCount() > 0) + return context->argument(0).toString(); + return QString(); +} + +static void setDebugInformation(QScriptValueImpl *error, QScriptContextPrivate *context) +{ + Q_ASSERT(context->previous); + context->previous->setDebugInformation(error); +} + +static QScriptValueImpl method_EvalError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newEvalError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +static QScriptValueImpl method_RangeError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newRangeError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +static QScriptValueImpl method_ReferenceError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newReferenceError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +static QScriptValueImpl method_SyntaxError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newSyntaxError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +static QScriptValueImpl method_TypeError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newTypeError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +static QScriptValueImpl method_UriError(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->isCalledAsConstructor()) + result = context->thisObject(); + eng->errorConstructor->newURIError(&result, getMessage(context)); + setDebugInformation(&result, context); + return result; +} + +Error::Error(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("Error"), QScriptClassInfo::ErrorType) +{ + eng->newFunction(&ctor, this); + newErrorPrototype(&publicPrototype, QScriptValueImpl(), ctor, QLatin1String("Error")); + addPrototypeFunction(QLatin1String("backtrace"), method_backtrace, 0); + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + + // native errors + + evalErrorCtor = eng->createFunction(method_EvalError, 3, + classInfo(), QLatin1String("EvalError")); + rangeErrorCtor = eng->createFunction(method_RangeError, 3, + classInfo(), QLatin1String("RangeError")); + referenceErrorCtor = eng->createFunction(method_ReferenceError, 3, + classInfo(), QLatin1String("ReferenceError")); + syntaxErrorCtor = eng->createFunction(method_SyntaxError, 3, + classInfo(), QLatin1String("SyntaxError")); + typeErrorCtor = eng->createFunction(method_TypeError, 3, + classInfo(), QLatin1String("TypeError")); + uriErrorCtor = eng->createFunction(method_UriError, 3, + classInfo(), QLatin1String("URIError")); + + newErrorPrototype(&evalErrorPrototype, publicPrototype, + evalErrorCtor, QLatin1String("EvalError")); + newErrorPrototype(&rangeErrorPrototype, publicPrototype, + rangeErrorCtor, QLatin1String("RangeError")); + newErrorPrototype(&referenceErrorPrototype, publicPrototype, + referenceErrorCtor, QLatin1String("ReferenceError")); + newErrorPrototype(&syntaxErrorPrototype, publicPrototype, + syntaxErrorCtor, QLatin1String("SyntaxError")); + newErrorPrototype(&typeErrorPrototype, publicPrototype, + typeErrorCtor, QLatin1String("TypeError")); + newErrorPrototype(&uriErrorPrototype, publicPrototype, + uriErrorCtor, QLatin1String("URIError")); +} + +Error::~Error() +{ +} + +void Error::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + QString message = QString(); + + if (context->argumentCount() > 0) + message = context->argument(0).toString(); + + QScriptValueImpl result; + newError(&result, publicPrototype, message); + + setDebugInformation(&result, context); + + context->setReturnValue(result); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Error::mark(QScriptEnginePrivate *eng, int generation) +{ + Core::mark(eng, generation); + + eng->markObject(evalErrorCtor, generation); + eng->markObject(rangeErrorCtor, generation); + eng->markObject(referenceErrorCtor, generation); + eng->markObject(syntaxErrorCtor, generation); + eng->markObject(typeErrorCtor, generation); + eng->markObject(uriErrorCtor, generation); + + eng->markObject(evalErrorPrototype, generation); + eng->markObject(rangeErrorPrototype, generation); + eng->markObject(referenceErrorPrototype, generation); + eng->markObject(syntaxErrorPrototype, generation); + eng->markObject(typeErrorPrototype, generation); + eng->markObject(uriErrorPrototype, generation); +} + +void Error::newError(QScriptValueImpl *result, const QString &message) +{ + newError(result, publicPrototype, message); +} + +void Error::newEvalError(QScriptValueImpl *result, const QString &message) +{ + newError(result, evalErrorPrototype, message); +} + +void Error::newRangeError(QScriptValueImpl *result, const QString &message) +{ + newError(result, rangeErrorPrototype, message); +} + +void Error::newReferenceError(QScriptValueImpl *result, const QString &message) +{ + newError(result, referenceErrorPrototype, message); +} + +void Error::newSyntaxError(QScriptValueImpl *result, const QString &message) +{ + newError(result, syntaxErrorPrototype, message); +} + +void Error::newTypeError(QScriptValueImpl *result, const QString &message) +{ + newError(result, typeErrorPrototype, message); +} + +void Error::newURIError(QScriptValueImpl *result, const QString &message) +{ + newError(result, uriErrorPrototype, message); +} + +void Error::newError(QScriptValueImpl *result, const QScriptValueImpl &proto, + const QString &message) +{ + QScriptEnginePrivate *eng_p = engine(); + + if (!result->isValid()) + eng_p->newObject(result, proto, classInfo()); + else + result->setClassInfo(classInfo()); + result->setProperty(QLatin1String("message"), QScriptValueImpl(eng_p, message)); +} + +void Error::newErrorPrototype(QScriptValueImpl *result, const QScriptValueImpl &proto, + QScriptValueImpl &ztor, const QString &name) +{ + newError(result, proto); + result->setProperty(QLatin1String("name"), QScriptValueImpl(engine(), name)); + result->setProperty(QLatin1String("constructor"), ztor, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + ztor.setProperty(QLatin1String("prototype"), *result, + QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration); +} + +bool Error::isEvalError(const QScriptValueImpl &value) const +{ + return value.instanceOf(evalErrorPrototype); +} + +bool Error::isRangeError(const QScriptValueImpl &value) const +{ + return value.instanceOf(rangeErrorPrototype); +} + +bool Error::isReferenceError(const QScriptValueImpl &value) const +{ + return value.instanceOf(referenceErrorPrototype); +} + +bool Error::isSyntaxError(const QScriptValueImpl &value) const +{ + return value.instanceOf(syntaxErrorPrototype); +} + +bool Error::isTypeError(const QScriptValueImpl &value) const +{ + return value.instanceOf(typeErrorPrototype); +} + +bool Error::isURIError(const QScriptValueImpl &value) const +{ + return value.instanceOf(uriErrorPrototype); +} + +QStringList Error::backtrace(const QScriptValueImpl &error) +{ + QStringList result; + QScriptValueImpl stack = error.property(QLatin1String("stack")); + int frameCount = stack.property(QLatin1String("length")).toInt32(); + for (int i = 0; i < frameCount; ++i) { + QScriptValueImpl o = stack.property(i); + QScriptValueImpl frame = o.property(QLatin1String("frame")); + QString s; + QString functionName = o.property(QLatin1String("functionName")).toString(); + if (functionName.isEmpty()) { + if (i == frameCount-1) + s += QLatin1String("<global>"); + else + s += QLatin1String("<anonymous>"); + } else { + s += functionName; + } + s += QLatin1String("("); + QScriptValueImpl arguments = frame.property(QLatin1String("arguments")); + if (arguments.isObject()) { + int argCount = arguments.property(QLatin1String("length")).toInt32(); + for (int j = 0; j < argCount; ++j) { + if (j > 0) + s += QLatin1String(","); + s += arguments.property(j).toString(); + } + } + s += QLatin1String(")@") + o.property(QLatin1String("fileName")).toString() + + QLatin1String(":") + o.property(QLatin1String("lineNumber")).toString(); + result.append(s); + } + return result; +} + +QScriptValueImpl Error::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl name = context->thisObject().property(QLatin1String("name"), + QScriptValue::ResolvePrototype); + QScriptValueImpl message = context->thisObject().property(QLatin1String("message"), + QScriptValue::ResolvePrototype); + QString result = QLatin1String(""); + if (name.isValid()) + result = name.toString(); + if (message.isValid()) { + QString str = message.toString(); + if (!str.isEmpty()) { + if (!result.isEmpty()) + result += QLatin1String(": "); + result += str; + } + } + return (QScriptValueImpl(eng, result)); +} + +QScriptValueImpl Error::method_backtrace(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl self = context->thisObject(); + return eng->arrayFromStringList(backtrace(self)); +} + +} } // namespace QSA::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaerror_p.h b/src/script/qscriptecmaerror_p.h new file mode 100644 index 0000000..dddcb3e --- /dev/null +++ b/src/script/qscriptecmaerror_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 QSCRIPTECMAERROR_P_H +#define QSCRIPTECMAERROR_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Error: public Core +{ +public: + Error(QScriptEnginePrivate *engine); + virtual ~Error(); + + virtual void execute(QScriptContextPrivate *context); + + virtual void mark(QScriptEnginePrivate *eng, int generation); + + void newError(QScriptValueImpl *result, const QString &message = QString()); + void newEvalError(QScriptValueImpl *result, const QString &message = QString()); + void newRangeError(QScriptValueImpl *result, const QString &message = QString()); + void newReferenceError(QScriptValueImpl *result, const QString &message = QString()); + void newSyntaxError(QScriptValueImpl *result, const QString &message = QString()); + void newTypeError(QScriptValueImpl *result, const QString &message = QString()); + void newURIError(QScriptValueImpl *result, const QString &message = QString()); + + bool isEvalError(const QScriptValueImpl &value) const; + bool isRangeError(const QScriptValueImpl &value) const; + bool isReferenceError(const QScriptValueImpl &value) const; + bool isSyntaxError(const QScriptValueImpl &value) const; + bool isTypeError(const QScriptValueImpl &value) const; + bool isURIError(const QScriptValueImpl &value) const; + + static QStringList backtrace(const QScriptValueImpl &error); + + QScriptValueImpl evalErrorCtor; + QScriptValueImpl rangeErrorCtor; + QScriptValueImpl referenceErrorCtor; + QScriptValueImpl syntaxErrorCtor; + QScriptValueImpl typeErrorCtor; + QScriptValueImpl uriErrorCtor; + + QScriptValueImpl evalErrorPrototype; + QScriptValueImpl rangeErrorPrototype; + QScriptValueImpl referenceErrorPrototype; + QScriptValueImpl syntaxErrorPrototype; + QScriptValueImpl typeErrorPrototype; + QScriptValueImpl uriErrorPrototype; + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_backtrace(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + +private: + void newError(QScriptValueImpl *result, const QScriptValueImpl &proto, + const QString &message = QString()); + void newErrorPrototype(QScriptValueImpl *result, const QScriptValueImpl &proto, + QScriptValueImpl &ztor, const QString &name); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTECMAERROR_P_H diff --git a/src/script/qscriptecmafunction.cpp b/src/script/qscriptecmafunction.cpp new file mode 100644 index 0000000..ec45ae4 --- /dev/null +++ b/src/script/qscriptecmafunction.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** 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 "qscriptecmafunction_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +#ifndef QT_NO_QOBJECT +# include "qscriptextqobject_p.h" +# include <QtCore/QMetaMethod> +#endif + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class FunctionClassData: public QScriptClassData +{ + QScriptClassInfo *m_classInfo; + +public: + FunctionClassData(QScriptClassInfo *classInfo); + virtual ~FunctionClassData(); + + inline QScriptClassInfo *classInfo() const + { return m_classInfo; } + + virtual bool resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &obj, const Member &m, + QScriptValueImpl *out_value); + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value); + virtual void mark(const QScriptValueImpl &object, int generation); +}; + +FunctionClassData::FunctionClassData(QScriptClassInfo *classInfo) + : m_classInfo(classInfo) +{ +} + +FunctionClassData::~FunctionClassData() +{ +} + +bool FunctionClassData::resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode /*access*/) +{ + if (object.classInfo() != classInfo()) + return false; + + QScriptEnginePrivate *eng = object.engine(); + + if ((nameId == eng->idTable()->id_length) + || (nameId == eng->idTable()->id_arguments)) { + member->native(nameId, /*id=*/ 0, + QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration); + *base = object; + return true; + } + + return false; +} + +bool FunctionClassData::get(const QScriptValueImpl &object, const Member &member, + QScriptValueImpl *result) +{ + if (object.classInfo() != classInfo()) + return false; + + QScriptEnginePrivate *eng = object.engine(); + if (! member.isNativeProperty()) + return false; + + if (member.nameId() == eng->idTable()->id_length) { + *result = QScriptValueImpl(object.toFunction()->length); + return true; + } else if (member.nameId() == eng->idTable()->id_arguments) { + *result = eng->nullValue(); + return true; + } + + return false; +} + +bool FunctionClassData::put(QScriptValueImpl *, const QScript::Member &, + const QScriptValueImpl &) +{ + return false; +} + +void FunctionClassData::mark(const QScriptValueImpl &object, int generation) +{ + if (object.classInfo() != classInfo()) + return; + QScriptFunction *fun = object.toFunction(); + QScriptEnginePrivate *eng = object.engine(); + fun->mark(eng, generation); +} + +Function::Function(QScriptEnginePrivate *eng, QScriptClassInfo *classInfo): + Core(eng, classInfo) +{ + publicPrototype = eng->createFunction(method_void, 0, classInfo); // public prototype +} + +Function::~Function() +{ +} + +void Function::initialize() +{ + QScriptEnginePrivate *eng = engine(); + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 1); + addPrototypeFunction(QLatin1String("apply"), method_apply, 2); + addPrototypeFunction(QLatin1String("call"), method_call, 1); + addPrototypeFunction(QLatin1String("connect"), method_connect, 1); + addPrototypeFunction(QLatin1String("disconnect"), method_disconnect, 1); + + classInfo()->setData(new FunctionClassData(classInfo())); +} + +void Function::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + int lineNumber = context->currentLine; + QString contents = buildFunction(context); + engine()->evaluate(context, contents, lineNumber); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +QString Function::buildFunction(QScriptContextPrivate *context) +{ + int argc = context->argumentCount(); + + QString code; + code += QLatin1String("function("); + + // the formals + for (int i = 0; i < argc - 1; ++i) { + if (i != 0) + code += QLatin1String(","); + + code += context->argument(i).toString(); + } + + code += QLatin1String("){"); + + // the function body + if (argc != 0) + code += context->argument(argc - 1).toString(); + + code += QLatin1String("\n}"); + + return code; +} + +void Function::newFunction(QScriptValueImpl *result, QScriptFunction *foo) +{ + engine()->newFunction(result, foo); +} + +QScriptValueImpl Function::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl self = context->thisObject(); + if (QScriptFunction *foo = self.toFunction()) { + QString code = foo->toString(context); + return QScriptValueImpl(eng, code); + } + + return throwThisObjectTypeError( + context, QLatin1String("Function.prototype.toString")); +} + +QScriptValueImpl Function::method_call(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + if (! context->thisObject().isFunction()) { + return throwThisObjectTypeError( + context, QLatin1String("Function.prototype.call")); + } + + QScriptValueImpl thisObject = eng->toObject(context->argument(0)); + if (! (thisObject.isValid () && thisObject.isObject())) + thisObject = eng->globalObject(); + + QScriptValueImplList args; + for (int i = 1; i < context->argumentCount(); ++i) + args << context->argument(i); + + return context->thisObject().call(thisObject, args); +} + +QScriptValueImpl Function::method_apply(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + if (! context->thisObject().isFunction()) { + return throwThisObjectTypeError( + context, QLatin1String("Function.prototype.apply")); + } + + QScriptValueImpl thisObject = eng->toObject(context->argument(0)); + if (! (thisObject.isValid () && thisObject.isObject())) + thisObject = eng->globalObject(); + + QScriptValueImplList args; + QScriptValueImpl undefined = eng->undefinedValue(); + + QScriptValueImpl arg = context->argument(1); + + if (Ecma::Array::Instance *arr = eng->arrayConstructor->get(arg)) { + QScript::Array actuals = arr->value; + + for (quint32 i = 0; i < actuals.count(); ++i) { + QScriptValueImpl a = actuals.at(i); + if (! a.isValid()) + args << undefined; + else + args << a; + } + } else if (arg.classInfo() == eng->m_class_arguments) { + QScript::ArgumentsObjectData *arguments; + arguments = static_cast<QScript::ArgumentsObjectData*> (arg.objectData()); + QScriptObject *activation = arguments->activation.objectValue(); + for (uint i = 0; i < arguments->length; ++i) + args << activation->m_values[i]; + } else if (!(arg.isUndefined() || arg.isNull())) { + return context->throwError(QScriptContext::TypeError, + QLatin1String("Function.prototype.apply: second argument is not an array")); + } + + return context->thisObject().call(thisObject, args); +} + +QScriptValueImpl Function::method_void(QScriptContextPrivate *, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + return eng->undefinedValue(); +} + +QScriptValueImpl Function::method_disconnect(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ +#ifndef QT_NO_QOBJECT + if (context->argumentCount() == 0) { + return context->throwError( + QLatin1String("Function.prototype.disconnect: no arguments given")); + } + + QScriptValueImpl self = context->thisObject(); + QScriptFunction *fun = self.toFunction(); + if ((fun == 0) || (fun->type() != QScriptFunction::Qt)) { + return context->throwError( + QScriptContext::TypeError, + QLatin1String("Function.prototype.disconnect: this object is not a signal")); + } + + QtFunction *qtSignal = static_cast<QtFunction*>(fun); + + const QMetaObject *meta = qtSignal->metaObject(); + if (!meta) { + return context->throwError( + QScriptContext::TypeError, + QString::fromLatin1("Function.prototype.disconnect: cannot disconnect from deleted QObject")); + } + + QMetaMethod sig = meta->method(qtSignal->initialIndex()); + if (sig.methodType() != QMetaMethod::Signal) { + return context->throwError(QScriptContext::TypeError, + QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal") + .arg(QLatin1String(qtSignal->metaObject()->className())) + .arg(QLatin1String(sig.signature()))); + } + + QScriptValueImpl receiver; + QScriptValueImpl slot; + QScriptValueImpl arg0 = context->argument(0); + if (context->argumentCount() < 2) { + receiver = QScriptValueImpl(); + slot = arg0; + } else { + receiver = arg0; + QScriptValueImpl arg1 = context->argument(1); + if (arg1.isFunction()) + slot = arg1; + else + slot = receiver.property(arg1.toString(), QScriptValue::ResolvePrototype); + } + + if (!slot.isFunction()) { + return context->throwError( + QScriptContext::TypeError, + QLatin1String("Function.prototype.disconnect: target is not a function")); + } + + bool ok = eng->scriptDisconnect(self, receiver, slot); + if (!ok) { + return context->throwError( + QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1") + .arg(QLatin1String(qtSignal->metaObject()->className())) + .arg(QLatin1String(sig.signature()))); + } + return eng->undefinedValue(); +#else + Q_UNUSED(eng); + return context->throwError(QScriptContext::TypeError, + QLatin1String("Function.prototype.disconnect")); +#endif // QT_NO_QOBJECT +} + +QScriptValueImpl Function::method_connect(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + Q_UNUSED(classInfo); + +#ifndef QT_NO_QOBJECT + if (context->argumentCount() == 0) { + return context->throwError( + QLatin1String("Function.prototype.connect: no arguments given")); + } + + QScriptValueImpl self = context->thisObject(); + QScriptFunction *fun = self.toFunction(); + if ((fun == 0) || (fun->type() != QScriptFunction::Qt)) { + return context->throwError( + QScriptContext::TypeError, + QLatin1String("Function.prototype.connect: this object is not a signal")); + } + + QtFunction *qtSignal = static_cast<QtFunction*>(fun); + + const QMetaObject *meta = qtSignal->metaObject(); + if (!meta) { + return context->throwError( + QScriptContext::TypeError, + QString::fromLatin1("Function.prototype.connect: cannot connect to deleted QObject")); + } + + QMetaMethod sig = meta->method(qtSignal->initialIndex()); + if (sig.methodType() != QMetaMethod::Signal) { + return context->throwError(QScriptContext::TypeError, + QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal") + .arg(QLatin1String(qtSignal->metaObject()->className())) + .arg(QLatin1String(sig.signature()))); + } + + { + QList<int> overloads = qtSignal->overloadedIndexes(); + if (!overloads.isEmpty()) { + overloads.append(qtSignal->initialIndex()); + QByteArray signature = sig.signature(); + QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n") + .arg(QLatin1String(qtSignal->metaObject()->className())) + .arg(QLatin1String(signature.left(signature.indexOf('(')))); + for (int i = 0; i < overloads.size(); ++i) { + QMetaMethod mtd = meta->method(overloads.at(i)); + message.append(QString::fromLatin1(" %0\n").arg(QString::fromLatin1(mtd.signature()))); + } + message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload") + .arg(QLatin1String(signature))); + return context->throwError(message); + } + } + + QScriptValueImpl receiver; + QScriptValueImpl slot; + QScriptValueImpl arg0 = context->argument(0); + if (context->argumentCount() < 2) { + receiver = QScriptValueImpl(); + slot = arg0; + } else { + receiver = arg0; + QScriptValueImpl arg1 = context->argument(1); + if (arg1.isFunction()) + slot = arg1; + else + slot = receiver.property(arg1.toString(), QScriptValue::ResolvePrototype); + } + + if (!slot.isFunction()) { + return context->throwError( + QScriptContext::TypeError, + QLatin1String("Function.prototype.connect: target is not a function")); + } + + bool ok = eng->scriptConnect(self, receiver, slot); + if (!ok) { + return context->throwError( + QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1") + .arg(QLatin1String(qtSignal->metaObject()->className())) + .arg(QLatin1String(sig.signature()))); + } + return eng->undefinedValue(); +#else + Q_UNUSED(eng); + Q_UNUSED(classInfo); + return context->throwError(QScriptContext::TypeError, + QLatin1String("Function.prototype.connect")); +#endif // QT_NO_QOBJECT +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmafunction_p.h b/src/script/qscriptecmafunction_p.h new file mode 100644 index 0000000..23b56f9 --- /dev/null +++ b/src/script/qscriptecmafunction_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 QSCRIPTECMAFUNCTION_P_H +#define QSCRIPTECMAFUNCTION_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Function: public Core +{ +public: + Function(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo); + virtual ~Function(); + + void initialize(); + + virtual void execute(QScriptContextPrivate *context); + + void newFunction(QScriptValueImpl *result, QScriptFunction *foo); + +protected: + QString buildFunction(QScriptContextPrivate *context); + + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_apply(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_call(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_void(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_disconnect(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_connect(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptecmaglobal.cpp b/src/script/qscriptecmaglobal.cpp new file mode 100644 index 0000000..da7ab9e --- /dev/null +++ b/src/script/qscriptecmaglobal.cpp @@ -0,0 +1,572 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// for strtoll +#include <qplatformdefs.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptecmaglobal_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QVarLengthArray> +#include <QtCore/qnumeric.h> + +QT_BEGIN_NAMESPACE + +extern double qstrtod(const char *s00, char const **se, bool *ok); + +namespace QScript { + +extern qsreal integerFromString(const QString &str, int radix); + +static inline char toHex(char c) +{ + static const char hexnumbers[] = "0123456789ABCDEF"; + return hexnumbers[c & 0xf]; +} + +static int fromHex(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + return -1; +} + +static QByteArray escape(const QString &input) +{ + QVarLengthArray<char> output; + output.reserve(input.size() * 3); + const int length = input.length(); + for (int i = 0; i < length; ++i) { + ushort uc = input.at(i).unicode(); + if (uc < 0x100) { + if ( (uc > 0x60 && uc < 0x7B) + || (uc > 0x3F && uc < 0x5B) + || (uc > 0x2C && uc < 0x3A) + || (uc == 0x2A) + || (uc == 0x2B) + || (uc == 0x5F)) { + output.append(char(uc)); + } else { + output.append('%'); + output.append(toHex(uc >> 4)); + output.append(toHex(uc)); + } + } else { + output.append('%'); + output.append('u'); + output.append(toHex(uc >> 12)); + output.append(toHex(uc >> 8)); + output.append(toHex(uc >> 4)); + output.append(toHex(uc)); + } + } + return QByteArray(output.constData(), output.size()); +} + +static QString unescape(const QByteArray &input) +{ + QString result; + int i = 0; + const int length = input.length(); + while (i < length) { + char c = input.at(i++); + if ((c == '%') && (i + 1 < length)) { + char a = input.at(i); + if ((a == 'u') && (i + 4 < length)) { + int d3 = fromHex(input.at(i+1)); + int d2 = fromHex(input.at(i+2)); + int d1 = fromHex(input.at(i+3)); + int d0 = fromHex(input.at(i+4)); + if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) { + ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0); + result.append(QChar(uc)); + i += 5; + } else { + result.append(QLatin1Char(c)); + } + } else { + int d1 = fromHex(a); + int d0 = fromHex(input.at(i+1)); + if ((d1 != -1) && (d0 != -1)) { + c = (d1 << 4) | d0; + i += 2; + } + result.append(QLatin1Char(c)); + } + } else { + result.append(QLatin1Char(c)); + } + } + return result; +} + +static const char uriReserved[] = ";/?:@&=+$,"; +static const char uriUnescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; + +static QString encode(const QString &input, const QString &unescapedSet, bool *ok) +{ + QString output; + const int length = input.length(); + int i = 0; + while (i < length) { + const QChar c = input.at(i); + if (!unescapedSet.contains(c)) { + ushort uc = c.unicode(); + if ((uc >= 0xDC00) && (uc <= 0xDFFF)) { + // URIError + break; + } + if (!((uc < 0xD800) || (uc > 0xDBFF))) { + ++i; + if (i == length) { + // URIError + break; + } + const ushort uc2 = input.at(i).unicode(); + if ((uc < 0xDC00) || (uc > 0xDFFF)) { + // URIError + break; + } + uc = ((uc - 0xD800) * 0x400) + (uc2 - 0xDC00) + 0x10000; + } + QString tmp(1, QChar(uc)); + QByteArray octets = tmp.toUtf8(); + for (int j = 0; j < octets.length(); ++j) { + output.append(QLatin1Char('%')); + output.append(QLatin1Char(toHex(octets.at(j) >> 4))); + output.append(QLatin1Char(toHex(octets.at(j)))); + } + } else { + output.append(c); + } + ++i; + } + *ok = (i == length); + return output; +} + +static QString decode(const QString &input, const QString &reservedSet, bool *ok) +{ + QString output; + const int length = input.length(); + int i = 0; + const QChar percent = QLatin1Char('%'); + while (i < length) { + const QChar c = input.at(i); + if (c == percent) { + int start = i; + if (i + 2 >= length) { + // URIError + break; + } + int d1 = fromHex(input.at(i+1).toLatin1()); + int d0 = fromHex(input.at(i+2).toLatin1()); + if ((d1 == -1) || (d0 == -1)) { + // URIError + break; + } + int b = (d1 << 4) | d0; + i += 2; + if (b & 0x80) { + int n = -1; + while ((b << ++n) & 0x80) ; + if ((n == 1) || (n > 4)) { + // URIError + break; + } + QByteArray octets; + octets.append(b); + if (i + (3 * (n - 1)) >= length) { + // URIError + break; + } + for (int j = 1; j < n; ++j) { + ++i; + if (input.at(i) != percent) { + // URIError + break; + } + d1 = fromHex(input.at(i+1).toLatin1()); + d0 = fromHex(input.at(i+2).toLatin1()); + if ((d1 == -1) || (d0 == -1)) { + // URIError + break; + } + b = (d1 << 4) | d0; + if ((b & 0xC0) != 0x80) { + // URIError + break; + } + i += 2; + octets.append(b); + } + QString tmp = QString::fromUtf8(octets); + Q_ASSERT(tmp.length() == 1); + uint v = tmp.at(0).unicode(); // ### need 32-bit value + if (v < 0x10000) { + QChar z = QChar(ushort(v)); + if (!reservedSet.contains(z)) { + output.append(z); + } else { + output.append(input.mid(start, i - start + 1)); + } + } else { + if (v > 0x10FFFF) { + // URIError + break; + } + ushort l = ushort(((v - 0x10000) & 0x3FF) + 0xDC00); + ushort h = ushort((((v - 0x10000) >> 10) & 0x3FF) + 0xD800); + output.append(QChar(l)); + output.append(QChar(h)); + } + } else { + output.append(ushort(b)); + } + } else { + output.append(c); + } + ++i; + } + *ok = (i == length); + return output; +} + +class PrintFunction : public QScriptFunction +{ +public: + PrintFunction() {} + + virtual ~PrintFunction() {} + + virtual void execute(QScriptContextPrivate *context) + { + QScriptEnginePrivate *eng = context->engine(); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionEntry(context); +#endif + QString result; + for (int i = 0; i < context->argumentCount(); ++i) { + if (i != 0) + result.append(QLatin1String(" ")); + + QString s = context->argument(i).toString(); + if (context->state() == QScriptContext::ExceptionState) + break; + result.append(s); + } + + if (context->state() != QScriptContext::ExceptionState) { + QTextStream qout(stdout, QIODevice::WriteOnly); + qout << result << endl; + context->setReturnValue(eng->undefinedValue()); + } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionExit(context); +#endif + } + + QString functionName() const + { + return QLatin1String("print"); + } +}; + +} // anonumous + +namespace QScript { namespace Ecma { + +Global::Global(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo) + : m_engine(engine), m_classInfo(classInfo) +{ +} + +Global::~Global() +{ +} + +void Global::construct(QScriptValueImpl *object, QScriptEnginePrivate *eng) +{ + QScriptClassInfo *classInfo = eng->registerClass(QLatin1String("global"), + QScriptClassInfo::ActivationType); + + // create with prototype null, since Object.prototype doesn't exist at this point + eng->newObject(object, eng->nullValue(), classInfo); + + Global *instance = new Global(eng, classInfo); + object->setObjectData(instance); +} + +void Global::initialize(QScriptValueImpl *object, QScriptEnginePrivate *eng) +{ + // set the real prototype + object->setPrototype(eng->objectConstructor->publicPrototype); + + const QScriptValue::PropertyFlags flags = QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration; + + object->setProperty(QLatin1String("NaN"), QScriptValueImpl(qSNaN()), flags); + object->setProperty(QLatin1String("Infinity"), QScriptValueImpl(qInf()), flags); + object->setProperty(QLatin1String("undefined"), eng->undefinedValue(), flags); + + object->setProperty(QLatin1String("print"), + eng->createFunction(new PrintFunction()), flags); + addFunction(*object, QLatin1String("parseInt"), method_parseInt, 2, flags); + addFunction(*object, QLatin1String("parseFloat"), method_parseFloat, 1, flags); + addFunction(*object, QLatin1String("isNaN"), method_isNaN, 1, flags); + addFunction(*object, QLatin1String("isFinite"), method_isFinite, 1, flags); + addFunction(*object, QLatin1String("decodeURI"), method_decodeURI, 1, flags); + addFunction(*object, QLatin1String("decodeURIComponent"), method_decodeURIComponent, 1, flags); + addFunction(*object, QLatin1String("encodeURI"), method_encodeURI, 1, flags); + addFunction(*object, QLatin1String("encodeURIComponent"), method_encodeURIComponent, 1, flags); + addFunction(*object, QLatin1String("escape"), method_escape, 1, flags); + addFunction(*object, QLatin1String("unescape"), method_unescape, 1, flags); + addFunction(*object, QLatin1String("version"), method_version, 0, flags); + addFunction(*object, QLatin1String("gc"), method_gc, 0, flags); +} + +QScriptValueImpl Global::method_parseInt(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + if (context->argumentCount() == 0) + return qSNaN(); + + qsreal radix = 0; + if (context->argumentCount() > 1) { + radix = context->argument(1).toInteger(); + if (qIsNaN(radix) || (radix && (radix < 2 || radix > 36))) { + return qSNaN(); + } + } + + return QScript::integerFromString(context->argument(0).toString(), static_cast<int>(radix)); +} + +QScriptValueImpl Global::method_parseFloat(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + if (context->argumentCount() == 0) + return QScriptValueImpl(qSNaN()); + QString str = context->argument(0).toString().trimmed(); + QByteArray latin1 = str.toLatin1(); + const char *data = latin1.constData(); + const char *eptr = 0; + qsreal result = qstrtod(data, &eptr, 0); + if (eptr == data) { + if (str == QLatin1String("Infinity")) + result = +qInf(); + else if (str == QLatin1String("+Infinity")) + result = +qInf(); + else if (str == QLatin1String("-Infinity")) + result = -qInf(); + else + result = qSNaN(); + } + return result; +} + +QScriptValueImpl Global::method_isNaN(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = qSNaN(); + if (context->argumentCount() > 0) + v = context->argument(0).toNumber(); + return (QScriptValueImpl(qIsNaN(v))); +} + +QScriptValueImpl Global::method_isFinite(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = qInf(); + if (context->argumentCount() > 0) + v = context->argument(0).toNumber(); + return (QScriptValueImpl(qIsFinite(v))); +} + +QScriptValueImpl Global::method_decodeURI(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl result; + + if (context->argumentCount() > 0) { + QString str = context->argument(0).toString(); + bool ok; + QString out = decode(str, QString::fromUtf8(uriReserved) + QString::fromUtf8("#"), &ok); + if (ok) + return QScriptValueImpl(eng, out); + else + return context->throwError(QScriptContext::URIError, + QLatin1String("malformed URI sequence")); + } + + return eng->undefinedValue(); +} + +QScriptValueImpl Global::method_decodeURIComponent(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->argumentCount() > 0) { + QString str = context->argument(0).toString(); + bool ok; + QString out = decode(str, QString::fromUtf8(""), &ok); + if (ok) + result = QScriptValueImpl(eng, out); + else + result = context->throwError(QScriptContext::URIError, + QLatin1String("malformed URI sequence")); + } else { + result = eng->undefinedValue(); + } + return result; +} + +QScriptValueImpl Global::method_encodeURI(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->argumentCount() > 0) { + QString str = context->argument(0).toString(); + bool ok; + QString out = encode(str, + QLatin1String(uriReserved) + + QLatin1String(uriUnescaped) + + QString::fromUtf8("#"), + &ok); + if (ok) + result = QScriptValueImpl(eng, out); + else + result = context->throwError(QScriptContext::URIError, + QLatin1String("malformed URI sequence")); + } else { + result = eng->undefinedValue(); + } + return result; +} + +QScriptValueImpl Global::method_encodeURIComponent(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QScriptValueImpl result; + if (context->argumentCount() > 0) { + QString str = context->argument(0).toString(); + bool ok; + QString out = encode(str, QLatin1String(uriUnescaped), &ok); + if (ok) + result = QScriptValueImpl(eng, out); + else + result = context->throwError(QScriptContext::URIError, + QLatin1String("malformed URI sequence")); + } else { + result = eng->undefinedValue(); + } + return result; +} + +QScriptValueImpl Global::method_escape(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + if (context->argumentCount() > 0) { + QString str = context->argument(0).toString(); + return QScriptValueImpl(eng, QLatin1String(escape(str))); + } + return QScriptValueImpl(eng, QLatin1String("undefined")); +} + +QScriptValueImpl Global::method_unescape(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + if (context->argumentCount() > 0) { + QByteArray data = context->argument(0).toString().toLatin1(); + return QScriptValueImpl(eng, unescape(data)); + } + return QScriptValueImpl(eng, QLatin1String("undefined")); +} + +QScriptValueImpl Global::method_version(QScriptContextPrivate *, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + return (QScriptValueImpl(1)); +} + +QScriptValueImpl Global::method_gc(QScriptContextPrivate *, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + eng->gc(); + return QScriptValueImpl(eng->objectAllocator.freeBlocks()); +} + +void Global::addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags) +{ + QScriptEnginePrivate *eng_p = object.engine(); + QScriptValueImpl val = eng_p->createFunction(fun, length, object.classInfo(), name); + object.setProperty(name, val, flags); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaglobal_p.h b/src/script/qscriptecmaglobal_p.h new file mode 100644 index 0000000..3df1c0a --- /dev/null +++ b/src/script/qscriptecmaglobal_p.h @@ -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 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 QSCRIPTECMAGLOBAL_P_H +#define QSCRIPTECMAGLOBAL_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 "qscriptobjectdata_p.h" +#include "qscriptfunction_p.h" +#include "qscriptvalue.h" + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; +class QScriptContextPrivate; +class QScriptClassInfo; +class QScriptValueImpl; + +#ifndef QT_NO_SCRIPT + +namespace QScript { namespace Ecma { + +class Global: public QScriptObjectData +{ +protected: + Global(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo); + +public: + virtual ~Global(); + + inline QScriptEnginePrivate *engine() const; + + static void construct(QScriptValueImpl *object, QScriptEnginePrivate *eng); + static void initialize(QScriptValueImpl *object, QScriptEnginePrivate *eng); + +protected: + static QScriptValueImpl method_parseInt(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_parseFloat(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_isNaN(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_isFinite(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_decodeURI(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_decodeURIComponent(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_encodeURI(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_encodeURIComponent(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_escape(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_unescape(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_version(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_gc(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + +private: + static void addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags); + + QScriptEnginePrivate *m_engine; + QScriptClassInfo *m_classInfo; +}; + +inline QScriptEnginePrivate *Global::engine() const +{ return m_engine; } + + +} } // namespace QScript::Ecma + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptecmamath.cpp b/src/script/qscriptecmamath.cpp new file mode 100644 index 0000000..e0fcf0a --- /dev/null +++ b/src/script/qscriptecmamath.cpp @@ -0,0 +1,391 @@ +/**************************************************************************** +** +** 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 "qscriptecmamath_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> +#include <QtCore/qnumeric.h> +#include <QtCore/QSysInfo> +#include <math.h> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +static const qsreal qt_PI = 2.0 * ::asin(1.0); + +Math::Math(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo): + m_engine(engine), + m_classInfo(classInfo) +{ +} + +Math::~Math() +{ +} + +void Math::construct(QScriptValueImpl *object, QScriptEnginePrivate *eng) +{ + QScriptClassInfo *classInfo = eng->registerClass(QLatin1String("Math")); + + Math *instance = new Math(eng, classInfo); + eng->newObject(object, classInfo); + object->setObjectData(instance); + + QScriptValue::PropertyFlags flags = QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration; + + object->setProperty(QLatin1String("E"), + QScriptValueImpl(::exp(1.0)), flags); + object->setProperty(QLatin1String("LN2"), + QScriptValueImpl(::log(2.0)), flags); + object->setProperty(QLatin1String("LN10"), + QScriptValueImpl(::log(10.0)), flags); + object->setProperty(QLatin1String("LOG2E"), + QScriptValueImpl(1.0/::log(2.0)), flags); + object->setProperty(QLatin1String("LOG10E"), + QScriptValueImpl(1.0/::log(10.0)), flags); + object->setProperty(QLatin1String("PI"), + QScriptValueImpl(qt_PI), flags); + object->setProperty(QLatin1String("SQRT1_2"), + QScriptValueImpl(::sqrt(0.5)), flags); + object->setProperty(QLatin1String("SQRT2"), + QScriptValueImpl(::sqrt(2.0)), flags); + + flags = QScriptValue::SkipInEnumeration; + addFunction(*object, QLatin1String("abs"), method_abs, 1, flags); + addFunction(*object, QLatin1String("acos"), method_acos, 1, flags); + addFunction(*object, QLatin1String("asin"), method_asin, 0, flags); + addFunction(*object, QLatin1String("atan"), method_atan, 1, flags); + addFunction(*object, QLatin1String("atan2"), method_atan2, 2, flags); + addFunction(*object, QLatin1String("ceil"), method_ceil, 1, flags); + addFunction(*object, QLatin1String("cos"), method_cos, 1, flags); + addFunction(*object, QLatin1String("exp"), method_exp, 1, flags); + addFunction(*object, QLatin1String("floor"), method_floor, 1, flags); + addFunction(*object, QLatin1String("log"), method_log, 1, flags); + addFunction(*object, QLatin1String("max"), method_max, 2, flags); + addFunction(*object, QLatin1String("min"), method_min, 2, flags); + addFunction(*object, QLatin1String("pow"), method_pow, 2, flags); + addFunction(*object, QLatin1String("random"), method_random, 0, flags); + addFunction(*object, QLatin1String("round"), method_round, 1, flags); + addFunction(*object, QLatin1String("sin"), method_sin, 1, flags); + addFunction(*object, QLatin1String("sqrt"), method_sqrt, 1, flags); + addFunction(*object, QLatin1String("tan"), method_tan, 1, flags); +} + +/* copies the sign from y to x and returns the result */ +static qsreal copySign(qsreal x, qsreal y) +{ + uchar *xch = (uchar *)&x; + uchar *ych = (uchar *)&y; + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) + xch[0] = (xch[0] & 0x7f) | (ych[0] & 0x80); + else + xch[7] = (xch[7] & 0x7f) | (ych[7] & 0x80); + return x; +} + +QScriptValueImpl Math::method_abs(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v == 0) // 0 | -0 + return (QScriptValueImpl(0)); + else + return (QScriptValueImpl(v < 0 ? -v : v)); +} + +QScriptValueImpl Math::method_acos(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v > 1) + return QScriptValueImpl(qSNaN()); + return (QScriptValueImpl(::acos(v))); +} + +QScriptValueImpl Math::method_asin(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v > 1) + return QScriptValueImpl(qSNaN()); + return (QScriptValueImpl(::asin(v))); +} + +QScriptValueImpl Math::method_atan(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v == 0.0) + return QScriptValueImpl(v); + return (QScriptValueImpl(::atan(v))); +} + +QScriptValueImpl Math::method_atan2(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v1 = context->argument(0).toNumber(); + qsreal v2 = context->argument(1).toNumber(); +#ifdef Q_OS_WINCE + if (v1 == 0.0) { + const bool v1MinusZero = _copysign(1.0, v1) < 0.0; + const bool v2MinusZero = (v2 == 0 && _copysign(1.0, v2) < 0.0); + if ((v1MinusZero && v2MinusZero) || (v1MinusZero && v2 == -1.0)) + return QScriptValueImpl(-qt_PI); + if (v2MinusZero) + return QScriptValueImpl(qt_PI); + if (v1MinusZero && v2 == 1.0) + return QScriptValueImpl(-0.0); +#if defined(_X86_) + if (v2 == 0.0 && (v1MinusZero || (!v1MinusZero && !v2MinusZero))) + return QScriptValueImpl(0.0); +#endif + } +#endif +#if defined(Q_OS_WINCE) && defined(_X86_) + if (v1 == -1.0 && !_finite(v2) && _copysign(1.0, v2) > 0.0) + return QScriptValueImpl(-0.0); +#endif + if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0)) + return QScriptValueImpl(copySign(0, -1.0)); + if ((v1 == 0.0) && (v2 == 0.0)) { + if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0)) + return QScriptValueImpl(qt_PI); + else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) + return QScriptValueImpl(-qt_PI); + } + return (QScriptValueImpl(::atan2(v1, v2))); +} + +QScriptValueImpl Math::method_ceil(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v < 0.0 && v > -1.0) + return QScriptValueImpl(copySign(0, -1.0)); + return (QScriptValueImpl(::ceil(v))); +} + +QScriptValueImpl Math::method_cos(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + return (QScriptValueImpl(::cos(v))); +} + +QScriptValueImpl Math::method_exp(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (qIsInf(v)) { + if (copySign(1.0, v) == -1.0) + return QScriptValueImpl(0); + else + return QScriptValueImpl(qInf()); + } + return (QScriptValueImpl(::exp(v))); +} + +QScriptValueImpl Math::method_floor(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + return (QScriptValueImpl(::floor(v))); +} + +QScriptValueImpl Math::method_log(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v < 0) + return QScriptValueImpl(qSNaN()); + return (QScriptValueImpl(::log(v))); +} + +QScriptValueImpl Math::method_max(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal mx = -qInf(); + for (int i = 0; i < context->argumentCount(); ++i) { + qsreal x = context->argument(i).toNumber(); + if (x > mx || qIsNaN(x)) + mx = x; + } + return (QScriptValueImpl(mx)); +} + +QScriptValueImpl Math::method_min(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal mx = qInf(); + for (int i = 0; i < context->argumentCount(); ++i) { + qsreal x = context->argument(i).toNumber(); + if ((x == 0 && mx == x && copySign(1.0, x) == -1.0) + || (x < mx) || qIsNaN(x)) { + mx = x; + } + } + return (QScriptValueImpl(mx)); +} + +QScriptValueImpl Math::method_pow(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal x = context->argument(0).toNumber(); + qsreal y = context->argument(1).toNumber(); + if (qIsNaN(y)) + return QScriptValueImpl(qSNaN()); + if (y == 0) + return QScriptValueImpl(1); + if (((x == 1) || (x == -1)) && qIsInf(y)) + return QScriptValueImpl(qSNaN()); + if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) + return QScriptValueImpl(qInf()); + if ((x == 0) && copySign(1.0, x) == -1.0) { + if (y < 0) { + if (::fmod(-y, 2.0) == 1.0) + return QScriptValueImpl(-qInf()); + else + return QScriptValueImpl(qInf()); + } else if (y > 0) { + if (::fmod(y, 2.0) == 1.0) + return QScriptValueImpl(copySign(0, -1.0)); + else + return QScriptValueImpl(0); + } + } +#ifdef Q_OS_AIX + if (qIsInf(x) && copySign(1.0, x) == -1.0) { + if (y > 0) { + if (::fmod(y, 2.0) == 1.0) + return QScriptValueImpl(-qInf()); + else + return QScriptValueImpl(qInf()); + } else if (y < 0) { + if (::fmod(-y, 2.0) == 1.0) + return QScriptValueImpl(copySign(0, -1.0)); + else + return QScriptValueImpl(0); + } + } +#endif + return (QScriptValueImpl(::pow(x, y))); +} + +QScriptValueImpl Math::method_random(QScriptContextPrivate *, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + return (QScriptValueImpl(qrand() / (qsreal) RAND_MAX)); +} + +QScriptValueImpl Math::method_round(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + v = copySign(::floor(v + 0.5), v); + return (QScriptValueImpl(v)); +} + +QScriptValueImpl Math::method_sin(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + return (QScriptValueImpl(::sin(v))); +} + +QScriptValueImpl Math::method_sqrt(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + return (QScriptValueImpl(::sqrt(v))); +} + +QScriptValueImpl Math::method_tan(QScriptContextPrivate *context, + QScriptEnginePrivate *, + QScriptClassInfo *) +{ + qsreal v = context->argument(0).toNumber(); + if (v == 0.0) + return QScriptValueImpl(v); + return (QScriptValueImpl(::tan(v))); +} + +void Math::addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags) +{ + QScriptEnginePrivate *eng_p = object.engine(); + QScriptValueImpl val = eng_p->createFunction(fun, length, object.classInfo(), name); + object.setProperty(name, val, flags); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmamath_p.h b/src/script/qscriptecmamath_p.h new file mode 100644 index 0000000..3a850c2 --- /dev/null +++ b/src/script/qscriptecmamath_p.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 QSCRIPTECMAMATH_P_H +#define QSCRIPTECMAMATH_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 "qscriptobjectdata_p.h" +#include "qscriptfunction_p.h" +#include "qscriptvalue.h" + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; +class QScriptContextPrivate; +class QScriptClassInfo; +class QScriptValueImpl; + +#ifndef QT_NO_SCRIPT + +namespace QScript { namespace Ecma { + +class Math: public QScriptObjectData +{ +protected: + Math(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo); + +public: + virtual ~Math(); + + static void construct(QScriptValueImpl *object, QScriptEnginePrivate *eng); + + inline QScriptEnginePrivate *engine() const; + +protected: + static QScriptValueImpl method_abs(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_acos(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_asin(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_atan(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_atan2(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_ceil(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_cos(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_exp(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_floor(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_log(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_max(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_min(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_pow(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_random(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_round(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_sin(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_sqrt(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_tan(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + +private: + static void addFunction(QScriptValueImpl &object, const QString &name, + QScriptInternalFunctionSignature fun, int length, + const QScriptValue::PropertyFlags flags); + + QScriptEnginePrivate *m_engine; + QScriptClassInfo *m_classInfo; +}; + +inline QScriptEnginePrivate *Math::engine() const +{ return m_engine; } + + +} } // namespace QScript::Ecma + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptecmanumber.cpp b/src/script/qscriptecmanumber.cpp new file mode 100644 index 0000000..7d3d903 --- /dev/null +++ b/src/script/qscriptecmanumber.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** 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 "qscriptecmanumber_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> +#include <QtCore/qnumeric.h> +#include <math.h> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +Number::Number(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("Number"), QScriptClassInfo::NumberType) +{ + newNumber(&publicPrototype, 0); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("toLocaleString"), method_toLocaleString, 0); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); + addPrototypeFunction(QLatin1String("toFixed"), method_toFixed, 1); + addPrototypeFunction(QLatin1String("toExponential"), method_toExponential, 1); + addPrototypeFunction(QLatin1String("toPrecision"), method_toPrecision, 1); + + QScriptValue::PropertyFlags flags = QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration; + ctor.setProperty(QLatin1String("NaN"), + QScriptValueImpl(qSNaN()), flags); + ctor.setProperty(QLatin1String("NEGATIVE_INFINITY"), + QScriptValueImpl(-qInf()), flags); + ctor.setProperty(QLatin1String("POSITIVE_INFINITY"), + QScriptValueImpl(qInf()), flags); + ctor.setProperty(QLatin1String("MAX_VALUE"), + QScriptValueImpl(1.7976931348623158e+308), flags); +#ifdef __INTEL_COMPILER +# pragma warning( push ) +# pragma warning(disable: 239) +#endif + ctor.setProperty(QLatin1String("MIN_VALUE"), + QScriptValueImpl(5e-324), flags); +#ifdef __INTEL_COMPILER +# pragma warning( pop ) +#endif +} + +Number::~Number() +{ +} + +void Number::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + qsreal value; + if (context->argumentCount() > 0) + value = context->argument(0).toNumber(); + else + value = 0; + + QScriptValueImpl num(value); + if (!context->isCalledAsConstructor()) { + context->setReturnValue(num); + } else { + QScriptValueImpl &obj = context->m_thisObject; + obj.setClassInfo(classInfo()); + obj.setInternalValue(num); + obj.setPrototype(publicPrototype); + context->setReturnValue(obj); + } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Number::newNumber(QScriptValueImpl *result, qsreal value) +{ + engine()->newObject(result, publicPrototype, classInfo()); + result->setInternalValue(QScriptValueImpl(value)); +} + +QScriptValueImpl Number::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.toString")); + } + QScriptValueImpl arg = context->argument(0); + if (!arg.isUndefined()) { + int radix = arg.toInt32(); + if (radix < 2 || radix > 36) + return context->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") + .arg(radix)); + if (radix != 10) { + QString str; + qsreal num = self.internalValue().toNumber(); + if (qIsNaN(num)) + return QScriptValueImpl(eng, QLatin1String("NaN")); + else if (qIsInf(num)) + return QScriptValueImpl(eng, QLatin1String(num < 0 ? "-Infinity" : "Infinity")); + bool negative = false; + if (num < 0) { + negative = true; + num = -num; + } + qsreal frac = num - ::floor(num); + num = QScriptEnginePrivate::toInteger(num); + do { + char c = (char)::fmod(num, radix); + c = (c < 10) ? (c + '0') : (c - 10 + 'a'); + str.prepend(QLatin1Char(c)); + num = ::floor(num / radix); + } while (num != 0); + if (frac != 0) { + str.append(QLatin1Char('.')); + do { + frac = frac * radix; + char c = (char)::floor(frac); + c = (c < 10) ? (c + '0') : (c - 10 + 'a'); + str.append(QLatin1Char(c)); + frac = frac - ::floor(frac); + } while (frac != 0); + } + if (negative) + str.prepend(QLatin1Char('-')); + return QScriptValueImpl(eng, str); + } + } + QString str = self.internalValue().toString(); + return (QScriptValueImpl(eng, str)); +} + +QScriptValueImpl Number::method_toLocaleString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.toLocaleString")); + } + QString str = self.internalValue().toString(); + return (QScriptValueImpl(eng, str)); +} + +QScriptValueImpl Number::method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.valueOf")); + } + return (self.internalValue()); +} + +QScriptValueImpl Number::method_toFixed(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.toFixed")); + } + qsreal fdigits = 0; + + if (context->argumentCount() > 0) + fdigits = context->argument(0).toInteger(); + + if (qIsNaN(fdigits)) + fdigits = 0; + + qsreal v = self.internalValue().toNumber(); + QString str; + if (qIsNaN(v)) + str = QString::fromLatin1("NaN"); + else if (qIsInf(v)) + str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity"); + else + str = QString::number(v, 'f', int (fdigits)); + return (QScriptValueImpl(eng, str)); +} + +QScriptValueImpl Number::method_toExponential(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.toExponential")); + } + qsreal fdigits = 0; + + if (context->argumentCount() > 0) + fdigits = context->argument(0).toInteger(); + + qsreal v = self.internalValue().toNumber(); + QString z = QString::number(v, 'e', int (fdigits)); + return (QScriptValueImpl(eng, z)); +} + +QScriptValueImpl Number::method_toPrecision(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("Number.prototype.toPrecision")); + } + qsreal fdigits = 0; + + if (context->argumentCount() > 0) + fdigits = context->argument(0).toInteger(); + + qsreal v = self.internalValue().toNumber(); + return (QScriptValueImpl(eng, QString::number(v, 'g', int (fdigits)))); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmanumber_p.h b/src/script/qscriptecmanumber_p.h new file mode 100644 index 0000000..55e2cf9 --- /dev/null +++ b/src/script/qscriptecmanumber_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 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 QSCRIPTECMANUMBER_P_H +#define QSCRIPTECMANUMBER_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Number: public Core +{ +public: + Number(QScriptEnginePrivate *engine); + virtual ~Number(); + + virtual void execute(QScriptContextPrivate *context); + + void newNumber(QScriptValueImpl *result, double value = 0); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_toFixed(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_toExponential(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_toPrecision(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptecmaobject.cpp b/src/script/qscriptecmaobject.cpp new file mode 100644 index 0000000..694f479 --- /dev/null +++ b/src/script/qscriptecmaobject.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 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 "qscriptecmaobject_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +Object::Object(QScriptEnginePrivate *eng, QScriptClassInfo *classInfo): + Core(eng, classInfo) +{ + newObject(&publicPrototype, eng->nullValue()); +} + +Object::~Object() +{ +} + +void Object::initialize() +{ + QScriptEnginePrivate *eng = engine(); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 1); + addPrototypeFunction(QLatin1String("toLocaleString"), method_toLocaleString, 1); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); + addPrototypeFunction(QLatin1String("hasOwnProperty"), method_hasOwnProperty, 1); + addPrototypeFunction(QLatin1String("isPrototypeOf"), method_isPrototypeOf, 1); + addPrototypeFunction(QLatin1String("propertyIsEnumerable"), method_propertyIsEnumerable, 1); + addPrototypeFunction(QLatin1String("__defineGetter__"), method_defineGetter, 2); + addPrototypeFunction(QLatin1String("__defineSetter__"), method_defineSetter, 2); +} + +void Object::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + QScriptValueImpl value; + + if (context->argumentCount() > 0) + value = engine()->toObject(context->argument(0)); + else + value.invalidate(); + + if (! value.isValid()) + newObject(&value); + + context->setReturnValue(value); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void Object::newObject(QScriptValueImpl *result, const QScriptValueImpl &proto) +{ + engine()->newObject(result, proto, classInfo()); +} + +QScriptValueImpl Object::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl glo = eng->globalObject(); + QString s = QLatin1String("[object "); + QScriptValueImpl self = context->thisObject(); + s += self.classInfo()->name(); + s += QLatin1String("]"); + return (QScriptValueImpl(eng, s)); +} + +QScriptValueImpl Object::method_toLocaleString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + return method_toString(context, eng, classInfo); +} + +QScriptValueImpl Object::method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + return (context->thisObject()); +} + +QScriptValueImpl Object::method_hasOwnProperty(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + bool result = false; + + if (context->thisObject().isObject() && (context->argumentCount() > 0)) { + QScriptValueImpl arg = context->argument(0); + + QScriptNameIdImpl *id = 0; + if (arg.isString()) + id = arg.stringValue(); + + if (! id || ! id->unique) { + QString str = arg.toString(); + id = eng->nameId(str); + } + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl self = context->thisObject(); + if (self.resolve(id, &member, &base, QScriptValue::ResolveLocal, QScript::Read)) + result = true; + } + + return (QScriptValueImpl(result)); +} + +QScriptValueImpl Object::method_isPrototypeOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + bool result = false; + + if (context->thisObject().isObject() && (context->argumentCount() > 0)) { + QScriptValueImpl arg = context->argument(0); + + if (arg.isObject()) { + QScriptValueImpl proto = arg.prototype(); + + if (proto.isObject()) { + QScriptValueImpl self = context->thisObject(); + result = self.objectValue() == proto.objectValue(); + } + } + } + + return (QScriptValueImpl(result)); +} + +QScriptValueImpl Object::method_propertyIsEnumerable(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + bool result = false; + + if (context->thisObject().isObject() && (context->argumentCount() > 0)) { + QScriptValueImpl arg = context->argument(0); + + QScriptNameIdImpl *id = 0; + if (arg.isString()) + id = arg.stringValue(); + + if (! id || ! id->unique) { + QString str = arg.toString(); + id = eng->nameId(str); + } + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl self = context->thisObject(); + if (self.resolve(id, &member, &base, QScriptValue::ResolveLocal, QScript::Read)) { + result = ! member.dontEnum(); + if (result) { + QScriptValueImpl tmp; + base.get(member, &tmp); + result = tmp.isValid(); + } + } + } + + return (QScriptValueImpl(result)); +} + +QScriptValueImpl Object::method_defineGetter(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QString propertyName = context->argument(0).toString(); + if (context->thisObject().propertyFlags(propertyName) & QScriptValue::ReadOnly) + return context->throwError(QLatin1String("cannot redefine read-only property")); + QScriptValueImpl getter = context->argument(1); + if (!getter.isFunction()) + return context->throwError(QLatin1String("getter must be a function")); + context->thisObject().setProperty(propertyName, getter, QScriptValue::PropertyGetter); + return eng->undefinedValue(); +} + +QScriptValueImpl Object::method_defineSetter(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QString propertyName = context->argument(0).toString(); + if (context->thisObject().propertyFlags(propertyName) & QScriptValue::ReadOnly) + return context->throwError(QLatin1String("cannot redefine read-only property")); + QScriptValueImpl setter = context->argument(1); + if (!setter.isFunction()) + return context->throwError(QLatin1String("setter must be a function")); + context->thisObject().setProperty(propertyName, setter, QScriptValue::PropertySetter); + return eng->undefinedValue(); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaobject_p.h b/src/script/qscriptecmaobject_p.h new file mode 100644 index 0000000..d55a425 --- /dev/null +++ b/src/script/qscriptecmaobject_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 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 QSCRIPTECMAOBJECT_P_H +#define QSCRIPTECMAOBJECT_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class Object: public Core +{ +public: + Object(QScriptEnginePrivate *engine, QScriptClassInfo *classInfo); + virtual ~Object(); + + void initialize(); + + virtual void execute(QScriptContextPrivate *context); + + void newObject(QScriptValueImpl *result, const QScriptValueImpl &proto = QScriptValueImpl()); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_hasOwnProperty(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_isPrototypeOf(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_propertyIsEnumerable(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_defineGetter(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_defineSetter(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptecmaregexp.cpp b/src/script/qscriptecmaregexp.cpp new file mode 100644 index 0000000..4aef611 --- /dev/null +++ b/src/script/qscriptecmaregexp.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** 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 "qscriptecmaregexp_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QStringList> +#include <QtCore/QRegExp> +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +RegExp::RegExp(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("RegExp"), QScriptClassInfo::RegExpType) +{ + newRegExp(&publicPrototype, QString(), /*flags=*/0); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("exec"), method_exec, 1); + addPrototypeFunction(QLatin1String("test"), method_test, 1); + addPrototypeFunction(QLatin1String("toString"), method_toString, 1); +} + +RegExp::~RegExp() +{ +} + +RegExp::Instance *RegExp::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + +void RegExp::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + QString P; + int F; + QScriptValueImpl pattern = context->argument(0); + QScriptValueImpl flags = context->argument(1); + if (!context->isCalledAsConstructor()) { + if ((pattern.classInfo() == classInfo()) && flags.isUndefined()) { + context->m_result = pattern; + goto Lout; + } + } + if (pattern.classInfo() == classInfo()) { + if (!flags.isUndefined()) { + context->throwTypeError(QString::fromLatin1("cannot specify flags when creating a copy of a RegExp")); + goto Lout; + } + Instance *data = Instance::get(pattern, classInfo()); +#ifndef QT_NO_REGEXP + P = data->value.pattern(); +#else + P = data->pattern; +#endif + F = data->flags; + } else { + if (!pattern.isUndefined()) + P = pattern.toString(); + F = 0; + if (!flags.isUndefined()) { + QString flagsStr = flags.toString(); + for (int i = 0; i < flagsStr.length(); ++i) { + int bitflag = flagFromChar(flagsStr.at(i)); + if (bitflag == 0) { + context->throwError( + QScriptContext::SyntaxError, + QString::fromUtf8("invalid regular expression flag '%0'") + .arg(flagsStr.at(i))); + goto Lout; + } + F |= bitflag; + } + } + } + if (context->isCalledAsConstructor()) { + QScriptValueImpl &object = context->m_thisObject; + object.setClassInfo(classInfo()); + object.setPrototype(publicPrototype); +#ifndef QT_NO_REGEXP + initRegExp(&object, toRegExp(P, F), F); +#else + initRegExp(&object, P, F); +#endif + } else { + newRegExp(&context->m_result, P, F); + } + Lout: ; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void RegExp::newRegExp(QScriptValueImpl *result, const QString &pattern, int flags) +{ +#ifndef QT_NO_REGEXP + QRegExp rx = toRegExp(pattern, flags); + newRegExp_helper(result, rx, flags); +#else + engine()->newObject(result, publicPrototype, classInfo()); + initRegExp(result, pattern, flags); +#endif // QT_NO_REGEXP +} + +#ifndef QT_NO_REGEXP +void RegExp::newRegExp(QScriptValueImpl *result, const QRegExp &rx, int flags) +{ + Q_ASSERT(!(flags & IgnoreCase) || (rx.caseSensitivity() == Qt::CaseInsensitive)); + newRegExp_helper(result, rx, flags); +} + +void RegExp::newRegExp_helper(QScriptValueImpl *result, const QRegExp &rx, + int flags) +{ + engine()->newObject(result, publicPrototype, classInfo()); + initRegExp(result, rx, flags); +} + +QRegExp RegExp::toRegExp(const QScriptValueImpl &value) const +{ + Instance *rx_data = Instance::get(value, classInfo()); + Q_ASSERT(rx_data != 0); + return rx_data->value; +} + +QRegExp RegExp::toRegExp(const QString &pattern, int flags) +{ + bool ignoreCase = (flags & IgnoreCase) != 0; + return QRegExp(pattern, + (ignoreCase ? Qt::CaseInsensitive: Qt::CaseSensitive), + QRegExp::RegExp2); +} + +#endif // QT_NO_REGEXP + +void RegExp::initRegExp(QScriptValueImpl *result, +#ifndef QT_NO_REGEXP + const QRegExp &rx, +#else + const QString &pattern, +#endif + int flags) +{ + Instance *instance = new Instance(); +#ifndef QT_NO_REGEXP + instance->value = rx; +#else + instance->pattern = pattern; +#endif + instance->flags = flags; + result->setObjectData(instance); + + bool global = (flags & Global) != 0; + bool ignoreCase = (flags & IgnoreCase) != 0; + bool multiline = (flags & Multiline) != 0; + + QScriptValue::PropertyFlags propertyFlags = QScriptValue::SkipInEnumeration + | QScriptValue::Undeletable + | QScriptValue::ReadOnly; + + result->setProperty(QLatin1String("global"), QScriptValueImpl(global), + propertyFlags); + result->setProperty(QLatin1String("ignoreCase"), QScriptValueImpl(ignoreCase), + propertyFlags); + result->setProperty(QLatin1String("multiline"), QScriptValueImpl(multiline), + propertyFlags); +#ifndef QT_NO_REGEXP + const QString &pattern = rx.pattern(); +#endif + result->setProperty(QLatin1String("source"), QScriptValueImpl(engine(), pattern), + propertyFlags); + result->setProperty(QLatin1String("lastIndex"), QScriptValueImpl(0), + propertyFlags & ~QScriptValue::ReadOnly); +} + +int 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 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; +} + +QScriptValueImpl RegExp::method_exec(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("RegExp.prototype.exec")); + } + Instance *rx_data = Instance::get(self, classInfo); + Q_ASSERT(rx_data != 0); + + QString S = context->argument(0).toString(); + int length = S.length(); + QScriptValueImpl lastIndex = self.property(QLatin1String("lastIndex")); + + int i = lastIndex.isValid() ? int (lastIndex.toInteger()) : 0; + bool global = self.property(QLatin1String("global")).toBoolean(); + + if (! global) + i = 0; + + if (i < 0 || i >= length) + return (eng->nullValue()); + +#ifndef QT_NO_REGEXP + int index = rx_data->value.indexIn(S, i); + if (index == -1) +#endif // QT_NO_REGEXP + return eng->nullValue(); + +#ifndef QT_NO_REGEXP + int e = index + rx_data->value.matchedLength(); + + if (global) + self.setProperty(QLatin1String("lastIndex"), QScriptValueImpl(e)); + + QScript::Array elts(eng); + QStringList capturedTexts = rx_data->value.capturedTexts(); + for (int i = 0; i < capturedTexts.count(); ++i) + elts.assign(i, QScriptValueImpl(eng, capturedTexts.at(i))); + + QScriptValueImpl r = eng->newArray(elts); + + r.setProperty(QLatin1String("index"), QScriptValueImpl(index)); + r.setProperty(QLatin1String("input"), QScriptValueImpl(eng, S)); + + return r; +#endif // QT_NO_REGEXP +} + +QScriptValueImpl RegExp::method_test(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + QScriptValueImpl r = method_exec(context, eng, classInfo); + return QScriptValueImpl(!r.isNull()); +} + +QScriptValueImpl RegExp::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QString result; + result += QLatin1Char('/'); +#ifndef QT_NO_REGEXP + const QString &pattern = instance->value.pattern(); +#else + const QString &pattern = instance->pattern; +#endif + if (pattern.isEmpty()) + result += QLatin1String("(?:)"); + else + result += pattern; // ### quote + result += QLatin1Char('/'); + result += flagsToString(instance->flags); + return (QScriptValueImpl(eng, result)); + } + + return throwThisObjectTypeError( + context, QLatin1String("RegExp.prototype.toString")); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmaregexp_p.h b/src/script/qscriptecmaregexp_p.h new file mode 100644 index 0000000..77fe467 --- /dev/null +++ b/src/script/qscriptecmaregexp_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 QSCRIPTECMAREGEXP_P_H +#define QSCRIPTECMAREGEXP_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/QRegExp> + +#ifndef QT_NO_SCRIPT + +#include "qscriptecmacore_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class RegExp: public Core +{ +public: + enum RegExpFlag { + Global = 0x01, + IgnoreCase = 0x02, + Multiline = 0x04 + }; + + RegExp(QScriptEnginePrivate *engine); + virtual ~RegExp(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptObjectData { + public: + Instance() : flags(0) {} + virtual ~Instance() {} + + static Instance *get(const QScriptValueImpl &object, + QScriptClassInfo *klass); + + public: // attributes +#ifndef QT_NO_REGEXP + QRegExp value; +#else + QString pattern; +#endif + int flags; + }; + + inline Instance *get(const QScriptValueImpl &object) const + { return Instance::get(object, classInfo()); } + + void newRegExp(QScriptValueImpl *result, const QString &pattern, + int flags); +#ifndef QT_NO_REGEXP + void newRegExp(QScriptValueImpl *result, const QRegExp &rx, + int flags = 0); + QRegExp toRegExp(const QScriptValueImpl &value) const; + static QRegExp toRegExp(const QString &pattern, int flags); +#endif + + static int flagFromChar(const QChar &ch); + static QString flagsToString(int flags); + +protected: + static QScriptValueImpl method_exec(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_test(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toString(QScriptContextPrivate *context, + QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + +private: +#ifndef QT_NO_REGEXP + void newRegExp_helper(QScriptValueImpl *result, const QRegExp &rx, + int flags); +#endif + void initRegExp(QScriptValueImpl *result, +#ifndef QT_NO_REGEXP + const QRegExp &rx, +#else + const QString &pattern, +#endif + int flags); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTECMAREGEXP_P_H diff --git a/src/script/qscriptecmastring.cpp b/src/script/qscriptecmastring.cpp new file mode 100644 index 0000000..3c04375 --- /dev/null +++ b/src/script/qscriptecmastring.cpp @@ -0,0 +1,778 @@ +/**************************************************************************** +** +** 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 "qscriptecmastring_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptclassdata_p.h" + +#include <QtCore/QStringList> +#include <QtCore/QtDebug> +#include <QtCore/qnumeric.h> + +#include <limits.h> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class StringClassData: public QScriptClassData +{ + QScriptClassInfo *m_classInfo; + +public: + StringClassData(QScriptClassInfo *classInfo); + virtual ~StringClassData(); + + inline QScriptClassInfo *classInfo() const + { return m_classInfo; } + + virtual bool resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &object, const Member &member, + QScriptValueImpl *out_value); + virtual bool put(QScriptValueImpl *object, const Member &member, + const QScriptValueImpl &value); + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object); +}; + +class StringClassDataIterator: public QScriptClassDataIterator +{ +public: + StringClassDataIterator(int length); + virtual ~StringClassDataIterator(); + + virtual bool hasNext() const; + virtual void next(QScript::Member *member); + + virtual bool hasPrevious() const; + virtual void previous(QScript::Member *member); + + virtual void toFront(); + virtual void toBack(); + +private: + int m_length; + int m_pos; +}; + +StringClassData::StringClassData(QScriptClassInfo *classInfo): + m_classInfo(classInfo) +{ +} + +StringClassData::~StringClassData() +{ +} + +bool StringClassData::resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, + QScriptValueImpl *base, + QScript::AccessMode /*access*/) +{ + if (object.classInfo() != classInfo()) + return false; + + QScriptEnginePrivate *eng = object.engine(); + + if (nameId == eng->idTable()->id_length) { + member->native(nameId, /*id=*/ 0, + QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration); + *base = object; + return true; + } + + bool ok = false; + int index = nameId->s.toInt(&ok); + if (!ok || (index < 0)) + return false; + + QScriptNameIdImpl *ref = object.internalValue().stringValue(); + if (index >= ref->s.length()) + return false; + + member->native(nameId, index, QScriptValue::Undeletable | QScriptValue::ReadOnly); + return true; +} + +bool StringClassData::get(const QScriptValueImpl &object, + const QScript::Member &member, + QScriptValueImpl *result) +{ + Q_ASSERT(member.isValid()); + + if (object.classInfo() != classInfo()) + return false; + + QScriptEnginePrivate *eng = object.engine(); + if (! member.isNativeProperty()) + return false; + + QScriptNameIdImpl *ref = object.internalValue().stringValue(); + int len = ref->s.length(); + + if (member.nameId() == eng->idTable()->id_length) + *result = QScriptValueImpl(len); + + else if (member.id() >= 0 && member.id() < len) + eng->newString(result, ref->s.at(member.id())); + + else + *result = eng->undefinedValue(); + + return true; +} + +bool StringClassData::put(QScriptValueImpl *, const Member &, + const QScriptValueImpl &) +{ + // writes to string elements are ignored + return true; +} + +QScriptClassDataIterator *StringClassData::newIterator(const QScriptValueImpl &object) +{ + QScriptNameIdImpl *id = object.internalValue().stringValue(); + return new StringClassDataIterator(id->s.length()); +} + +StringClassDataIterator::StringClassDataIterator(int length) +{ + m_length = length; + m_pos = 0; +} + +StringClassDataIterator::~StringClassDataIterator() +{ +} + +bool StringClassDataIterator::hasNext() const +{ + return m_pos < m_length; +} + +void StringClassDataIterator::next(QScript::Member *member) +{ + member->native(/*nameId=*/ 0, m_pos, QScriptValue::Undeletable | QScriptValue::ReadOnly); + ++m_pos; +} + +bool StringClassDataIterator::hasPrevious() const +{ + return (m_pos - 1) >= 0; +} + +void StringClassDataIterator::previous(QScript::Member *member) +{ + --m_pos; + member->native(/*nameId=*/ 0, m_pos, QScriptValue::Undeletable | QScriptValue::ReadOnly); +} + +void StringClassDataIterator::toFront() +{ + m_pos = 0; +} + +void StringClassDataIterator::toBack() +{ + m_pos = m_length; +} + + + +String::String(QScriptEnginePrivate *eng): + Core(eng, QLatin1String("String"), QScriptClassInfo::StringType) +{ + classInfo()->setData(new StringClassData(classInfo())); + + newString(&publicPrototype, QString()); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); + addPrototypeFunction(QLatin1String("charAt"), method_charAt, 1); + addPrototypeFunction(QLatin1String("charCodeAt"), method_charCodeAt, 1); + addPrototypeFunction(QLatin1String("concat"), method_concat, 1); + addPrototypeFunction(QLatin1String("indexOf"), method_indexOf, 1); + addPrototypeFunction(QLatin1String("lastIndexOf"), method_lastIndexOf, 1); + addPrototypeFunction(QLatin1String("localeCompare"), method_localeCompare, 1); + addPrototypeFunction(QLatin1String("match"), method_match, 1); + addPrototypeFunction(QLatin1String("replace"), method_replace, 2); + addPrototypeFunction(QLatin1String("search"), method_search, 1); + addPrototypeFunction(QLatin1String("slice"), method_slice, 2); + addPrototypeFunction(QLatin1String("split"), method_split, 2); + addPrototypeFunction(QLatin1String("substr"), method_substr, 2); + addPrototypeFunction(QLatin1String("substring"), method_substring, 2); + addPrototypeFunction(QLatin1String("toLowerCase"), method_toLowerCase, 0); + addPrototypeFunction(QLatin1String("toLocaleLowerCase"), method_toLocaleLowerCase, 0); + addPrototypeFunction(QLatin1String("toUpperCase"), method_toUpperCase, 0); + addPrototypeFunction(QLatin1String("toLocaleUpperCase"), method_toLocaleUpperCase, 0); + + addConstructorFunction(QLatin1String("fromCharCode"), method_fromCharCode, 1); +} + +String::~String() +{ +} + +void String::execute(QScriptContextPrivate *context) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionEntry(context); +#endif + QString value; + + if (context->argumentCount() > 0) + value = context->argument(0).toString(); + + QScriptValueImpl str(engine(), value); + if (!context->isCalledAsConstructor()) { + context->setReturnValue(str); + } else { + QScriptValueImpl &obj = context->m_thisObject; + obj.setClassInfo(classInfo()); + obj.setInternalValue(str); + obj.setPrototype(publicPrototype); + context->setReturnValue(obj); + } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine()->notifyFunctionExit(context); +#endif +} + +void String::newString(QScriptValueImpl *result, const QString &value) +{ + engine()->newObject(result, publicPrototype, classInfo()); + result->setInternalValue(QScriptValueImpl(engine(), value)); +} + +QScriptValueImpl String::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return context->throwError(QScriptContext::TypeError, QLatin1String("String.prototype.toString")); + } + return (self.internalValue()); +} + +QScriptValueImpl String::method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + QScriptValueImpl self = context->thisObject(); + if (self.classInfo() != classInfo) { + return throwThisObjectTypeError( + context, QLatin1String("String.prototype.valueOf")); + } + return (self.internalValue()); +} + +QScriptValueImpl String::method_charAt(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString str = context->thisObject().toString(); + + int pos = 0; + if (context->argumentCount() > 0) + pos = int (context->argument(0).toInteger()); + + QString result; + if (pos >= 0 && pos < str.length()) + result += str.at(pos); + + return (QScriptValueImpl(eng, result)); +} + +QScriptValueImpl String::method_charCodeAt(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + QString str = context->thisObject().toString(); + + int pos = 0; + if (context->argumentCount() > 0) + pos = int (context->argument(0).toInteger()); + + qsreal result = qSNaN(); + + if (pos >= 0 && pos < str.length()) + result = str.at(pos).unicode(); + + return (QScriptValueImpl(result)); +} + +QScriptValueImpl String::method_concat(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + + for (int i = 0; i < context->argumentCount(); ++i) + value += context->argument(i).toString(); + + return (QScriptValueImpl(eng, value)); +} + +QScriptValueImpl String::method_indexOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + + QString searchString = context->argument(0).toString(); + + int pos = 0; + if (context->argumentCount() > 1) + pos = int (context->argument(1).toInteger()); + + int index = -1; + if (! value.isEmpty()) + index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length())); + + return (QScriptValueImpl(index)); +} + +QScriptValueImpl String::method_lastIndexOf(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + + QString searchString = context->argument(0).toString(); + + qsreal position = context->argument(1).toNumber(); + if (qIsNaN(position)) + position = +qInf(); + else + position = QScriptEnginePrivate::toInteger(position); + + int pos = QScriptEnginePrivate::toInt32(qMin(qMax(position, 0.0), qsreal(value.length()))); + if (!searchString.isEmpty() && pos == value.length()) + --pos; + int index = value.lastIndexOf(searchString, pos); + return (QScriptValueImpl(index)); +} + +QScriptValueImpl String::method_localeCompare(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + QString that = context->argument(0).toString(); + return QScriptValueImpl(QString::localeAwareCompare(value, that)); +} + +QScriptValueImpl String::method_match(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl pattern = context->argument(0); + + if (! eng->regexpConstructor->get(pattern)) + eng->regexpConstructor->newRegExp(&pattern, context->argument(0).toString(), /*flags=*/0); + + QScriptValueImpl rx_exec = pattern.property(QLatin1String("exec"), QScriptValue::ResolvePrototype); + if (! (rx_exec.isValid() && rx_exec.isFunction())) { + return context->throwError(QScriptContext::TypeError, + QLatin1String("String.prototype.match")); + } + + QScriptValueImplList args; + args << context->thisObject(); + + QScriptValueImpl global = pattern.property(QLatin1String("global")); + if (! (global.isValid() && global.toBoolean())) + return (rx_exec.call(pattern, args)); + + QScript::Array result(eng); + + QScriptNameIdImpl *lastIndexId = eng->nameId(QLatin1String("lastIndex")); + QScriptNameIdImpl *zeroId = eng->nameId(QLatin1String("0")); + + pattern.setProperty(lastIndexId, QScriptValueImpl(0)); + int n = 0; + while (true) { + qsreal lastIndex = pattern.property(lastIndexId).toNumber(); + QScriptValueImpl r = rx_exec.call(pattern, args); + if (r.isNull()) + break; + qsreal newLastIndex = pattern.property(lastIndexId).toNumber(); + if (newLastIndex == lastIndex) + pattern.setProperty(lastIndexId, QScriptValueImpl(lastIndex + 1)); + result.assign(n++, r.property(zeroId)); + } + + return (eng->newArray(result)); +} + +QScriptValueImpl String::method_replace(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString input = context->thisObject().toString(); + QScriptValueImpl searchValue = context->argument(0); + QScriptValueImpl replaceValue = context->argument(1); + + QString output; + if (searchValue.classInfo() == eng->regexpConstructor->classInfo()) { + // searchValue is a RegExp + QScriptValueImpl rx_exec = searchValue.property(QLatin1String("exec"), QScriptValue::ResolvePrototype); + if (!rx_exec.isFunction()) { + return context->throwError(QScriptContext::TypeError, + QLatin1String("String.prototype.replace")); + } + QVector<QScriptValueImpl> occurrences; + QScriptValueImpl global = searchValue.property(QLatin1String("global")); + QScriptValueImplList args; + args << QScriptValueImpl(eng, input); + if (!global.toBoolean()) { + QScriptValueImpl r = rx_exec.call(searchValue, args); + if (!r.isNull()) + occurrences.append(r); + } else { + QScriptNameIdImpl *lastIndexId = eng->nameId(QLatin1String("lastIndex")); + searchValue.setProperty(lastIndexId, QScriptValueImpl(0)); + while (true) { + qsreal lastIndex = searchValue.property(lastIndexId).toNumber(); + QScriptValueImpl r = rx_exec.call(searchValue, args); + if (r.isNull()) + break; + qsreal newLastIndex = searchValue.property(lastIndexId).toNumber(); + if (newLastIndex == lastIndex) + searchValue.setProperty(lastIndexId, QScriptValueImpl(lastIndex + 1)); + occurrences.append(r); + } + } + int pos = 0; + if (replaceValue.isFunction()) { + QScriptNameIdImpl *indexId = eng->nameId(QLatin1String("index")); + QScriptNameIdImpl *lengthId = eng->nameId(QLatin1String("length")); + for (int i = 0; i < occurrences.count(); ++i) { + QScriptValueImpl needle = occurrences.at(i); + int index = int (needle.property(indexId).toInteger()); + uint length = eng->toUint32(needle.property(lengthId).toNumber()); + output += input.mid(pos, index - pos); + args.clear(); + for (uint j = 0; j < length; ++j) + args << needle.property(j); + args << QScriptValueImpl(index); + args << QScriptValueImpl(eng, input); + QScriptValueImpl ret = replaceValue.call(eng->nullValue(), args); + output += ret.toString(); + pos = index + args[0].toString().length(); + } + } else { + // use string representation of replaceValue + const QString replaceString = replaceValue.toString(); + const QLatin1Char dollar = QLatin1Char('$'); + QScriptNameIdImpl *indexId = eng->nameId(QLatin1String("index")); + QScriptNameIdImpl *zeroId = eng->nameId(QLatin1String("0")); + for (int i = 0; i < occurrences.count(); ++i) { + QScriptValueImpl needle = occurrences.at(i); + int index = int (needle.property(indexId).toInteger()); + output += input.mid(pos, index - pos); + int j = 0; + while (j < replaceString.length()) { + const QChar c = replaceString.at(j++); + if ((c == dollar) && (j < replaceString.length())) { + const QChar nc = replaceString.at(j); + if (nc == dollar) { + ++j; + } else if (nc == QLatin1Char('`')) { + ++j; + output += input.left(index); + continue; + } else if (nc == QLatin1Char('\'')) { + ++j; + output += input.mid(index + needle.property(zeroId).toString().length()); + continue; + } else if (nc.isDigit()) { + ++j; + int cap = nc.toLatin1() - '0'; + if ((j < replaceString.length()) && replaceString.at(j).isDigit()) { + cap = cap * 10; + cap = replaceString.at(j++).toLatin1() - '0'; + } + output += needle.property(QScriptValueImpl(cap).toString()).toString(); + continue; + } + } + output += c; + } + pos = index + needle.property(zeroId).toString().length(); + } + } + output += input.mid(pos); + } else { + // use string representation of searchValue + const QString searchString = searchValue.toString(); + int pos = 0; + if (replaceValue.isFunction()) { + int index = input.indexOf(searchString, pos); + if (index != -1) { + output += input.mid(pos, index - pos); + QScriptValueImplList args; + args << QScriptValueImpl(eng, searchString); + args << QScriptValueImpl(index); + args << QScriptValueImpl(eng, input); + QScriptValueImpl ret = replaceValue.call(eng->nullValue(), args); + output += ret.toString(); + pos = index + searchString.length(); + } + } else { + // use string representation of replaceValue + const QString replaceString = replaceValue.toString(); + const QLatin1Char dollar = QLatin1Char('$'); + int index = input.indexOf(searchString, pos); + if (index != -1) { + output += input.mid(pos, index - pos); + int j = 0; + while (j < replaceString.length()) { + const QChar c = replaceString.at(j++); + if ((c == dollar) && (j < replaceString.length())) { + const QChar nc = replaceString.at(j); + if (nc == dollar) { + ++j; + } else if (nc == QLatin1Char('`')) { + output += input.left(index); + ++j; + continue; + } else if (nc == QLatin1Char('\'')) { + output += input.mid(index + searchString.length()); + ++j; + continue; + } + } + output += c; + } + pos = index + searchString.length(); + } + } + output += input.mid(pos); + } + return QScriptValueImpl(eng, output); +} + +QScriptValueImpl String::method_search(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl pattern = context->argument(0); + + Ecma::RegExp::Instance *rx_data = 0; + if (0 == (rx_data = eng->regexpConstructor->get(pattern))) { + eng->regexpConstructor->newRegExp(&pattern, context->argument(0).toString(), /*flags=*/0); + rx_data = eng->regexpConstructor->get(pattern); + } + + QString value = context->thisObject().toString(); +#ifndef QT_NO_REGEXP + return (QScriptValueImpl(value.indexOf(rx_data->value))); +#else + return eng->nullValue(); +#endif +} + +QScriptValueImpl String::method_slice(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString text = context->thisObject().toString(); + int length = text.length(); + + int start = int (context->argument(0).toInteger()); + int end = context->argument(1).isUndefined() + ? length : int (context->argument(1).toInteger()); + + if (start < 0) + start = qMax(length + start, 0); + else + start = qMin(start, length); + + if (end < 0) + end = qMax(length + end, 0); + else + end = qMin(end, length); + + int count = qMax(0, end - start); + return (QScriptValueImpl(eng, text.mid(start, count))); +} + +QScriptValueImpl String::method_split(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QScriptValueImpl l = context->argument(1); + quint32 lim = l.isUndefined() ? UINT_MAX : QScriptEnginePrivate::toUint32(l.toNumber()); + + if (lim == 0) + return eng->newArray(); + + QString S = context->thisObject().toString(); + QScriptValueImpl separator = context->argument(0); + + QScript::Array A(eng); + // the argumentCount() check is for compatibility with spidermonkey; + // it is not according to ECMA-262 + if (separator.isUndefined() && (context->argumentCount() == 0)) { + A.assign(0, QScriptValueImpl(eng, S)); + } else { + QStringList matches; +#ifndef QT_NO_REGEXP + if (Ecma::RegExp::Instance *rx = eng->regexpConstructor->get(separator)) { + matches = S.split(rx->value, rx->value.pattern().isEmpty() + ? QString::SkipEmptyParts : QString::KeepEmptyParts); + } else +#endif // QT_NO_REGEXP + { + QString sep = separator.toString(); + matches = S.split(sep, sep.isEmpty() + ? QString::SkipEmptyParts : QString::KeepEmptyParts); + } + uint count = qMin(lim, uint(matches.count())); + for (uint i = 0; i < count; ++i) + A.assign(i, QScriptValueImpl(eng, matches.at(i))); + } + + return eng->newArray(A); +} + +QScriptValueImpl String::method_substr(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + + qsreal start = 0; + if (context->argumentCount() > 0) + start = context->argument(0).toInteger(); + + qsreal length = +qInf(); + if (context->argumentCount() > 1) + length = context->argument(1).toInteger(); + + qsreal count = value.length(); + if (start < 0) + start = qMax(count + start, 0.0); + + length = qMin(qMax(length, 0.0), count - start); + + qint32 x = QScriptEnginePrivate::toInt32(start); + qint32 y = QScriptEnginePrivate::toInt32(length); + return QScriptValueImpl(eng, value.mid(x, y)); +} + +QScriptValueImpl String::method_substring(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + int length = value.length(); + + qsreal start = 0; + qsreal end = length; + + if (context->argumentCount() > 0) + start = context->argument(0).toInteger(); + + if (context->argumentCount() > 1) + end = context->argument(1).toInteger(); + + if (qIsNaN(start) || start < 0) + start = 0; + + if (qIsNaN(end) || end < 0) + end = 0; + + if (start > length) + start = length; + + if (end > length) + end = length; + + if (start > end) { + qsreal was = start; + start = end; + end = was; + } + + qint32 x = QScriptEnginePrivate::toInt32(start); + qint32 y = QScriptEnginePrivate::toInt32(end - start); + + return (QScriptValueImpl(eng, value.mid(x, y))); +} + +QScriptValueImpl String::method_toLowerCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + return (QScriptValueImpl(eng, value.toLower())); +} + +QScriptValueImpl String::method_toLocaleLowerCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + return method_toLowerCase(context, eng, classInfo); // ### check me +} + +QScriptValueImpl String::method_toUpperCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + return (QScriptValueImpl(eng, value.toUpper())); +} + +QScriptValueImpl String::method_toLocaleUpperCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + return method_toUpperCase(context, eng, classInfo); // ### check me +} + +QScriptValueImpl String::method_fromCharCode(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString str; + for (int i = 0; i < context->argumentCount(); ++i) { + QChar c(context->argument(i).toUInt16()); + str += c; + } + return (QScriptValueImpl(eng, str)); +} + +// Qt extensions + +QScriptValueImpl String::method_ext_arg(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + QString value = context->thisObject().toString(); + QScriptValueImpl arg = context->argument(0); + QString result; + if (arg.isString()) + result = value.arg(arg.toString()); + else if (arg.isNumber()) + result = value.arg(arg.toNumber()); + return QScriptValueImpl(eng, result); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptecmastring_p.h b/src/script/qscriptecmastring_p.h new file mode 100644 index 0000000..9ddd659 --- /dev/null +++ b/src/script/qscriptecmastring_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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 QSCRIPTECMASTRING_P_H +#define QSCRIPTECMASTRING_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 "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ecma { + +class String: public Core +{ +public: + String(QScriptEnginePrivate *engine); + virtual ~String(); + + virtual void execute(QScriptContextPrivate *context); + + void newString(QScriptValueImpl *result, const QString &value = QString()); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_charAt(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_charCodeAt(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_concat(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_indexOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_lastIndexOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_localeCompare(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_match(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_replace(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_search(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_slice(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_split(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_substr(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_substring(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLowerCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleLowerCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toUpperCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_toLocaleUpperCase(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_fromCharCode(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + +public: + // Qt extensions + static QScriptValueImpl method_ext_arg(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptengine.cpp b/src/script/qscriptengine.cpp new file mode 100644 index 0000000..d4e1923 --- /dev/null +++ b/src/script/qscriptengine.cpp @@ -0,0 +1,1879 @@ +/**************************************************************************** +** +** 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 "qscriptengine.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptsyntaxcheckresult_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptEngine + \reentrant + + \brief The QScriptEngine class provides an environment for evaluating Qt Script code. + + \ingroup script + \mainclass + + See the \l{QtScript} documentation for information about the Qt Script language, + and how to get started with scripting your C++ application. + + \section1 Evaluating Scripts + + Use evaluate() to evaluate script code; this is the C++ equivalent + of the built-in script function \c{eval()}. + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 0 + + evaluate() returns a QScriptValue that holds the result of the + evaluation. The QScriptValue class provides functions for converting + the result to various C++ types (e.g. QScriptValue::toString() + and QScriptValue::toNumber()). + + The following code snippet shows how a script function can be + defined and then invoked from C++ using QScriptValue::call(): + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 1 + + As can be seen from the above snippets, a script is provided to the + engine in the form of a string. One common way of loading scripts is + by reading the contents of a file and passing it to evaluate(): + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 2 + + Here we pass the name of the file as the second argument to + evaluate(). This does not affect evaluation in any way; the second + argument is a general-purpose string that is used to identify the + script for debugging purposes (for example, our filename will now + show up in any uncaughtExceptionBacktrace() involving the script). + + \section1 Engine Configuration + + The globalObject() function returns the \bold {Global Object} + associated with the script engine. Properties of the Global Object + are accessible from any script code (i.e. they are global + variables). Typically, before evaluating "user" scripts, you will + want to configure a script engine by adding one or more properties + to the Global Object: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 3 + + Adding custom properties to the scripting environment is one of the + standard means of providing a scripting API that is specific to your + application. Usually these custom properties are objects created by + the newQObject() or newObject() functions, or constructor functions + created by newFunction(). + + \section1 Script Exceptions + + evaluate() can throw a script exception (e.g. due to a syntax + error); in that case, the return value is the value that was thrown + (typically an \c{Error} object). You can check whether the + evaluation caused an exception by calling hasUncaughtException(). In + that case, you can call toString() on the error object to obtain an + error message. The current uncaught exception is also available + through uncaughtException(). You can obtain a human-readable + backtrace of the exception with uncaughtExceptionBacktrace(). + Calling clearExceptions() will cause any uncaught exceptions to be + cleared. + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 4 + + The checkSyntax() function can be used to determine whether code can be + usefully passed to evaluate(). + + \section1 Script Object Creation + + Use newObject() to create a standard Qt Script object; this is the + C++ equivalent of the script statement \c{new Object()}. You can use + the object-specific functionality in QScriptValue to manipulate the + script object (e.g. QScriptValue::setProperty()). Similarly, use + newArray() to create a Qt Script array object. Use newDate() to + create a \c{Date} object, and newRegExp() to create a \c{RegExp} + object. + + \section1 QObject Integration + + Use newQObject() to wrap a QObject (or subclass) + pointer. newQObject() returns a proxy script object; properties, + children, and signals and slots of the QObject are available as + properties of the proxy object. No binding code is needed because it + is done dynamically using the Qt meta object system. + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 5 + + Use qScriptConnect() to connect a C++ signal to a script function; + this is the Qt Script equivalent of QObject::connect(). When a + script function is invoked in response to a C++ signal, it can cause + a script exception; you can connect to the signalHandlerException() + signal to catch such an exception. + + Use newQMetaObject() to wrap a QMetaObject; this gives you a "script + representation" of a QObject-based class. newQMetaObject() returns a + proxy script object; enum values of the class are available as + properties of the proxy object. You can also specify a function that + will be used to construct objects of the class (e.g. when the + constructor is invoked from a script). For classes that have a + "standard" Qt constructor, Qt Script can provide a default script + constructor for you; see scriptValueFromQMetaObject(). + + See the \l{QtScript} documentation for more information on + the QObject integration. + + \section1 Support for Custom C++ Types + + Use newVariant() to wrap a QVariant. This can be used to store + values of custom (non-QObject) C++ types that have been registered + with the Qt meta-type system. To make such types scriptable, you + typically associate a prototype (delegate) object with the C++ type + by calling setDefaultPrototype(); the prototype object defines the + scripting API for the C++ type. Unlike the QObject integration, + there is no automatic binding possible here; i.e. you have to create + the scripting API yourself, for example by using the QScriptable + class. + + Use fromScriptValue() to cast from a QScriptValue to another type, + and toScriptValue() to create a QScriptValue from another value. + You can specify how the conversion of C++ types is to be performed + with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType(). + By default, Qt Script will use QVariant to store values of custom + types. + + \section1 Importing Extensions + + Use importExtension() to import plugin-based extensions into the + engine. Call availableExtensions() to obtain a list naming all the + available extensions, and importedExtensions() to obtain a list + naming only those extensions that have been imported. + + Call pushContext() to open up a new variable scope, and popContext() + to close the current scope. This is useful if you are implementing + an extension that evaluates script code containing temporary + variable definitions (e.g. \c{var foo = 123;}) that are safe to + discard when evaluation has completed. + + \section1 Native Functions + + Use newFunction() to wrap native (C++) functions, including + constructors for your own custom types, so that these can be invoked + from script code. Such functions must have the signature + QScriptEngine::FunctionSignature. You may then pass the function as + argument to newFunction(). Here is an example of a function that + returns the sum of its first two arguments: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 6 + + To expose this function to script code, you can set it as a property + of the Global Object: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 7 + + Once this is done, script code can call your function in the exact + same manner as a "normal" script function: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 8 + + \section1 Long-running Scripts + + If you need to evaluate possibly long-running scripts from the main + (GUI) thread, you should first call setProcessEventsInterval() to + make sure that the GUI stays responsive. You can abort a currently + running script by calling abortEvaluation(). You can determine + whether an engine is currently running a script by calling + isEvaluating(). + + \section1 Core Debugging/Tracing Facilities + + Since Qt 4.4, you can be notified of events pertaining to script + execution (e.g. script function calls and statement execution) + through the QScriptEngineAgent interface; see the setAgent() + function. This can be used to implement debugging and profiling of a + QScriptEngine. + + \sa QScriptValue, QScriptContext, QScriptEngineAgent + +*/ + +/*! + \enum QScriptEngine::ValueOwnership + + This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject(). + + \value QtOwnership The standard Qt ownership rules apply, i.e. the associated object will never be explicitly deleted by the script engine. This is the default. (QObject ownership is explained in \l{Object Trees and Object Ownership}.) + \value ScriptOwnership The value is owned by the script environment. The associated data will be deleted when appropriate (i.e. after the garbage collector has discovered that there are no more live references to the value). + \value AutoOwnership If the associated object has a parent, the Qt ownership rules apply (QtOwnership); otherwise, the object is owned by the script environment (ScriptOwnership). +*/ + +/*! + \enum QScriptEngine::QObjectWrapOption + + These flags specify options when wrapping a QObject pointer with newQObject(). + + \value ExcludeChildObjects The script object will not expose child objects as properties. + \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass. + \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass. + \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties + \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot. + \value AutoCreateDynamicProperties Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object. + \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object. + \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties. +*/ + +#ifdef QT_NO_QOBJECT + +QScriptEngine::QScriptEngine() + : d_ptr(new QScriptEnginePrivate) +{ + d_ptr->q_ptr = this; + d_ptr->init(); +} + +/*! \internal +*/ +QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; + d_ptr->init(); +} +#else + +/*! + Constructs a QScriptEngine object. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ +QScriptEngine::QScriptEngine() + : QObject(*new QScriptEnginePrivate, 0) +{ + Q_D(QScriptEngine); + d->init(); +} + +/*! + Constructs a QScriptEngine object with the given \a parent. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ + +QScriptEngine::QScriptEngine(QObject *parent) + : QObject(*new QScriptEnginePrivate, parent) +{ + Q_D(QScriptEngine); + d->init(); +} + +/*! \internal +*/ +QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QScriptEngine); + d->init(); +} +#endif + +/*! + Destroys this QScriptEngine. +*/ +QScriptEngine::~QScriptEngine() +{ + Q_D(QScriptEngine); + d->m_frameRepository.release(currentContext()); + d->objectAllocator.destruct(); +#ifdef QT_NO_QOBJECT + delete d_ptr; + d_ptr = 0; +#endif +} + +/*! + Returns this engine's Global Object. + + By default, the Global Object contains the built-in objects that are + part of \l{ECMA-262}, such as Math, Date and String. Additionally, + you can set properties of the Global Object to make your own + extensions available to all script code. Non-local variables in + script code will be created as properties of the Global Object, as + well as local variables in global code. +*/ +QScriptValue QScriptEngine::globalObject() const +{ + Q_D(const QScriptEngine); + return const_cast<QScriptEnginePrivate*>(d)->toPublic(d->m_globalObject); +} + +/*! + \since 4.5 + + Sets this engine's Global Object to be the given \a object. + If \a object is not a valid script object, this function does + nothing. + + When setting a custom global object, you may want to use + QScriptValueIterator to copy the properties of the standard Global + Object; alternatively, you can set the internal prototype of your + custom object to be the original Global Object. +*/ +void QScriptEngine::setGlobalObject(const QScriptValue &object) +{ + Q_D(QScriptEngine); + if (!object.isObject()) + return; + QScriptValueImpl objectImpl = d->toImpl(object); + + // update properties of the global context + QScriptValueImpl old = d->m_globalObject; + QScriptContextPrivate *ctx = d->currentContext(); + while (ctx->parentContext() != 0) + ctx = ctx->parentContext(); + if (QScriptEnginePrivate::strictlyEquals(ctx->m_thisObject, old)) + ctx->m_thisObject = objectImpl; + if (QScriptEnginePrivate::strictlyEquals(ctx->m_activation, old)) + ctx->m_activation = objectImpl; + if (QScriptEnginePrivate::strictlyEquals(ctx->m_scopeChain, old)) + ctx->m_scopeChain = objectImpl; + + d->m_globalObject = objectImpl; +} + +/*! + Returns a QScriptValue of the primitive type Null. + + \sa undefinedValue() +*/ +QScriptValue QScriptEngine::nullValue() +{ + Q_D(QScriptEngine); + return d->toPublic(d->nullValue()); +} + +/*! + Returns a QScriptValue of the primitive type Undefined. + + \sa nullValue() +*/ +QScriptValue QScriptEngine::undefinedValue() +{ + Q_D(QScriptEngine); + return d->toPublic(d->undefinedValue()); +} + +/*! + Creates a constructor function from \a fun, with the given \a length. + The \c{prototype} property of the resulting function is set to be the + given \a prototype. The \c{constructor} property of \a prototype is + set to be the resulting function. + + When a function is called as a constructor (e.g. \c{new Foo()}), the + `this' object associated with the function call is the new object + that the function is expected to initialize; the prototype of this + default constructed object will be the function's public + \c{prototype} property. If you always want the function to behave as + a constructor (e.g. \c{Foo()} should also create a new object), or + if you need to create your own object rather than using the default + `this' object, you should make sure that the prototype of your + object is set correctly; either by setting it manually, or, when + wrapping a custom type, by having registered the defaultPrototype() + of that type. Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9 + + To wrap a custom type and provide a constructor for it, you'd typically + do something like this: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10 +*/ +QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, + const QScriptValue &prototype, + int length) +{ + Q_D(QScriptEngine); + QScriptValueImpl v = d->createFunction(new QScript::CFunction(fun, length)); + QScriptValueImpl proto = d->toImpl(prototype); + v.setProperty(d->idTable()->id_prototype, proto, + QScriptValue::Undeletable); + proto.setProperty(d->idTable()->id_constructor, v, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + return d->toPublic(v); +} + +#ifndef QT_NO_REGEXP +/*! + Creates a QtScript object of class RegExp with the given + \a regexp. + + \sa QScriptValue::toRegExp() +*/ +QScriptValue QScriptEngine::newRegExp(const QRegExp ®exp) +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->regexpConstructor->newRegExp(&v, regexp); + return d->toPublic(v); +} + +#endif // QT_NO_REGEXP + +/*! + Creates a QtScript object holding the given variant \a value. + + If a default prototype has been registered with the meta type id of + \a value, then the prototype of the created object will be that + prototype; otherwise, the prototype will be the Object prototype + object. + + \sa setDefaultPrototype(), QScriptValue::toVariant() +*/ +QScriptValue QScriptEngine::newVariant(const QVariant &value) +{ + Q_D(QScriptEngine); + QScriptValueImpl result; + d->newVariant(&result, value); + return d->toPublic(result); +} + +/*! + \since 4.4 + \overload + + Initializes the given Qt Script \a object to hold the given variant + \a value, and returns the \a object. + + This function enables you to "promote" a plain Qt Script object + (created by the newObject() function) to a variant, or to replace + the variant contained inside an object previously created by the + newVariant() function. + + The prototype() of the \a object will remain unchanged. + + If \a object is not an object, this function behaves like the normal + newVariant(), i.e. it creates a new script object and returns it. + + This function is useful when you want to provide a script + constructor for a C++ type. If your constructor is invoked in a + \c{new} expression (QScriptContext::isCalledAsConstructor() returns + true), you can pass QScriptContext::thisObject() (the default + constructed script object) to this function to initialize the new + object. +*/ +QScriptValue QScriptEngine::newVariant(const QScriptValue &object, + const QVariant &value) +{ + Q_D(QScriptEngine); + QScriptValuePrivate *p = QScriptValuePrivate::get(object); + if (!p || !p->value.isObject()) + return newVariant(value); + if (p->value.isVariant()) + p->value.setVariantValue(value); + else + d->newVariant(&p->value, value, /*setDefaultPrototype=*/false); + return object; +} + +#ifndef QT_NO_QOBJECT +/*! + Creates a QtScript object that wraps the given QObject \a + object, using the given \a ownership. The given \a options control + various aspects of the interaction with the resulting script object. + + Signals and slots, properties and children of \a object are + available as properties of the created QScriptValue. For more + information, see the \l{QtScript} documentation. + + If \a object is a null pointer, this function returns nullValue(). + + If a default prototype has been registered for the \a object's class + (or its superclass, recursively), the prototype of the new script + object will be set to be that default prototype. + + If the given \a object is deleted outside of QtScript's control, any + attempt to access the deleted QObject's members through the QtScript + wrapper object (either by script code or C++) will result in a + script exception. + + \sa QScriptValue::toQObject() +*/ +QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership, + const QObjectWrapOptions &options) +{ + Q_D(QScriptEngine); + QScriptValueImpl result; + d->newQObject(&result, object, ownership, options); + return d->toPublic(result); +} + +/*! + \since 4.4 + \overload + + Initializes the given \a scriptObject to hold the given \a qtObject, + and returns the \a scriptObject. + + This function enables you to "promote" a plain Qt Script object + (created by the newObject() function) to a QObject proxy, or to + replace the QObject contained inside an object previously created by + the newQObject() function. + + The prototype() of the \a scriptObject will remain unchanged. + + If \a scriptObject is not an object, this function behaves like the + normal newQObject(), i.e. it creates a new script object and returns + it. + + This function is useful when you want to provide a script + constructor for a QObject-based class. If your constructor is + invoked in a \c{new} expression + (QScriptContext::isCalledAsConstructor() returns true), you can pass + QScriptContext::thisObject() (the default constructed script object) + to this function to initialize the new object. +*/ +QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject, + QObject *qtObject, + ValueOwnership ownership, + const QObjectWrapOptions &options) +{ + Q_D(QScriptEngine); + QScriptValuePrivate *p = QScriptValuePrivate::get(scriptObject); + if (!p || !p->value.isObject()) + return newQObject(qtObject, ownership, options); + if (p->value.isVariant()) { + QScript::ExtQObject::Instance *data; + data = d->qobjectConstructor->get(p->value); + Q_ASSERT(data != 0); + data->value = qtObject; + data->ownership = ownership; + data->options = options; + } else { + d->newQObject(&p->value, qtObject, ownership, options, + /*setDefaultPrototype=*/false); + } + return scriptObject; +} + +#endif // QT_NO_QOBJECT + +/*! + Creates a QtScript object of class Object. + + The prototype of the created object will be the Object + prototype object. + + \sa newArray(), QScriptValue::setProperty() +*/ +QScriptValue QScriptEngine::newObject() +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->newObject(&v, d->objectConstructor->publicPrototype); + return d->toPublic(v); +} + +/*! + \since 4.4 + \overload + + Creates a QtScript Object of the given class, \a scriptClass. + + The prototype of the created object will be the Object + prototype object. + + \a data, if specified, is set as the internal data of the + new object (using QScriptValue::setData()). + + \sa QScriptValue::scriptClass() +*/ +QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass, + const QScriptValue &data) +{ + Q_D(QScriptEngine); + return d->toPublic(d->newObject(scriptClass, d->toImpl(data))); +} + +/*! + \internal +*/ +QScriptValue QScriptEngine::newActivationObject() +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->newActivation(&v); + return d->toPublic(v); +} + +/*! + Creates a QScriptValue that wraps a native (C++) function. \a fun + must be a C++ function with signature QScriptEngine::FunctionSignature. \a + length is the number of arguments that \a fun expects; this becomes + the \c{length} property of the created QScriptValue. + + Note that \a length only gives an indication of the number of + arguments that the function expects; an actual invocation of a + function can include any number of arguments. You can check the + \l{QScriptContext::argumentCount()}{argumentCount()} of the + QScriptContext associated with the invocation to determine the + actual number of arguments passed. + + A \c{prototype} property is automatically created for the resulting + function object, to provide for the possibility that the function + will be used as a constructor. + + By combining newFunction() and the property flags + QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you + can create script object properties that behave like normal + properties in script code, but are in fact accessed through + functions (analogous to how properties work in \l{Qt's Property + System}). Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11 + + When the property \c{foo} of the script object is subsequently + accessed in script code, \c{getSetFoo()} will be invoked to handle + the access. In this particular case, we chose to store the "real" + value of \c{foo} as a property of the accessor function itself; you + are of course free to do whatever you like in this function. + + In the above example, a single native function was used to handle + both reads and writes to the property; the argument count is used to + determine if we are handling a read or write. You can also use two + separate functions; just specify the relevant flag + (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when + setting the property, e.g.: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12 + + \sa QScriptValue::call() +*/ +QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length) +{ + Q_D(QScriptEngine); + QScriptValueImpl v = d->createFunction(new QScript::CFunction(fun, length)); + QScriptValueImpl prototype = d->newObject(); + v.setProperty(d->idTable()->id_prototype, prototype, QScriptValue::Undeletable); + prototype.setProperty(d->idTable()->id_constructor, v, + QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + return d->toPublic(v); +} + +/*! + \internal + \since 4.4 +*/ +QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg) +{ + Q_D(QScriptEngine); + QScriptValueImpl v = d->createFunction(new QScript::C3Function(fun, arg, /*length=*/0)); + QScriptValueImpl prototype = d->newObject(); + v.setProperty(d->idTable()->id_prototype, prototype, QScriptValue::Undeletable); + prototype.setProperty(d->idTable()->id_constructor, v, + QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + return d->toPublic(v); +} + +/*! + Creates a QtScript object of class Array with the given \a length. + + \sa newObject() +*/ +QScriptValue QScriptEngine::newArray(uint length) +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + QScript::Array a(d); + a.resize(length); + d->newArray(&v, a); + return d->toPublic(v); +} + +/*! + Creates a QtScript object of class RegExp with the given + \a pattern and \a flags. + + The legal flags are 'g' (global), 'i' (ignore case), and 'm' + (multiline). +*/ +QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags) +{ + Q_D(QScriptEngine); + int bitflags = 0; + for (int i = 0; i < flags.size(); ++i) + bitflags |= QScript::Ecma::RegExp::flagFromChar(flags.at(i)); + QScriptValueImpl v; + d->regexpConstructor->newRegExp(&v, pattern, bitflags); + return d->toPublic(v); +} + +/*! + Creates a QtScript object of class Date with the given + \a value (the number of milliseconds since 01 January 1970, + UTC). +*/ +QScriptValue QScriptEngine::newDate(qsreal value) +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->dateConstructor->newDate(&v, value); + return d->toPublic(v); +} + +/*! + Creates a QtScript object of class Date from the given \a value. + + \sa QScriptValue::toDateTime() +*/ +QScriptValue QScriptEngine::newDate(const QDateTime &value) +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->dateConstructor->newDate(&v, value); + return d->toPublic(v); +} + +#ifndef QT_NO_QOBJECT +/*! + Creates a QtScript object that represents a QObject class, using the + the given \a metaObject and constructor \a ctor. + + Enums of \a metaObject (declared with Q_ENUMS) are available as + properties of the created QScriptValue. When the class is called as + a function, \a ctor will be called to create a new instance of the + class. + + Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 27 + + \sa newQObject(), scriptValueFromQMetaObject() +*/ +QScriptValue QScriptEngine::newQMetaObject( + const QMetaObject *metaObject, const QScriptValue &ctor) +{ + Q_D(QScriptEngine); + QScriptValueImpl v; + d->qmetaObjectConstructor->newQMetaObject(&v, metaObject, d->toImpl(ctor)); + return d->toPublic(v); +} + +/*! + \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject() + + Creates a QScriptValue that represents the Qt class \c{T}. + + This function is used in combination with one of the + Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 13 + + \warning This function is not available with MSVC 6. Use + qScriptValueFromQMetaObject() instead if you need to support that version + of the compiler. + + \sa QScriptEngine::newQMetaObject() +*/ + +/*! + \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine) + \since 4.3 + \relates QScriptEngine + + Uses \a engine to create a QScriptValue that represents the Qt class + \c{T}. + + This function is equivalent to + QScriptEngine::scriptValueFromQMetaObject(). It is provided as a + work-around for MSVC 6, which doesn't support member template + functions. + + \sa QScriptEngine::newQMetaObject() +*/ +#endif // QT_NO_QOBJECT + +/*! + \obsolete + + Returns true if \a program can be evaluated; i.e. the code is + sufficient to determine whether it appears to be a syntactically + correct program, or contains a syntax error. + + This function returns false if \a program is incomplete; i.e. the + input is syntactically correct up to the point where the input is + terminated. + + Note that this function only does a static check of \a program; + e.g. it does not check whether references to variables are + valid, and so on. + + A typical usage of canEvaluate() is to implement an interactive + interpreter for QtScript. The user is repeatedly queried for + individual lines of code; the lines are concatened internally, and + only when canEvaluate() returns true for the resulting program is it + passed to evaluate(). + + The following are some examples to illustrate the behavior of + canEvaluate(). (Note that all example inputs are assumed to have an + explicit newline as their last character, since otherwise the + QtScript parser would automatically insert a semi-colon character at + the end of the input, and this could cause canEvaluate() to produce + different results.) + + Given the input + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 14 + canEvaluate() will return true, since the program appears to be complete. + + Given the input + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 15 + canEvaluate() will return false, since the if-statement is not complete, + but is syntactically correct so far. + + Given the input + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 16 + canEvaluate() will return true, but evaluate() will throw a + SyntaxError given the same input. + + Given the input + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 17 + canEvaluate() will return true, even though the code is clearly not + syntactically valid QtScript code. evaluate() will throw a + SyntaxError when this code is evaluated. + + Given the input + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 18 + canEvaluate() will return true, but evaluate() will throw a + ReferenceError if \c{foo} is not defined in the script + environment. + + \sa evaluate(), checkSyntax() +*/ +bool QScriptEngine::canEvaluate(const QString &program) const +{ + return QScriptEnginePrivate::canEvaluate(program); +} + +/*! + \since 4.5 + + Checks the syntax of the given \a program. Returns a + QScriptSyntaxCheckResult object that contains the result of the check. +*/ +QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program) +{ + return QScriptEnginePrivate::checkSyntax(program); +} + +/*! + Evaluates \a program, using \a lineNumber as the base line number, + and returns the result of the evaluation. + + The script code will be evaluated in the current context. + + The evaluation of \a program can cause an exception in the + engine; in this case the return value will be the exception + that was thrown (typically an \c{Error} object). You can call + hasUncaughtException() to determine if an exception occurred in + the last call to evaluate(). + + \a lineNumber is used to specify a starting line number for \a + program; line number information reported by the engine that pertain + to this evaluation (e.g. uncaughtExceptionLineNumber()) will be + based on this argument. For example, if \a program consists of two + lines of code, and the statement on the second line causes a script + exception, uncaughtExceptionLineNumber() would return the given \a + lineNumber plus one. When no starting line number is specified, line + numbers will be 1-based. + + \a fileName is used for error reporting. For example in error objects + the file name is accessible through the "fileName" property if it's + provided with this function. + + \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation() +*/ +QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber) +{ + Q_D(QScriptEngine); + QScriptContextPrivate *ctx_p = d->currentContext(); + d->evaluate(ctx_p, program, lineNumber, fileName); + return d->toPublic(ctx_p->m_result); +} + +/*! + Returns the current context. + + The current context is typically accessed to retrieve the arguments + and `this' object in native functions; for convenience, it is + available as the first argument in QScriptEngine::FunctionSignature. +*/ +QScriptContext *QScriptEngine::currentContext() const +{ + Q_D(const QScriptEngine); + return QScriptContextPrivate::get(d->currentContext()); +} + +/*! + Enters a new execution context and returns the associated + QScriptContext object. + + Once you are done with the context, you should call popContext() to + restore the old context. + + By default, the `this' object of the new context is the Global Object. + The context's \l{QScriptContext::callee()}{callee}() will be invalid. + + This function is useful when you want to evaluate script code + as if it were the body of a function. You can use the context's + \l{QScriptContext::activationObject()}{activationObject}() to initialize + local variables that will be available to scripts. Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 19 + + In the above example, the new variable "tmp" defined in the script + will be local to the context; in other words, the script doesn't + have any effect on the global environment. + + \sa popContext() +*/ +QScriptContext *QScriptEngine::pushContext() +{ + Q_D(QScriptEngine); + QScriptContextPrivate *ctx_p = d->pushContext(); + ctx_p->setThisObject(d->globalObject()); + QScriptValueImpl activation; + d->newActivation(&activation); + activation.setScope(d->globalObject()); + ctx_p->setActivationObject(activation); + return QScriptContextPrivate::get(ctx_p); +} + +/*! + Pops the current execution context and restores the previous one. + This function must be used in conjunction with pushContext(). + + \sa pushContext() +*/ +void QScriptEngine::popContext() +{ + Q_D(QScriptEngine); + if (d->currentContext() && d->currentContext()->parentContext()) + d->popContext(); +} + +/*! + Returns true if the last script evaluation resulted in an uncaught + exception; otherwise returns false. + + The exception state is cleared when evaluate() is called. + + \sa uncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +bool QScriptEngine::hasUncaughtException() const +{ + Q_D(const QScriptEngine); + return d->hasUncaughtException(); +} + +/*! + Returns the current uncaught exception, or an invalid QScriptValue + if there is no uncaught exception. + + The exception value is typically an \c{Error} object; in that case, + you can call toString() on the return value to obtain an error + message. + + \sa hasUncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +QScriptValue QScriptEngine::uncaughtException() const +{ + Q_D(const QScriptEngine); + return const_cast<QScriptEnginePrivate*>(d)->toPublic(d->uncaughtException()); +} + +/*! + Returns the line number where the last uncaught exception occurred. + + Line numbers are 1-based, unless a different base was specified as + the second argument to evaluate(). + + \sa hasUncaughtException(), uncaughtExceptionBacktrace() +*/ +int QScriptEngine::uncaughtExceptionLineNumber() const +{ + return QScriptContextPrivate::get(currentContext())->errorLineNumber; +} + +/*! + Returns a human-readable backtrace of the last uncaught exception. + + Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}. + + \sa uncaughtException() +*/ +QStringList QScriptEngine::uncaughtExceptionBacktrace() const +{ + Q_D(const QScriptEngine); + return d->uncaughtExceptionBacktrace(); +} + +/*! + \since 4.4 + + Clears any uncaught exceptions in this engine. + + \sa hasUncaughtException() +*/ +void QScriptEngine::clearExceptions() +{ + Q_D(QScriptEngine); + d->clearExceptions(); +} + +/*! + Returns the default prototype associated with the given \a metaTypeId, + or an invalid QScriptValue if no default prototype has been set. + + \sa setDefaultPrototype() +*/ +QScriptValue QScriptEngine::defaultPrototype(int metaTypeId) const +{ + Q_D(const QScriptEngine); + return const_cast<QScriptEnginePrivate*>(d)->toPublic(d->defaultPrototype(metaTypeId)); +} + +/*! + Sets the default prototype of the C++ type identified by the given + \a metaTypeId to \a prototype. + + The default prototype provides a script interface for values of + type \a metaTypeId when a value of that type is accessed from script + code. Whenever the script engine (implicitly or explicitly) creates + a QScriptValue from a value of type \a metaTypeId, the default + prototype will be set as the QScriptValue's prototype. + + The \a prototype object itself may be constructed using one of two + principal techniques; the simplest is to subclass QScriptable, which + enables you to define the scripting API of the type through QObject + properties and slots. Another possibility is to create a script + object by calling newObject(), and populate the object with the + desired properties (e.g. native functions wrapped with + newFunction()). + + \sa defaultPrototype(), qScriptRegisterMetaType(), QScriptable, {Default Prototypes Example} +*/ +void QScriptEngine::setDefaultPrototype(int metaTypeId, const QScriptValue &prototype) +{ + Q_D(QScriptEngine); + d->setDefaultPrototype(metaTypeId, d->toImpl(prototype)); +} + +/*! + \typedef QScriptEngine::FunctionSignature + \relates QScriptEngine + + The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}. + + A function with such a signature can be passed to + QScriptEngine::newFunction() to wrap the function. +*/ + +/*! + \typedef QScriptEngine::FunctionWithArgSignature + \relates QScriptEngine + + The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}. + + A function with such a signature can be passed to + QScriptEngine::newFunction() to wrap the function. +*/ + +/*! + \typedef QScriptEngine::MarshalFunction + \internal +*/ + +/*! + \typedef QScriptEngine::DemarshalFunction + \internal +*/ + +/*! + \internal +*/ +QScriptValue QScriptEngine::create(int type, const void *ptr) +{ + Q_D(QScriptEngine); + return d->toPublic(d->create(type, ptr)); +} + +/*! + \internal +*/ +bool QScriptEngine::convert(const QScriptValue &value, int type, void *ptr) +{ + Q_D(QScriptEngine); + return QScriptEnginePrivate::convert(d->toImpl(value), type, ptr, d); +} + +/*! + \internal +*/ +bool QScriptEngine::convertV2(const QScriptValue &value, int type, void *ptr) +{ + QScriptValueImpl impl = QScriptValuePrivate::valueOf(value); + return QScriptEnginePrivate::convert(impl, type, ptr, /*engine=*/0); +} + +/*! + \internal +*/ +void QScriptEngine::registerCustomType(int type, MarshalFunction mf, + DemarshalFunction df, + const QScriptValue &prototype) +{ + Q_D(QScriptEngine); + QScriptCustomTypeInfo info = d->m_customTypes.value(type); + info.marshal = mf; + info.demarshal = df; + info.prototype = d->toImpl(prototype); + d->m_customTypes.insert(type, info); +} + +/*! + \since 4.5 + + Installs translator functions on the given \a object, or on the Global + Object if no object is specified. + + The relation between Qt Script translator functions and C++ translator + functions is described in the following table: + + \table + \header \o Script Function \o Corresponding C++ Function + \row \o qsTr() \o QObject::tr() + \row \o QT_TR_NOOP() \o QT_TR_NOOP() + \row \o qsTranslate() \o QCoreApplication::translate() + \row \o QT_TRANSLATE_NOOP() \o QT_TRANSLATE_NOOP() + \endtable + + \sa {Internationalization with Qt} +*/ +void QScriptEngine::installTranslatorFunctions(const QScriptValue &object) +{ + Q_D(QScriptEngine); + QScriptValue target = object.isObject() ? object : globalObject(); + QScriptValueImpl impl = QScriptValuePrivate::valueOf(target); + d->installTranslatorFunctions(impl); +} + +/*! + Imports the given \a extension into this QScriptEngine. Returns + undefinedValue() if the extension was successfully imported. You + can call hasUncaughtException() to check if an error occurred; in + that case, the return value is the value that was thrown by the + exception (usually an \c{Error} object). + + QScriptEngine ensures that a particular extension is only imported + once; subsequent calls to importExtension() with the same extension + name will do nothing and return undefinedValue(). + + \sa availableExtensions(), QScriptExtensionPlugin, {Creating QtScript Extensions} +*/ +QScriptValue QScriptEngine::importExtension(const QString &extension) +{ + Q_D(QScriptEngine); + return d->toPublic(d->importExtension(extension)); +} + +/*! + \since 4.4 + + Returns a list naming the available extensions that can be + imported using the importExtension() function. This list includes + extensions that have been imported. + + \sa importExtension(), importedExtensions() +*/ +QStringList QScriptEngine::availableExtensions() const +{ + Q_D(const QScriptEngine); + return d->availableExtensions(); +} + +/*! + \since 4.4 + + Returns a list naming the extensions that have been imported + using the importExtension() function. + + \sa availableExtensions() +*/ +QStringList QScriptEngine::importedExtensions() const +{ + Q_D(const QScriptEngine); + return d->importedExtensions(); +} + +/*! \fn QScriptValue QScriptEngine::toScriptValue(const T &value) + + Creates a QScriptValue with the given \a value. + + Note that the template type \c{T} must be known to QMetaType. + + See \l{Conversion Between QtScript and C++ Types} for a + description of the built-in type conversion provided by + QtScript. By default, the types that are not specially handled by + QtScript are represented as QVariants (e.g. the \a value is passed + to newVariant()); you can change this behavior by installing your + own type conversion functions with qScriptRegisterMetaType(). + + \warning This function is not available with MSVC 6. Use + qScriptValueFromValue() instead if you need to support that + version of the compiler. + + \sa fromScriptValue(), qScriptRegisterMetaType() +*/ + +/*! \fn T QScriptEngine::fromScriptValue(const QScriptValue &value) + + Returns the given \a value converted to the template type \c{T}. + + Note that \c{T} must be known to QMetaType. + + See \l{Conversion Between QtScript and C++ Types} for a + description of the built-in type conversion provided by + QtScript. + + \warning This function is not available with MSVC 6. Use + qScriptValueToValue() or qscriptvalue_cast() instead if you need + to support that version of the compiler. + + \sa toScriptValue(), qScriptRegisterMetaType() +*/ + +/*! + \fn QScriptValue qScriptValueFromValue(QScriptEngine *engine, const T &value) + \since 4.3 + \relates QScriptEngine + + Creates a QScriptValue using the given \a engine with the given \a + value of template type \c{T}. + + This function is equivalent to QScriptEngine::toScriptValue(). + It is provided as a work-around for MSVC 6, which doesn't support + member template functions. + + \sa qScriptValueToValue() +*/ + +/*! + \fn T qScriptValueToValue<T>(const QScriptValue &value) + \since 4.3 + \relates QScriptEngine + + Returns the given \a value converted to the template type \c{T}. + + This function is equivalent to QScriptEngine::fromScriptValue(). + It is provided as a work-around for MSVC 6, which doesn't + support member template functions. + + \sa qScriptValueFromValue() +*/ + +/*! + \fn QScriptValue qScriptValueFromSequence(QScriptEngine *engine, const Container &container) + \since 4.3 + \relates QScriptEngine + + Creates an array in the form of a QScriptValue using the given \a engine + with the given \a container of template type \c{Container}. + + The \c Container type must provide a \c const_iterator class to enable the + contents of the container to be copied into the array. + + Additionally, the type of each element in the sequence should be suitable + for conversion to a QScriptValue. + See \l{QtScript Module#Conversion Between QtScript and C++ Types} + {Conversion Between QtScript and C++ Types} for more information about the + restrictions on types that can be used with QScriptValue. + + \sa qScriptValueFromValue() +*/ + +/*! + \fn void qScriptValueToSequence(const QScriptValue &value, Container &container) + \since 4.3 + \relates QScriptEngine + + Copies the elements in the sequence specified by \a value to the given + \a container of template type \c{Container}. + + The \a value used is typically an array, but any container can be copied + as long as it provides a \c length property describing how many elements + it contains. + + Additionally, the type of each element in the sequence must be suitable + for conversion to a C++ type from a QScriptValue. + See \l{QtScript Module#Conversion Between QtScript and C++ Types} + {Conversion Between QtScript and C++ Types} for more information about the + restrictions on types that can be used with QScriptValue. + + \sa qscriptvalue_cast() +*/ + +/*! + \fn T qscriptvalue_cast<T>(const QScriptValue &value) + \since 4.3 + \relates QScriptValue + + Returns the given \a value converted to the template type \c{T}. + + \sa qScriptRegisterMetaType(), QScriptEngine::toScriptValue() +*/ + +/*! \fn int qScriptRegisterMetaType( + QScriptEngine *engine, + QScriptValue (*toScriptValue)(QScriptEngine *, const T &t), + void (*fromScriptValue)(const QScriptValue &, T &t), + const QScriptValue &prototype = QScriptValue()) + \relates QScriptEngine + + Registers the type \c{T} in the given \a engine. \a toScriptValue must + be a function that will convert from a value of type \c{T} to a + QScriptValue, and \a fromScriptValue a function that does the + opposite. \a prototype, if valid, is the prototype that's set on + QScriptValues returned by \a toScriptValue. + + Returns the internal ID used by QMetaType. + + You only need to call this function if you want to provide custom + conversion of values of type \c{T}, i.e. if the default + QVariant-based representation and conversion is not + appropriate. (Note that custom QObject-derived types also fall in + this category; e.g. for a QObject-derived class called MyObject, + you probably want to define conversion functions for MyObject* + that utilize QScriptEngine::newQObject() and + QScriptValue::toQObject().) + + If you only want to define a common script interface for values of + type \c{T}, and don't care how those values are represented + (i.e. storing them in QVariants is fine), use + \l{QScriptEngine::setDefaultPrototype()}{setDefaultPrototype}() + instead; this will minimize conversion costs. + + You need to declare the custom type first with + Q_DECLARE_METATYPE(). + + After a type has been registered, you can convert from a + QScriptValue to that type using + \l{QScriptEngine::fromScriptValue()}{fromScriptValue}(), and + create a QScriptValue from a value of that type using + \l{QScriptEngine::toScriptValue()}{toScriptValue}(). The engine + will take care of calling the proper conversion function when + calling C++ slots, and when getting or setting a C++ property; + i.e. the custom type may be used seamlessly on both the C++ side + and the script side. + + The following is an example of how to use this function. We will + specify custom conversion of our type \c{MyStruct}. Here's the C++ + type: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 20 + + We must declare it so that the type will be known to QMetaType: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 21 + + Next, the \c{MyStruct} conversion functions. We represent the + \c{MyStruct} value as a script object and just copy the properties: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 22 + + Now we can register \c{MyStruct} with the engine: + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 23 + + Working with \c{MyStruct} values is now easy: + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 24 + + If you want to be able to construct values of your custom type + from script code, you have to register a constructor function for + the type. For example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 25 + + \sa qScriptRegisterSequenceMetaType(), qRegisterMetaType() +*/ + +/*! + \macro Q_SCRIPT_DECLARE_QMETAOBJECT(QMetaObject, ArgType) + \since 4.3 + \relates QScriptEngine + + Declares the given \a QMetaObject. Used in combination with + QScriptEngine::scriptValueFromQMetaObject() to make enums and + instantiation of \a QMetaObject available to script code. The + constructor generated by this macro takes a single argument of + type \a ArgType; typically the argument is the parent type of the + new instance, in which case \a ArgType is \c{QWidget*} or + \c{QObject*}. Objects created by the constructor will have + QScriptEngine::AutoOwnership ownership. +*/ + +/*! \fn int qScriptRegisterSequenceMetaType( + QScriptEngine *engine, + const QScriptValue &prototype = QScriptValue()) + \relates QScriptEngine + + Registers the sequence type \c{T} in the given \a engine. This + function provides conversion functions that convert between \c{T} + and Qt Script \c{Array} objects. \c{T} must provide a + const_iterator class and begin(), end() and push_back() + functions. If \a prototype is valid, it will be set as the + prototype of \c{Array} objects due to conversion from \c{T}; + otherwise, the standard \c{Array} prototype will be used. + + Returns the internal ID used by QMetaType. + + You need to declare the container type first with + Q_DECLARE_METATYPE(). If the element type isn't a standard Qt/C++ + type, it must be declared using Q_DECLARE_METATYPE() as well. + Example: + + \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 26 + + \sa qScriptRegisterMetaType() +*/ + +/*! + Runs the garbage collector. + + The garbage collector will attempt to reclaim memory by locating and + disposing of objects that are no longer reachable in the script + environment. + + Normally you don't need to call this function; the garbage collector + will automatically be invoked when the QScriptEngine decides that + it's wise to do so (i.e. when a certain number of new objects have + been created). However, you can call this function to explicitly + request that garbage collection should be performed as soon as + possible. +*/ +void QScriptEngine::collectGarbage() +{ + Q_D(QScriptEngine); + d->gc(); +} + +/*! + + Sets the interval between calls to QCoreApplication::processEvents + to \a interval milliseconds. + + While the interpreter is running, all event processing is by default + blocked. This means for instance that the gui will not be updated + and timers will not be fired. To allow event processing during + interpreter execution one can specify the processing interval to be + a positive value, indicating the number of milliseconds between each + time QCoreApplication::processEvents() is called. + + The default value is -1, which disables event processing during + interpreter execution. + + You can use QCoreApplication::postEvent() to post an event that + performs custom processing at the next interval. For example, you + could keep track of the total running time of the script and call + abortEvaluation() when you detect that the script has been running + for a long time without completing. + + \sa processEventsInterval() +*/ +void QScriptEngine::setProcessEventsInterval(int interval) +{ + Q_D(QScriptEngine); + d->m_processEventsInterval = interval; +} + +/*! + + Returns the interval in milliseconds between calls to + QCoreApplication::processEvents() while the interpreter is running. + + \sa setProcessEventsInterval() +*/ +int QScriptEngine::processEventsInterval() const +{ + Q_D(const QScriptEngine); + return d->m_processEventsInterval; +} + +/*! + \since 4.4 + + Returns true if this engine is currently evaluating a script, + otherwise returns false. + + \sa evaluate(), abortEvaluation() +*/ +bool QScriptEngine::isEvaluating() const +{ + Q_D(const QScriptEngine); + return d->m_evaluating; +} + +/*! + \since 4.4 + + Aborts any script evaluation currently taking place in this engine. + The given \a result is passed back as the result of the evaluation + (i.e. it is returned from the call to evaluate() being aborted). + + If the engine isn't evaluating a script (i.e. isEvaluating() returns + false), this function does nothing. + + Call this function if you need to abort a running script for some + reason, e.g. when you have detected that the script has been + running for several seconds without completing. + + \sa evaluate(), isEvaluating(), setProcessEventsInterval() +*/ +void QScriptEngine::abortEvaluation(const QScriptValue &result) +{ + Q_D(QScriptEngine); + d->abortEvaluation(d->toImpl(result)); +} + +#ifndef QT_NO_QOBJECT + +/*! + \since 4.4 + \relates QScriptEngine + + Creates a connection from the \a signal in the \a sender to the + given \a function. If \a receiver is an object, it will act as the + `this' object when the signal handler function is invoked. Returns + true if the connection succeeds; otherwise returns false. + + \sa qScriptDisconnect(), QScriptEngine::signalHandlerException() +*/ +bool qScriptConnect(QObject *sender, const char *signal, + const QScriptValue &receiver, const QScriptValue &function) +{ + if (!sender || !signal) + return false; + if (!function.isFunction()) + return false; + if (receiver.isObject() && (receiver.engine() != function.engine())) + return false; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(function.engine()); + return eng_p->scriptConnect(sender, signal, + eng_p->toImpl(receiver), + eng_p->toImpl(function)); +} + +/*! + \since 4.4 + \relates QScriptEngine + + Disconnects the \a signal in the \a sender from the given (\a + receiver, \a function) pair. Returns true if the connection is + successfully broken; otherwise returns false. + + \sa qScriptConnect() +*/ +bool qScriptDisconnect(QObject *sender, const char *signal, + const QScriptValue &receiver, const QScriptValue &function) +{ + if (!sender || !signal) + return false; + if (!function.isFunction()) + return false; + if (receiver.isObject() && (receiver.engine() != function.engine())) + return false; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(function.engine()); + return eng_p->scriptDisconnect(sender, signal, + eng_p->toImpl(receiver), + eng_p->toImpl(function)); +} + +/*! + \since 4.4 + \fn void QScriptEngine::signalHandlerException(const QScriptValue &exception) + + This signal is emitted when a script function connected to a signal causes + an \a exception. + + \sa qScriptConnect() +*/ + +QT_BEGIN_INCLUDE_NAMESPACE +#include "moc_qscriptengine.cpp" +QT_END_INCLUDE_NAMESPACE + +#endif // QT_NO_QOBJECT + +/*! + \since 4.4 + + Installs the given \a agent on this engine. The agent will be + notified of various events pertaining to script execution. This is + useful when you want to find out exactly what the engine is doing, + e.g. when evaluate() is called. The agent interface is the basis of + tools like debuggers and profilers. + + The engine maintains ownership of the \a agent. + + Calling this function will replace the existing agent, if any. + + \sa agent() +*/ +void QScriptEngine::setAgent(QScriptEngineAgent *agent) +{ + Q_D(QScriptEngine); + d->setAgent(agent); +} + +/*! + \since 4.4 + + Returns the agent currently installed on this engine, or 0 if no + agent is installed. + + \sa setAgent() +*/ +QScriptEngineAgent *QScriptEngine::agent() const +{ + Q_D(const QScriptEngine); + return d->agent(); +} + +/*! + \since 4.4 + + Returns a handle that represents the given string, \a str. + + QScriptString can be used to quickly look up properties, and + compare property names, of script objects. + + \sa QScriptValue::property() +*/ +QScriptString QScriptEngine::toStringHandle(const QString &str) +{ + Q_D(QScriptEngine); + return d->internedString(str); +} + +/*! + \since 4.5 + + Converts the given \a value to an object, if such a conversion is + possible; otherwise returns an invalid QScriptValue. The conversion + is performed according to the following table: + + \table + \header \o Input Type \o Result + \row \o Undefined \o An invalid QScriptValue. + \row \o Null \o An invalid QScriptValue. + \row \o Boolean \o A new Boolean object whose internal value is set to the value of the boolean. + \row \o Number \o A new Number object whose internal value is set to the value of the number. + \row \o String \o A new String object whose internal value is set to the value of the string. + \row \o Object \o The result is the object itself (no conversion). + \endtable + + \sa newObject() +*/ +QScriptValue QScriptEngine::toObject(const QScriptValue &value) +{ + Q_D(QScriptEngine); + return d->toPublic(d->toObject(d->toImpl(value))); +} + +/*! + \internal + + Returns the object with the given \a id, or an invalid + QScriptValue if there is no object with that id. + + \sa QScriptValue::objectId() +*/ +QScriptValue QScriptEngine::objectById(qint64 id) const +{ + Q_D(const QScriptEngine); + return const_cast<QScriptEnginePrivate*>(d)->toPublic(d->objectById(id)); +} + +/*! + \since 4.5 + \class QScriptSyntaxCheckResult + + \brief The QScriptSyntaxCheckResult class provides the result of a script syntax check. + + \ingroup script + \mainclass + + QScriptSyntaxCheckResult is returned by QScriptEngine::checkSyntax() to + provide information about the syntactical (in)correctness of a script. +*/ + +/*! + \enum QScriptSyntaxCheckResult::State + + This enum specifies the state of a syntax check. + + \value Error The program contains a syntax error. + \value Intermediate The program is incomplete. + \value Valid The program is a syntactically correct Qt Script program. +*/ + +/*! + Constructs a new QScriptSyntaxCheckResult from the \a other result. +*/ +QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult &other) + : d_ptr(other.d_ptr) +{ + if (d_ptr) + d_ptr->ref.ref(); +} + +/*! + \internal +*/ +QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate *d) + : d_ptr(d) +{ + if (d_ptr) + d_ptr->ref.ref(); +} + +/*! + \internal +*/ +QScriptSyntaxCheckResult::QScriptSyntaxCheckResult() + : d_ptr(0) +{ +} + +/*! + Destroys this QScriptSyntaxCheckResult. +*/ +QScriptSyntaxCheckResult::~QScriptSyntaxCheckResult() +{ + if (d_ptr && !d_ptr->ref.deref()) { + delete d_ptr; + d_ptr = 0; + } +} + +/*! + Returns the state of this QScriptSyntaxCheckResult. +*/ +QScriptSyntaxCheckResult::State QScriptSyntaxCheckResult::state() const +{ + Q_D(const QScriptSyntaxCheckResult); + return d->state; +} + +/*! + Returns the error line number of this QScriptSyntaxCheckResult, or -1 if + there is no error. + + \sa state(), errorMessage() +*/ +int QScriptSyntaxCheckResult::errorLineNumber() const +{ + Q_D(const QScriptSyntaxCheckResult); + return d->errorLineNumber; +} + +/*! + Returns the error column number of this QScriptSyntaxCheckResult, or -1 if + there is no error. + + \sa state(), errorLineNumber() +*/ +int QScriptSyntaxCheckResult::errorColumnNumber() const +{ + Q_D(const QScriptSyntaxCheckResult); + return d->errorColumnNumber; +} + +/*! + Returns the error message of this QScriptSyntaxCheckResult, or an empty + string if there is no error. + + \sa state(), errorLineNumber() +*/ +QString QScriptSyntaxCheckResult::errorMessage() const +{ + Q_D(const QScriptSyntaxCheckResult); + return d->errorMessage; +} + +/*! + Assigns the \a other result to this QScriptSyntaxCheckResult, and returns a + reference to this QScriptSyntaxCheckResult. +*/ +QScriptSyntaxCheckResult &QScriptSyntaxCheckResult::operator=(const QScriptSyntaxCheckResult &other) +{ + if (d_ptr == other.d_ptr) + return *this; + if (d_ptr && !d_ptr->ref.deref()) { + delete d_ptr; + d_ptr = 0; + } + d_ptr = other.d_ptr; + if (d_ptr) + d_ptr->ref.ref(); + return *this; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptengine.h b/src/script/qscriptengine.h new file mode 100644 index 0000000..afd551b --- /dev/null +++ b/src/script/qscriptengine.h @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** 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 QSCRIPTENGINE_H +#define QSCRIPTENGINE_H + +#include <QtCore/qmetatype.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qvariant.h> + +#ifndef QT_NO_QOBJECT +#include <QtCore/qobject.h> +#else +#include <QtCore/qobjectdefs.h> +#endif + +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QDateTime; +class QScriptClass; +class QScriptEngineAgent; +class QScriptEnginePrivate; + +#ifndef QT_NO_QOBJECT + +template <class T> +inline QScriptValue qscriptQMetaObjectConstructor(QScriptContext *, QScriptEngine *, T *) +{ + return QScriptValue(); +} + +#endif // QT_NO_QOBJECT + +#ifndef QT_NO_REGEXP +class QRegExp; +#endif + +#ifndef QT_NO_MEMBER_TEMPLATES +template <typename T> +inline QScriptValue qScriptValueFromValue(QScriptEngine *, const T &); + +template <typename T> +inline T qScriptValueToValue(const QScriptValue &); +#endif + +class QScriptSyntaxCheckResultPrivate; +class Q_SCRIPT_EXPORT QScriptSyntaxCheckResult +{ +public: + enum State { + Error, + Intermediate, + Valid + }; + + QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult &other); + ~QScriptSyntaxCheckResult(); + + State state() const; + int errorLineNumber() const; + int errorColumnNumber() const; + QString errorMessage() const; + + QScriptSyntaxCheckResult &operator=(const QScriptSyntaxCheckResult &other); + +private: + QScriptSyntaxCheckResult(); + QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate *d); + QScriptSyntaxCheckResultPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptSyntaxCheckResult) + friend class QScriptEnginePrivate; +}; + +class Q_SCRIPT_EXPORT QScriptEngine +#ifndef QT_NO_QOBJECT + : public QObject +#endif +{ +#ifndef QT_NO_QOBJECT + Q_OBJECT +#endif +public: + enum ValueOwnership { + QtOwnership, + ScriptOwnership, + AutoOwnership + }; + + enum QObjectWrapOption { + ExcludeChildObjects = 0x0001, + ExcludeSuperClassMethods = 0x0002, + ExcludeSuperClassProperties = 0x0004, + ExcludeSuperClassContents = 0x0006, + SkipMethodsInEnumeration = 0x0008, + ExcludeDeleteLater = 0x0010, + + AutoCreateDynamicProperties = 0x0100, + PreferExistingWrapperObject = 0x0200 + }; + Q_DECLARE_FLAGS(QObjectWrapOptions, QObjectWrapOption) + + QScriptEngine(); +#ifndef QT_NO_QOBJECT + explicit QScriptEngine(QObject *parent); +#endif + virtual ~QScriptEngine(); + + QScriptValue globalObject() const; + void setGlobalObject(const QScriptValue &object); + + QScriptContext *currentContext() const; + QScriptContext *pushContext(); + void popContext(); + + bool canEvaluate(const QString &program) const; + static QScriptSyntaxCheckResult checkSyntax(const QString &program); + + QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + + bool isEvaluating() const; + void abortEvaluation(const QScriptValue &result = QScriptValue()); + + bool hasUncaughtException() const; + QScriptValue uncaughtException() const; + int uncaughtExceptionLineNumber() const; + QStringList uncaughtExceptionBacktrace() const; + void clearExceptions(); + + QScriptValue nullValue(); + QScriptValue undefinedValue(); + + typedef QScriptValue (*FunctionSignature)(QScriptContext *, QScriptEngine *); + typedef QScriptValue (*FunctionWithArgSignature)(QScriptContext *, QScriptEngine *, void *); + + QScriptValue newFunction(FunctionSignature signature, int length = 0); + QScriptValue newFunction(FunctionSignature signature, const QScriptValue &prototype, int length = 0); + + QScriptValue newFunction(FunctionWithArgSignature signature, void *arg); + + QScriptValue newVariant(const QVariant &value); + QScriptValue newVariant(const QScriptValue &object, const QVariant &value); + +#ifndef QT_NO_REGEXP + QScriptValue newRegExp(const QRegExp ®exp); +#endif + + QScriptValue newObject(); + QScriptValue newObject(QScriptClass *scriptClass, const QScriptValue &data = QScriptValue()); + QScriptValue newArray(uint length = 0); + QScriptValue newRegExp(const QString &pattern, const QString &flags); + QScriptValue newDate(qsreal value); + QScriptValue newDate(const QDateTime &value); + QScriptValue newActivationObject(); + +#ifndef QT_NO_QOBJECT + QScriptValue newQObject(QObject *object, ValueOwnership ownership = QtOwnership, + const QObjectWrapOptions &options = 0); + QScriptValue newQObject(const QScriptValue &scriptObject, QObject *qtObject, + ValueOwnership ownership = QtOwnership, + const QObjectWrapOptions &options = 0); + + QScriptValue newQMetaObject(const QMetaObject *metaObject, const QScriptValue &ctor = QScriptValue()); + +# ifndef QT_NO_MEMBER_TEMPLATES + template <class T> QScriptValue scriptValueFromQMetaObject(); +# endif // QT_NO_MEMBER_TEMPLATES + +#endif // QT_NO_QOBJECT + + + + QScriptValue defaultPrototype(int metaTypeId) const; + void setDefaultPrototype(int metaTypeId, const QScriptValue &prototype); + + + typedef QScriptValue (*MarshalFunction)(QScriptEngine *, const void *); + typedef void (*DemarshalFunction)(const QScriptValue &, void *); + + + +#ifndef QT_NO_MEMBER_TEMPLATES + template <typename T> + inline QScriptValue toScriptValue(const T &value) + { + return qScriptValueFromValue(this, value); + } + template <typename T> + inline T fromScriptValue(const QScriptValue &value) + { + return qScriptValueToValue<T>(value); + } +#endif // QT_NO_MEMBER_TEMPLATES + + void installTranslatorFunctions(const QScriptValue &object = QScriptValue()); + + QScriptValue importExtension(const QString &extension); + QStringList availableExtensions() const; + QStringList importedExtensions() const; + + void collectGarbage(); + + void setProcessEventsInterval(int interval); + int processEventsInterval() const; + + void setAgent(QScriptEngineAgent *agent); + QScriptEngineAgent *agent() const; + + QScriptString toStringHandle(const QString &str); + QScriptValue toObject(const QScriptValue &value); + + QScriptValue objectById(qint64 id) const; + +#ifndef QT_NO_QOBJECT +Q_SIGNALS: + void signalHandlerException(const QScriptValue &exception); +#endif + +private: + QScriptValue create(int type, const void *ptr); + + bool convert(const QScriptValue &value, int type, void *ptr); + static bool convertV2(const QScriptValue &value, int type, void *ptr); + + void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, + const QScriptValue &prototype); + + friend inline void qScriptRegisterMetaType_helper(QScriptEngine *, + int, MarshalFunction, DemarshalFunction, const QScriptValue &); + + friend inline QScriptValue qScriptValueFromValue_helper(QScriptEngine *, int, const void *); + + friend inline bool qscriptvalue_cast_helper(const QScriptValue &, int, void *); + +protected: +#ifdef QT_NO_QOBJECT + QScriptEnginePrivate *d_ptr; + + QScriptEngine(QScriptEnginePrivate &dd); +#else + QScriptEngine(QScriptEnginePrivate &dd, QObject *parent = 0); +#endif + +private: + Q_DECLARE_PRIVATE(QScriptEngine) + Q_DISABLE_COPY(QScriptEngine) +#ifndef QT_NO_QOBJECT + Q_PRIVATE_SLOT(d_func(), void _q_objectDestroyed(QObject *)) +#endif +}; + +#ifndef QT_NO_QOBJECT +template <class T> +inline QScriptValue qScriptValueFromQMetaObject( + QScriptEngine *engine +#ifndef qdoc + , T * /* dummy */ = 0 +#endif + ) +{ + typedef QScriptValue(*ConstructPtr)(QScriptContext *, QScriptEngine *, T *); + ConstructPtr cptr = qscriptQMetaObjectConstructor<T>; + return engine->newQMetaObject(&T::staticMetaObject, + engine->newFunction(reinterpret_cast<QScriptEngine::FunctionWithArgSignature>(cptr), 0)); +} + +#define Q_SCRIPT_DECLARE_QMETAOBJECT(T, _Arg1) \ +template<> inline QScriptValue qscriptQMetaObjectConstructor<T>(QScriptContext *ctx, QScriptEngine *eng, T *) \ +{ \ + _Arg1 arg1 = qscriptvalue_cast<_Arg1> (ctx->argument(0)); \ + T* t = new T(arg1); \ + if (ctx->isCalledAsConstructor()) \ + return eng->newQObject(ctx->thisObject(), t, QScriptEngine::AutoOwnership); \ + QScriptValue o = eng->newQObject(t, QScriptEngine::AutoOwnership); \ + o.setPrototype(ctx->callee().property(QString::fromLatin1("prototype"))); \ + return o; \ +} + +# ifndef QT_NO_MEMBER_TEMPLATES + template <class T> QScriptValue QScriptEngine::scriptValueFromQMetaObject() + { + return qScriptValueFromQMetaObject<T>(this); + } +# endif // QT_NO_MEMBER_TEMPLATES + +#endif // QT_NO_QOBJECT + +inline QScriptValue qScriptValueFromValue_helper(QScriptEngine *engine, int type, const void *ptr) +{ + if (!engine) + return QScriptValue(); + + return engine->create(type, ptr); +} + +template <typename T> +inline QScriptValue qScriptValueFromValue(QScriptEngine *engine, const T &t) +{ + return qScriptValueFromValue_helper(engine, qMetaTypeId<T>(), &t); +} + +template <> +inline QScriptValue qScriptValueFromValue<QVariant>(QScriptEngine *engine, const QVariant &v) +{ + QScriptValue result = qScriptValueFromValue_helper(engine, v.userType(), v.data()); + if (!result.isValid()) + result = engine->newVariant(v); + return result; +} + +inline bool qscriptvalue_cast_helper(const QScriptValue &value, int type, void *ptr) +{ + return QScriptEngine::convertV2(value, type, ptr); +} + +template<typename T> +T qscriptvalue_cast(const QScriptValue &value +#if !defined qdoc && defined Q_CC_MSVC && _MSC_VER < 1300 +, T * = 0 +#endif + ) +{ + T t; + const int id = qMetaTypeId<T>(); + + if (qscriptvalue_cast_helper(value, id, &t)) + return t; + else if (value.isVariant()) + return qvariant_cast<T>(value.toVariant()); + + return T(); +} + +#if !defined Q_CC_MSVC || _MSC_VER >= 1300 +template <> +inline QVariant qscriptvalue_cast<QVariant>(const QScriptValue &value) +{ + return value.toVariant(); +} +#endif + +template <typename T> +inline T qScriptValueToValue(const QScriptValue &value) +{ + return qscriptvalue_cast<T>(value); +} + +inline void qScriptRegisterMetaType_helper(QScriptEngine *eng, int type, + QScriptEngine::MarshalFunction mf, + QScriptEngine::DemarshalFunction df, + const QScriptValue &prototype) +{ + eng->registerCustomType(type, mf, df, prototype); +} + +template<typename T> +int qScriptRegisterMetaType( + QScriptEngine *eng, + QScriptValue (*toScriptValue)(QScriptEngine *, const T &t), + void (*fromScriptValue)(const QScriptValue &, T &t), + const QScriptValue &prototype = QScriptValue() +#ifndef qdoc + , T * /* dummy */ = 0 +#endif +) +{ + const int id = qRegisterMetaType<T>(); // make sure it's registered + + qScriptRegisterMetaType_helper( + eng, id, reinterpret_cast<QScriptEngine::MarshalFunction>(toScriptValue), + reinterpret_cast<QScriptEngine::DemarshalFunction>(fromScriptValue), + prototype); + + return id; +} + +template <class Container> +QScriptValue qScriptValueFromSequence(QScriptEngine *eng, const Container &cont) +{ + QScriptValue a = eng->newArray(); + typename Container::const_iterator begin = cont.begin(); + typename Container::const_iterator end = cont.end(); + typename Container::const_iterator it; + quint32 i; + for (it = begin, i = 0; it != end; ++it, ++i) + a.setProperty(i, qScriptValueFromValue(eng, *it)); + return a; +} + +template <class Container> +void qScriptValueToSequence(const QScriptValue &value, Container &cont) +{ + quint32 len = value.property(QLatin1String("length")).toUInt32(); + for (quint32 i = 0; i < len; ++i) { + QScriptValue item = value.property(i); +#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET + cont.push_back(qscriptvalue_cast<Container::value_type>(item)); +#else + cont.push_back(qscriptvalue_cast<typename Container::value_type>(item)); +#endif + } +} + +template<typename T> +int qScriptRegisterSequenceMetaType( + QScriptEngine *engine, + const QScriptValue &prototype = QScriptValue() +#ifndef qdoc + , T * /* dummy */ = 0 +#endif +) +{ + return qScriptRegisterMetaType<T>(engine, qScriptValueFromSequence, + qScriptValueToSequence, prototype); +} + +#ifndef QT_NO_QOBJECT +Q_SCRIPT_EXPORT bool qScriptConnect(QObject *sender, const char *signal, + const QScriptValue &receiver, + const QScriptValue &function); +Q_SCRIPT_EXPORT bool qScriptDisconnect(QObject *sender, const char *signal, + const QScriptValue &receiver, + const QScriptValue &function); +#endif // QT_NO_QOBJECT + +Q_DECLARE_OPERATORS_FOR_FLAGS(QScriptEngine::QObjectWrapOptions) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTENGINE_H diff --git a/src/script/qscriptengine_p.cpp b/src/script/qscriptengine_p.cpp new file mode 100644 index 0000000..a2e58de --- /dev/null +++ b/src/script/qscriptengine_p.cpp @@ -0,0 +1,2724 @@ +/**************************************************************************** +** +** 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 "qscriptengine_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptlexer_p.h" +#include "qscriptnodepool_p.h" +#include "qscriptparser_p.h" +#include "qscriptcompiler_p.h" +#include "qscriptvalueiteratorimpl_p.h" +#include "qscriptecmaglobal_p.h" +#include "qscriptecmamath_p.h" +#include "qscriptecmaarray_p.h" +#include "qscriptextenumeration_p.h" +#include "qscriptsyntaxchecker_p.h" +#include "qscriptsyntaxcheckresult_p.h" +#include "qscriptclass.h" +#include "qscriptclass_p.h" +#include "qscriptengineagent.h" + +#include <QtCore/QDate> +#include <QtCore/QDateTime> +#include <QtCore/QRegExp> +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +#ifndef QT_NO_QOBJECT +#include "qscriptextensioninterface.h" +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QTextStream> +#include <QtCore/QCoreApplication> +#include <QtCore/QPluginLoader> +#endif + +Q_DECLARE_METATYPE(QScriptValue) +#ifndef QT_NO_QOBJECT +Q_DECLARE_METATYPE(QObjectList) +#endif +Q_DECLARE_METATYPE(QList<int>) + +QT_BEGIN_NAMESPACE + +extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str); +extern double qstrtod(const char *s00, char const **se, bool *ok); + +namespace QScript { + +QString numberToString(qsreal value) +{ + if (qIsNaN(value)) + return QLatin1String("NaN"); + + else if (qIsInf(value)) + return QLatin1String(value < 0 ? "-Infinity" : "Infinity"); + + else if (value == 0) + return QLatin1String("0"); + + QByteArray buf; + buf.reserve(80); + + int decpt; + int sign; + char *result = 0; + (void) qdtoa(value, 0, 0, &decpt, &sign, 0, &result); + + if (! result) + return QString(); + + else if (decpt <= 0 && decpt > -6) { + + buf.fill('0', -decpt + 2 + sign); + + if (sign) // fix the sign. + buf[0] = '-'; + + buf[sign + 1] = '.'; + buf += result; + } + + else { + if (sign) + buf += '-'; + + buf += result; + int length = buf.length() - sign; + + if (decpt <= 21 && decpt > 0) { + if (length <= decpt) + buf += QByteArray().fill('0', decpt - length); + else + buf.insert(decpt + sign, '.'); + } + + else if (result[0] >= '0' && result[0] <= '9') { + if (length > 1) + buf.insert(1 + sign, '.'); + + buf += 'e'; + buf += (decpt >= 0) ? '+' : '-'; + + int e = decpt - 1; + + if (e < 0) + e = -e; + + if (e >= 100) + buf += '0' + e / 100; + + if (e >= 10) + buf += '0' + (e % 100) / 10; + + buf += '0' + e % 10; + } + } + + free(result); + + return QString::fromLatin1(buf); +} + +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; +} + +qsreal integerFromString(const char *buf, int size, int radix) +{ + if (size == 0) + return qSNaN(); + + qsreal 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; + } + qsreal result; + if (j == i) { + if (!qstrcmp(buf, "Infinity")) + result = qInf(); + else + result = qSNaN(); + } else { + result = 0; + qsreal multiplier = 1; + for (--i ; i >= j; --i, multiplier *= radix) + result += toDigit(buf[i]) * multiplier; + } + result *= sign; + return result; +} + +qsreal integerFromString(const QString &str, int radix) +{ + QByteArray ba = str.trimmed().toUtf8(); + return integerFromString(ba.constData(), ba.size(), radix); +} + +qsreal numberFromString(const QString &repr) +{ + QString str = repr.trimmed(); + if ((str.length() > 2) && (str.at(0) == QLatin1Char('0')) && (str.at(1).toUpper() == QLatin1Char('X'))) + return integerFromString(str.mid(2), 16); + QByteArray latin1 = str.toLatin1(); + const char *data = latin1.constData(); + const char *eptr = 0; + qsreal result = qstrtod(data, &eptr, 0); + if (eptr == data) { + if (str == QLatin1String("Infinity")) + result = +qInf(); + else if (str == QLatin1String("+Infinity")) + result = +qInf(); + else if (str == QLatin1String("-Infinity")) + result = -qInf(); + else if (str.isEmpty()) + result = 0; + else + result = qSNaN(); + } else if (eptr != (data + latin1.length())) { + result = qSNaN(); + } + return result; +} + +NodePool::NodePool(const QString &fileName, QScriptEnginePrivate *engine) + : m_fileName(fileName), m_engine(engine) +{ +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + m_id = engine->nextScriptId(); +#endif +} + +NodePool::~NodePool() +{ + qDeleteAll(m_codeCache); + m_codeCache.clear(); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + m_engine->notifyScriptUnload(id()); +#endif +} + +Code *NodePool::createCompiledCode(AST::Node *node, CompilationUnit &compilation) +{ + QHash<AST::Node*, Code*>::const_iterator it = m_codeCache.constFind(node); + if (it != m_codeCache.constEnd()) + return it.value(); + + Code *code = new Code(); + code->init(compilation, this); + + m_codeCache.insert(node, code); + return code; +} + +class EvalFunction : public QScriptFunction +{ +public: + EvalFunction(QScriptEnginePrivate *) + { length = 1; } + + virtual ~EvalFunction() {} + + void evaluate(QScriptContextPrivate *context, const QString &contents, + int lineNo, const QString &fileName, bool calledFromScript) + { + QScriptEnginePrivate *eng_p = context->engine(); + + QExplicitlySharedDataPointer<NodePool> pool; + pool = new NodePool(fileName, eng_p); + eng_p->setNodePool(pool.data()); + + QString errorMessage; + int errorLineNumber; + AST::Node *program = eng_p->createAbstractSyntaxTree( + contents, lineNo, &errorMessage, &errorLineNumber); + + eng_p->setNodePool(0); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyScriptLoad(pool->id(), contents, fileName, lineNo); +#endif + + Code *code = 0; + if (program) { + Compiler compiler(eng_p); + compiler.setTopLevelCompiler(true); + CompilationUnit compilation = compiler.compile(program); + if (!compilation.isValid()) { + errorMessage = compilation.errorMessage(); + errorLineNumber = compilation.errorLineNumber(); + } else { + code = pool->createCompiledCode(program, compilation); + } + } + + if (!code) { + context->errorLineNumber = errorLineNumber; + context->currentLine = errorLineNumber; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + Code *oldCode = context->m_code; + Code dummy; + dummy.astPool = pool.data(); + context->m_code = &dummy; // so agents get the script ID + bool wasEvaluating = eng_p->m_evaluating; + eng_p->m_evaluating = true; + eng_p->notifyFunctionEntry(context); +#endif + context->throwError(QScriptContext::SyntaxError, errorMessage); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); + eng_p->m_evaluating = wasEvaluating; + context->m_code = oldCode; +#endif + return; + } + + if (calledFromScript) { + if (QScriptContextPrivate *pc = context->parentContext()) { + context->setActivationObject(pc->activationObject()); + context->setThisObject(pc->thisObject()); + context->m_scopeChain = pc->m_scopeChain; + } + } + + const QScriptInstruction *iPtr = context->instructionPointer(); + context->execute(code); + context->setInstructionPointer(iPtr); + } + + virtual void execute(QScriptContextPrivate *context) + { + QScriptEnginePrivate *eng = context->engine(); + int lineNo = context->currentLine; + if (lineNo == -1) { + QScriptContextPrivate *pc = context->parentContext(); + if (pc) + lineNo = pc->currentLine; + else + lineNo = 1; + } + QString fileName; // don't set this for now, we don't want to change the official eval() for now. + + if (context->argumentCount() == 0) { + context->setReturnValue(eng->undefinedValue()); + } else { + QScriptValueImpl arg = context->argument(0); + if (arg.isString()) { + QString contents = arg.toString(); + evaluate(context, contents, lineNo, fileName, /*calledFromScript=*/true); + } else { + context->setReturnValue(arg); + } + } + } + + QString functionName() const + { + return QLatin1String("eval"); + } +}; + +class ArgumentsClassData: public QScriptClassData +{ + +public: + + static inline QScript::ArgumentsObjectData *get(const QScriptValueImpl &object) + { return static_cast<QScript::ArgumentsObjectData*>(object.objectData()); } + + virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &object, const QScript::Member &member, + QScriptValueImpl *out_value); + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value); + virtual void mark(const QScriptValueImpl &object, int generation); + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object); +}; + +class ArgumentsClassDataIterator: public QScriptClassDataIterator +{ +public: + ArgumentsClassDataIterator(ArgumentsObjectData *data); + virtual ~ArgumentsClassDataIterator(); + + virtual bool hasNext() const; + virtual void next(QScript::Member *member); + + virtual bool hasPrevious() const; + virtual void previous(QScript::Member *member); + + virtual void toFront(); + virtual void toBack(); + +private: + ArgumentsObjectData *m_data; + uint m_pos; +}; + +bool ArgumentsClassData::resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode /*access*/) +{ + QString propertyName = object.engine()->toString(nameId); + bool isNumber; + quint32 index = propertyName.toUInt(&isNumber); + if (isNumber) { + QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object); + if (index < data->length) { + member->native(/*nameId=*/0, index, QScriptValue::SkipInEnumeration); + *base = object; + return true; + } + } + + return false; +} + +bool ArgumentsClassData::get(const QScriptValueImpl &object, const QScript::Member &member, + QScriptValueImpl *out_value) +{ + QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object); + if (member.nameId() == 0) { + QScriptObject *activation_data = data->activation.objectValue(); + *out_value = activation_data->m_values[member.id()]; + return true; + } + return false; +} + +bool ArgumentsClassData::put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value) +{ + Q_ASSERT(member.nameId() == 0); + QScript::ArgumentsObjectData *data = ArgumentsClassData::get(*object); + QScriptObject *activation_data = data->activation.objectValue(); + activation_data->m_values[member.id()] = value; + return true; +} + +void ArgumentsClassData::mark(const QScriptValueImpl &object, int generation) +{ + QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object); + data->activation.mark(generation); +} + +QScriptClassDataIterator *ArgumentsClassData::newIterator(const QScriptValueImpl &object) +{ + QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object); + return new ArgumentsClassDataIterator(data); +} + +ArgumentsClassDataIterator::ArgumentsClassDataIterator(ArgumentsObjectData *data) + : m_data(data), m_pos(0) +{ +} + +ArgumentsClassDataIterator::~ArgumentsClassDataIterator() +{ +} + +bool ArgumentsClassDataIterator::hasNext() const +{ + return m_pos < m_data->length; +} + +void ArgumentsClassDataIterator::next(QScript::Member *member) +{ + if (m_pos == m_data->length) { + member->invalidate(); + } else { + member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration); + ++m_pos; + } +} + +bool ArgumentsClassDataIterator::hasPrevious() const +{ + return (m_pos != 0); +} + +void ArgumentsClassDataIterator::previous(QScript::Member *member) +{ + if (m_pos == 0) { + member->invalidate(); + } else { + --m_pos; + member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration); + } +} + +void ArgumentsClassDataIterator::toFront() +{ + m_pos = 0; +} + +void ArgumentsClassDataIterator::toBack() +{ + m_pos = m_data->length; +} + +} // namespace QScript + +const qsreal QScriptEnginePrivate::D16 = 65536.0; +const qsreal QScriptEnginePrivate::D32 = 4294967296.0; + +QScriptEnginePrivate::~QScriptEnginePrivate() +{ + while (!m_agents.isEmpty()) + delete m_agents.takeFirst(); + + // invalidate values that we have references to + { + QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it; + for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it) + (*it)->invalidate(); + } + { + QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it; + for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it) + (*it)->invalidate(); + } + { + QVector<QScriptValuePrivate*>::const_iterator it; + for (it = m_otherHandles.constBegin(); it != m_otherHandles.constEnd(); ++it) + (*it)->invalidate(); + } + + // invalidate interned strings that are known to the outside world + { + QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it; + for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it) + it.value()->nameId = 0; + } + + delete[] m_string_hash_base; + qDeleteAll(m_stringRepository); + qDeleteAll(m_tempStringRepository); + + if (tempStackBegin) + delete[] tempStackBegin; + +#ifndef QT_NO_QOBJECT + deletePendingQObjects(); + qDeleteAll(m_qobjectData); +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + qDeleteAll(m_cachedMetaObjects); +# endif +#endif + + qDeleteAll(m_allocated_classes); +} + +QScript::AST::Node *QScriptEnginePrivate::changeAbstractSyntaxTree(QScript::AST::Node *prg) +{ + QScript::AST::Node *was = m_abstractSyntaxTree; + m_abstractSyntaxTree = prg; + return was; +} + +QScript::AST::Node *QScriptEnginePrivate::createAbstractSyntaxTree( + const QString &source, int lineNumber, QString *errorMessage, int *errorLineNumber) +{ + QScript::Lexer lex(this); + setLexer(&lex); + lex.setCode(source, lineNumber); + + QScriptParser parser; + + if (! parser.parse(this)) { + if (errorMessage) + *errorMessage = parser.errorMessage(); + if (errorLineNumber) + *errorLineNumber = parser.errorLineNumber(); + return 0; + } + + return abstractSyntaxTree(); +} + +void QScriptEnginePrivate::markObject(const QScriptValueImpl &object, int generation) +{ + QScriptObject *instance = object.objectValue(); + QScript::GCBlock *block = QScript::GCBlock::get(instance); + + enum { MAX_GC_DEPTH = 32 }; + + if (block->generation + 1 != generation) + return; + + if (m_gc_depth >= MAX_GC_DEPTH) { + // do the marking later + m_markStack.append(object); + return; + } + + ++block->generation; + ++m_gc_depth; + + if (QScriptClassData *data = object.classInfo()->data()) + data->mark(object, generation); + + if (instance->m_prototype.isObject()) + markObject(instance->m_prototype, generation); + + if (instance->m_scope.isObject()) + markObject(instance->m_scope, generation); + + const QScriptValueImpl &internalValue = instance->m_internalValue; + + if (internalValue.isValid()) { + if (internalValue.isObject()) + markObject(internalValue, generation); + + else if (internalValue.isString()) + markString(internalValue.m_string_value, generation); + } + + int garbage = 0; + + for (int i = 0; i < instance->memberCount(); ++i) { + QScript::Member m; + instance->member(i, &m); + + if (! m.isValid()) { + ++garbage; + continue; + } + + Q_ASSERT(m.isObjectProperty()); + + QScriptValueImpl child; + instance->get(m, &child); + + if (m.nameId()) + markString(m.nameId(), generation); + + if (! child.isValid()) + continue; + + else if (child.isObject()) + markObject(child, generation); + + else if (child.isString()) + markString(child.m_string_value, generation); + } + + --m_gc_depth; + + if (garbage < 128) // ### + return; + + int j = 0; + for (int i = 0; i < instance->memberCount(); ++i) { + QScript::Member m; + instance->member(i, &m); + + if (! m.isValid()) + continue; + + if (i != j) { + instance->m_members[j].object(m.nameId(), j, m.flags()); + instance->m_values[j] = instance->m_values[i]; + } + ++j; + } + //qDebug() << "==> old:" << instance->m_members.size() << "new:" << j; + instance->m_members.resize(j); + instance->m_values.resize(j); +} + +void QScriptEnginePrivate::markFrame(QScriptContextPrivate *context, int generation) +{ + QScriptValueImpl activation = context->activationObject(); + QScriptValueImpl thisObject = context->thisObject(); + QScriptValueImpl scopeChain = context->m_scopeChain; + QScriptValueImpl callee = context->m_callee; + QScriptValueImpl arguments = context->m_arguments; + + if (activation.isObject()) + markObject(activation, generation); + + if (scopeChain.isObject()) + markObject(scopeChain, generation); + + if (thisObject.isObject()) + markObject(thisObject, generation); + + if (callee.isObject()) + markObject(callee, generation); + + if (arguments.isObject()) + markObject(arguments, generation); + + if (context->returnValue().isValid()) { + if (context->returnValue().isObject()) + markObject(context->returnValue(), generation); + + else if (context->returnValue().isString()) + markString(context->returnValue().m_string_value, generation); + } + + if (context->baseStackPointer() != context->currentStackPointer()) { + // mark the temp stack + + for (const QScriptValueImpl *it = context->baseStackPointer(); it != (context->currentStackPointer() + 1); ++it) { + if (! it) { + qWarning() << "no temp stack!!!"; + break; + } + + else if (! it->isValid()) // ### assert? + continue; + + else if (it->isObject()) + markObject(*it, generation); + + else if (it->isString()) + markString(it->m_string_value, generation); + } + } +} + +bool QScriptEnginePrivate::isCollecting() const +{ + return (m_gc_depth != -1) || objectAllocator.sweeping(); +} + +void QScriptEnginePrivate::maybeGC_helper(bool do_string_gc) +{ + // qDebug() << "==>" << objectAllocator.newAllocatedBlocks() << "free:" << objectAllocator.freeBlocks(); + Q_ASSERT(m_gc_depth == -1); + ++m_gc_depth; + + int generation = m_objectGeneration + 1; + + markObject(m_globalObject, generation); + + objectConstructor->mark(this, generation); + numberConstructor->mark(this, generation); + booleanConstructor->mark(this, generation); + stringConstructor->mark(this, generation); + dateConstructor->mark(this, generation); + functionConstructor->mark(this, generation); + arrayConstructor->mark(this, generation); + regexpConstructor->mark(this, generation); + errorConstructor->mark(this, generation); + enumerationConstructor->mark(this, generation); + variantConstructor->mark(this, generation); +#ifndef QT_NO_QOBJECT + qobjectConstructor->mark(this, generation); + qmetaObjectConstructor->mark(this, generation); +#endif + + { + QScriptContextPrivate *current = currentContext(); + while (current != 0) { + markFrame (current, generation); + current = current->parentContext(); + } + } + + { + QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it; + for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it) + markObject((*it)->value, generation); + } + + { + QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it; + for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it) + markString((*it)->value.stringValue(), generation); + } + + { + QHash<int, QScriptCustomTypeInfo>::const_iterator it; + for (it = m_customTypes.constBegin(); it != m_customTypes.constEnd(); ++it) + (*it).prototype.mark(generation); + } + +#ifndef QT_NO_QOBJECT +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + { + QHash<const QMetaObject*, QScriptMetaObject*>::const_iterator it; + for (it = m_cachedMetaObjects.constBegin(); it != m_cachedMetaObjects.constEnd(); ++it) { + { + QList<QScriptNameIdImpl*> memberNames = (*it)->registeredMemberNames(); + QList<QScriptNameIdImpl*>::const_iterator it2; + for (it2 = memberNames.constBegin(); it2 != memberNames.constEnd(); ++it2) + markString(*it2, generation); + } + { + QList<QScriptValueImpl> propertyAccessors = (*it)->registeredPropertyAccessors(); + QList<QScriptValueImpl>::const_iterator it2; + for (it2 = propertyAccessors.constBegin(); it2 != propertyAccessors.constEnd(); ++it2) + markObject(*it2, generation); + } + } + } +# endif + processMarkStack(generation); // make sure everything is marked before marking qobject data + { + QHash<QObject*, QScriptQObjectData*>::const_iterator it; + for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) { + QScriptQObjectData *qdata = it.value(); + qdata->mark(generation); + } + } +#endif + processMarkStack(generation); + + Q_ASSERT(m_gc_depth == 0); + --m_gc_depth; + + objectAllocator.sweep(generation); + + m_objectGeneration = generation; + + //qDebug() << "free blocks:" << objectAllocator.freeBlocks(); + +#ifndef QT_NO_QOBJECT + deletePendingQObjects(); +#endif + + if (! do_string_gc) + return; + + { + QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it; + for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it) { + it.value()->nameId->used = true; + } + } + +#if 0 + qDebug() << "do_string_gc:" << do_string_gc + << ((m_stringRepository.size() - m_oldStringRepositorySize) > 256) + << ((m_tempStringRepository.size() - m_oldTempStringRepositorySize) > 2048); +#endif + + QVector<QScriptNameIdImpl*> compressed; + compressed.reserve(m_stringRepository.size()); + + for (int i = 0; i < m_stringRepository.size(); ++i) { + QScriptNameIdImpl *entry = m_stringRepository.at(i); + + if (entry->used || entry->persistent) { + compressed.append(entry); + entry->used = false; + } + + else { + //qDebug() << "deleted unique:" << entry->s; + delete entry; + } + } + + // qDebug() << "before:" << m_stringRepository.size() << "after:" << compressed.size() << globalObject.objectValue()->m_members.size(); + m_stringRepository = compressed; + rehashStringRepository(/*resize=*/ false); + m_oldStringRepositorySize = m_stringRepository.size(); + m_newAllocatedStringRepositoryChars = 0; + + compressed.clear(); + for (int i = 0; i < m_tempStringRepository.size(); ++i) { + QScriptNameIdImpl *entry = m_tempStringRepository.at(i); + + if (entry->used || entry->persistent) { + compressed.append(entry); + entry->used = false; + } + + else { + //qDebug() << "deleted:" << entry->s; + delete entry; + } + } + + //qDebug() << "before:" << m_tempStringRepository.size() << "after:" << compressed.size(); + + m_tempStringRepository = compressed; + m_oldTempStringRepositorySize = m_tempStringRepository.size(); + m_newAllocatedTempStringRepositoryChars = 0; +} + +void QScriptEnginePrivate::processMarkStack(int generation) +{ + // mark the objects we couldn't process due to recursion depth + while (!m_markStack.isEmpty()) + markObject(m_markStack.takeLast(), generation); +} + +void QScriptEnginePrivate::evaluate(QScriptContextPrivate *context, const QString &contents, int lineNumber, const QString &fileName) +{ + // ### try to remove cast + QScript::EvalFunction *evalFunction = static_cast<QScript::EvalFunction*>(m_evalFunction); + evalFunction->evaluate(context, contents, lineNumber, fileName, /*calledFromScript=*/ false); +} + +qsreal QScriptEnginePrivate::convertToNativeDouble_helper(const QScriptValueImpl &value) +{ + switch (value.type()) { + case QScript::InvalidType: + Q_ASSERT(value.isValid()); + break; + + case QScript::UndefinedType: + case QScript::PointerType: + break; + + case QScript::NullType: + return 0; + + case QScript::BooleanType: + return value.m_bool_value; + + case QScript::IntegerType: + case QScript::ReferenceType: + return value.m_int_value; + + case QScript::NumberType: + return value.m_number_value; + + case QScript::StringType: + return QScript::numberFromString(toString(value.m_string_value)); + + case QScript::ObjectType: { + QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::NumberTypeHint); + if (! p.isValid() || p.isObject()) + break; + + return convertToNativeDouble(p); + } + + case QScript::LazyStringType: + return QScript::numberFromString(*value.m_lazy_string_value); + + } // switch + + return qSNaN(); +} + +bool QScriptEnginePrivate::convertToNativeBoolean_helper(const QScriptValueImpl &value) +{ + switch (value.type()) { + case QScript::InvalidType: + Q_ASSERT(value.isValid()); + return false; + + case QScript::UndefinedType: + case QScript::PointerType: + case QScript::NullType: + case QScript::ReferenceType: + return false; + + case QScript::BooleanType: + return value.m_bool_value; + + case QScript::IntegerType: + return value.m_int_value != 0; + + case QScript::NumberType: + return value.m_number_value != 0 && !qIsNaN(value.m_number_value); + + case QScript::StringType: + return toString(value.m_string_value).length() != 0; + + case QScript::ObjectType: + return true; + + case QScript::LazyStringType: + return value.m_lazy_string_value->length() != 0; + + } // switch + + return false; +} + +QString QScriptEnginePrivate::convertToNativeString_helper(const QScriptValueImpl &value) +{ + static QStringList predefined; + if (predefined.isEmpty()) { + predefined.append(QString::fromLatin1("undefined")); + predefined.append(QString::fromLatin1("null")); + predefined.append(QString::fromLatin1("true")); + predefined.append(QString::fromLatin1("false")); + predefined.append(QString::fromLatin1("pointer")); + } + + switch (value.type()) { + case QScript::InvalidType: + Q_ASSERT(value.isValid()); + return QString(); + + case QScript::UndefinedType: + return predefined.at(0); + + case QScript::NullType: + return predefined.at(1); + + case QScript::BooleanType: + return value.m_bool_value ? predefined.at(2) : predefined.at(3); + + case QScript::IntegerType: + return QString::number(value.m_int_value); + + case QScript::NumberType: + return QScript::numberToString(value.m_number_value); + + case QScript::PointerType: + return predefined.at(4); + + case QScript::StringType: + return toString(value.m_string_value); + + case QScript::ReferenceType: + return QString(); + + case QScript::ObjectType: { + QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::StringTypeHint); + + if (!p.isValid() || strictlyEquals(p, value)) + return p.classInfo()->name(); + + return convertToNativeString(p); + } + + case QScript::LazyStringType: + return *value.m_lazy_string_value; + + } // switch + + return QString(); +} + +QScriptValueImpl QScriptEnginePrivate::toObject_helper(const QScriptValueImpl &value) +{ + QScriptValueImpl result; + switch (value.type()) { + case QScript::BooleanType: + booleanConstructor->newBoolean(&result, value.m_bool_value); + break; + + case QScript::NumberType: + numberConstructor->newNumber(&result, value.m_number_value); + break; + + case QScript::StringType: + stringConstructor->newString(&result, value.m_string_value->s); + break; + + case QScript::LazyStringType: + stringConstructor->newString(&result, *value.m_lazy_string_value); + break; + + case QScript::InvalidType: + case QScript::UndefinedType: + case QScript::NullType: + case QScript::IntegerType: + case QScript::ReferenceType: + case QScript::PointerType: + case QScript::ObjectType: + break; + } // switch + + return result; +} + +// [[defaultValue]] +QScriptValueImpl QScriptEnginePrivate::toPrimitive_helper(const QScriptValueImpl &object, + QScriptValueImpl::TypeHint hint) +{ + QScriptNameIdImpl *functionIds[2]; + + if ((hint == QScriptValueImpl::NumberTypeHint) + || (hint == QScriptValueImpl::NoTypeHint + && object.classInfo() != dateConstructor->classInfo())) { + functionIds[0] = idTable()->id_valueOf; + functionIds[1] = idTable()->id_toString; + } else { + functionIds[0] = idTable()->id_toString; + functionIds[1] = idTable()->id_valueOf; + } + + for (int i = 0; i < 2; ++i) { + QScriptValueImpl base; + QScript::Member member; + + if (! object.resolve(functionIds[i], &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) + return object; + + QScriptValueImpl f_valueOf; + base.get(member, &f_valueOf); + + if (QScriptFunction *foo = convertToNativeFunction(f_valueOf)) { + QScriptContextPrivate *me = pushContext(); + QScriptValueImpl activation; + newActivation(&activation); + if (f_valueOf.scope().isValid()) + activation.setScope(f_valueOf.scope()); + else + activation.setScope(m_globalObject); + me->setActivationObject(activation); + me->setThisObject(object); + me->m_callee = f_valueOf; + foo->execute(me); + QScriptValueImpl result = me->returnValue(); + bool exception = (me->state() == QScriptContext::ExceptionState); + popContext(); + if (exception || (result.isValid() && !result.isObject())) + return result; + } + } + + return object; +} + +void QScriptEnginePrivate::rehashStringRepository(bool resize) +{ + if (resize) { + delete[] m_string_hash_base; + m_string_hash_size <<= 1; // ### use primes + + m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size]; + } + + memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size); + + for (int index = 0; index < m_stringRepository.size(); ++index) { + QScriptNameIdImpl *entry = m_stringRepository.at(index); + uint h = _q_scriptHash(entry->s) % m_string_hash_size; + entry->h = h; + entry->next = m_string_hash_base[h]; + m_string_hash_base[h] = entry; + } +} + +QScriptNameIdImpl *QScriptEnginePrivate::insertStringEntry(const QString &s) +{ + QScriptNameIdImpl *entry = new QScriptNameIdImpl(s); + entry->unique = true; + m_stringRepository.append(entry); + m_newAllocatedStringRepositoryChars += s.length(); + + uint h = _q_scriptHash(s) % m_string_hash_size; + entry->h = h; + entry->next = m_string_hash_base[h]; + m_string_hash_base[h] = entry; + + if (m_stringRepository.count() == m_string_hash_size) + rehashStringRepository(); + + return entry; +} + +QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee, + const QScriptValueImpl &thisObject, + const QScriptValueImplList &args, + bool asConstructor) +{ + QScriptFunction *function = callee.toFunction(); + Q_ASSERT(function); + + if (++m_callDepth == m_maxCallDepth) { + QScriptContextPrivate *ctx_p = currentContext(); + return ctx_p->throwError(QLatin1String("call stack overflow")); + } + + QScriptContextPrivate *nested = pushContext(); + // set up the temp stack + if (! nested->tempStack) + nested->stackPtr = nested->tempStack = tempStackBegin; + + newActivation(&nested->m_activation); + if (callee.m_object_value->m_scope.isValid()) + nested->m_activation.m_object_value->m_scope = callee.m_object_value->m_scope; + else + nested->m_activation.m_object_value->m_scope = m_globalObject; + + QScriptObject *activation_data = nested->m_activation.m_object_value; + + int formalCount = function->formals.count(); + int argc = args.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx); + activation_data->m_values.resize(mx); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId = 0; + if (i < formalCount) + nameId = function->formals.at(i); + + activation_data->m_members[i].object(nameId, i, QScriptValue::SkipInEnumeration); + QScriptValueImpl arg = (i < argc) ? args.at(i) : m_undefinedValue; + if (arg.isValid() && arg.engine() && (arg.engine() != this)) { + qWarning("QScriptValue::call() failed: " + "cannot call function with argument created in " + "a different engine"); + popContext(); + return QScriptValueImpl(); + } + activation_data->m_values[i] = arg.isValid() ? arg : m_undefinedValue; + } + + nested->argc = argc; + QVector<QScriptValueImpl> argsv = args.toVector(); + nested->args = const_cast<QScriptValueImpl*> (argsv.constData()); + + if (thisObject.isObject()) + nested->m_thisObject = thisObject; + else + nested->m_thisObject = m_globalObject; + nested->m_callee = callee; + nested->m_calledAsConstructor = asConstructor; + + nested->m_result = m_undefinedValue; + function->execute(nested); + --m_callDepth; + QScriptValueImpl result = nested->m_result; + nested->args = 0; + popContext(); + + return result; +} + +QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee, + const QScriptValueImpl &thisObject, + const QScriptValueImpl &args, + bool asConstructor) +{ + QScriptValueImplList argsList; + if (QScript::Ecma::Array::Instance *arr = arrayConstructor->get(args)) { + QScript::Array actuals = arr->value; + for (quint32 i = 0; i < actuals.count(); ++i) { + QScriptValueImpl a = actuals.at(i); + if (! a.isValid()) + argsList << undefinedValue(); + else + argsList << a; + } + } else if (args.classInfo() == m_class_arguments) { + QScript::ArgumentsObjectData *arguments; + arguments = static_cast<QScript::ArgumentsObjectData*> (args.objectData()); + QScriptObject *activation = arguments->activation.objectValue(); + for (uint i = 0; i < arguments->length; ++i) + argsList << activation->m_values[i]; + } else if (!(args.isUndefined() || args.isNull())) { + return currentContext()->throwError( + QScriptContext::TypeError, + QLatin1String("QScriptValue::call(): arguments must be an array")); + } + return call(callee, thisObject, argsList, asConstructor); +} + +QScriptValueImpl QScriptEnginePrivate::arrayFromStringList(const QStringList &lst) +{ + QScriptValueImpl arr = newArray(lst.size()); + for (int i = 0; i < lst.size(); ++i) + arr.setProperty(i, QScriptValueImpl(this, lst.at(i))); + return arr; +} + +QStringList QScriptEnginePrivate::stringListFromArray(const QScriptValueImpl &arr) +{ + QStringList lst; + uint len = arr.property(QLatin1String("length")).toUInt32(); + for (uint i = 0; i < len; ++i) + lst.append(arr.property(i).toString()); + return lst; +} + +QScriptValueImpl QScriptEnginePrivate::arrayFromVariantList(const QVariantList &lst) +{ + QScriptValueImpl arr = newArray(lst.size()); + for (int i = 0; i < lst.size(); ++i) + arr.setProperty(i, valueFromVariant(lst.at(i))); + return arr; +} + +QVariantList QScriptEnginePrivate::variantListFromArray(const QScriptValueImpl &arr) +{ + QVariantList lst; + uint len = arr.property(QLatin1String("length")).toUInt32(); + for (uint i = 0; i < len; ++i) + lst.append(arr.property(i).toVariant()); + return lst; +} + +QScriptValueImpl QScriptEnginePrivate::objectFromVariantMap(const QVariantMap &vmap) +{ + QScriptValueImpl obj = newObject(); + QVariantMap::const_iterator it; + for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) + obj.setProperty(it.key(), valueFromVariant(it.value())); + return obj; +} + +QVariantMap QScriptEnginePrivate::variantMapFromObject(const QScriptValueImpl &obj) +{ + QVariantMap vmap; + QScriptValueIteratorImpl it(obj); + while (it.hasNext()) { + it.next(); + vmap.insert(it.name(), it.value().toVariant()); + } + return vmap; +} + +QScriptValueImpl QScriptEnginePrivate::create(int type, const void *ptr) +{ + Q_Q(QScriptEngine); + Q_ASSERT(ptr); + QScriptValueImpl result; + QScriptCustomTypeInfo info = m_customTypes.value(type); + if (info.marshal) { + result = toImpl(info.marshal(q, ptr)); + } else { + // check if it's one of the types we know + switch (QMetaType::Type(type)) { + case QMetaType::Void: + result = m_undefinedValue; + break; + case QMetaType::Bool: + result = QScriptValueImpl(*reinterpret_cast<const bool*>(ptr)); + break; + case QMetaType::Int: + result = QScriptValueImpl(*reinterpret_cast<const int*>(ptr)); + break; + case QMetaType::UInt: + result = QScriptValueImpl(*reinterpret_cast<const uint*>(ptr)); + break; + case QMetaType::LongLong: + result = QScriptValueImpl(qsreal(*reinterpret_cast<const qlonglong*>(ptr))); + break; + case QMetaType::ULongLong: +#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804 +#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.") + result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr))); +#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) + result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr))); +#else + result = QScriptValueImpl(qsreal(*reinterpret_cast<const qulonglong*>(ptr))); +#endif + break; + case QMetaType::Double: + result = QScriptValueImpl(*reinterpret_cast<const double*>(ptr)); + break; + case QMetaType::QString: + result = QScriptValueImpl(this, *reinterpret_cast<const QString*>(ptr)); + break; + case QMetaType::Float: + result = QScriptValueImpl(*reinterpret_cast<const float*>(ptr)); + break; + case QMetaType::Short: + result = QScriptValueImpl(*reinterpret_cast<const short*>(ptr)); + break; + case QMetaType::UShort: + result = QScriptValueImpl(*reinterpret_cast<const unsigned short*>(ptr)); + break; + case QMetaType::Char: + result = QScriptValueImpl(*reinterpret_cast<const char*>(ptr)); + break; + case QMetaType::UChar: + result = QScriptValueImpl(*reinterpret_cast<const unsigned char*>(ptr)); + break; + case QMetaType::QChar: + result = QScriptValueImpl((*reinterpret_cast<const QChar*>(ptr)).unicode()); + break; + case QMetaType::QStringList: + result = arrayFromStringList(*reinterpret_cast<const QStringList *>(ptr)); + break; + case QMetaType::QVariantList: + result = arrayFromVariantList(*reinterpret_cast<const QVariantList *>(ptr)); + break; + case QMetaType::QVariantMap: + result = objectFromVariantMap(*reinterpret_cast<const QVariantMap *>(ptr)); + break; + case QMetaType::QDateTime: { + QDateTime dateTime = *reinterpret_cast<const QDateTime *>(ptr); + dateConstructor->newDate(&result, dateTime); + } break; + case QMetaType::QDate: { + QDate date = *reinterpret_cast<const QDate *>(ptr); + dateConstructor->newDate(&result, date); + } break; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: { + QRegExp rx = *reinterpret_cast<const QRegExp *>(ptr); + regexpConstructor->newRegExp(&result, rx); + } break; +#endif +#ifndef QT_NO_QOBJECT + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + newQObject(&result, *reinterpret_cast<QObject* const *>(ptr)); + break; +#endif + default: + if (type == qMetaTypeId<QScriptValue>()) { + result = toImpl(*reinterpret_cast<const QScriptValue*>(ptr)); + if (!result.isValid()) + result = m_undefinedValue; + } + +#ifndef QT_NO_QOBJECT + // lazy registration of some common list types + else if (type == qMetaTypeId<QObjectList>()) { + qScriptRegisterSequenceMetaType<QObjectList>(q); + return create(type, ptr); + } +#endif + else if (type == qMetaTypeId<QList<int> >()) { + qScriptRegisterSequenceMetaType<QList<int> >(q); + return create(type, ptr); + } + + else { + QByteArray typeName = QMetaType::typeName(type); + if (typeName == "QVariant") + result = valueFromVariant(*reinterpret_cast<const QVariant*>(ptr)); + else if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr)) + result = nullValue(); + else + newVariant(&result, QVariant(type, ptr)); + } + } + } + if (result.isObject() && info.prototype.isValid() + && strictlyEquals(result.prototype(), objectConstructor->publicPrototype)) { + result.setPrototype(info.prototype); + } + return result; +} + +bool QScriptEnginePrivate::convert(const QScriptValueImpl &value, + int type, void *ptr, + QScriptEnginePrivate *eng) +{ + if (!eng) + eng = value.engine(); + if (eng) { + QScriptCustomTypeInfo info = eng->m_customTypes.value(type); + if (info.demarshal) { + info.demarshal(eng->toPublic(value), ptr); + return true; + } + } + + // check if it's one of the types we know + switch (QMetaType::Type(type)) { + case QMetaType::Bool: + *reinterpret_cast<bool*>(ptr) = value.toBoolean(); + return true; + case QMetaType::Int: + *reinterpret_cast<int*>(ptr) = value.toInt32(); + return true; + case QMetaType::UInt: + *reinterpret_cast<uint*>(ptr) = value.toUInt32(); + return true; + case QMetaType::LongLong: + *reinterpret_cast<qlonglong*>(ptr) = qlonglong(value.toInteger()); + return true; + case QMetaType::ULongLong: + *reinterpret_cast<qulonglong*>(ptr) = qulonglong(value.toInteger()); + return true; + case QMetaType::Double: + *reinterpret_cast<double*>(ptr) = value.toNumber(); + return true; + case QMetaType::QString: + if (value.isUndefined() || value.isNull()) + *reinterpret_cast<QString*>(ptr) = QString(); + else + *reinterpret_cast<QString*>(ptr) = value.toString(); + return true; + case QMetaType::Float: + *reinterpret_cast<float*>(ptr) = value.toNumber(); + return true; + case QMetaType::Short: + *reinterpret_cast<short*>(ptr) = short(value.toInt32()); + return true; + case QMetaType::UShort: + *reinterpret_cast<unsigned short*>(ptr) = value.toUInt16(); + return true; + case QMetaType::Char: + *reinterpret_cast<char*>(ptr) = char(value.toInt32()); + return true; + case QMetaType::UChar: + *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(value.toInt32()); + return true; + case QMetaType::QChar: + if (value.isString()) { + QString str = value.toString(); + *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0); + } else { + *reinterpret_cast<QChar*>(ptr) = QChar(value.toUInt16()); + } + return true; + case QMetaType::QDateTime: + if (value.isDate()) { + *reinterpret_cast<QDateTime *>(ptr) = value.toDateTime(); + return true; + } break; + case QMetaType::QDate: + if (value.isDate()) { + *reinterpret_cast<QDate *>(ptr) = value.toDateTime().date(); + return true; + } break; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + if (value.isRegExp()) { + *reinterpret_cast<QRegExp *>(ptr) = value.toRegExp(); + return true; + } break; +#endif +#ifndef QT_NO_QOBJECT + case QMetaType::QObjectStar: + if (value.isQObject() || value.isNull()) { + *reinterpret_cast<QObject* *>(ptr) = value.toQObject(); + return true; + } break; + case QMetaType::QWidgetStar: + if (value.isQObject() || value.isNull()) { + QObject *qo = value.toQObject(); + if (!qo || qo->isWidgetType()) { + *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo); + return true; + } + } break; +#endif + case QMetaType::QStringList: + if (value.isArray()) { + *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(value); + return true; + } break; + case QMetaType::QVariantList: + if (value.isArray()) { + *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(value); + return true; + } break; + case QMetaType::QVariantMap: + if (value.isObject()) { + *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(value); + return true; + } break; + default: + ; + } + + QByteArray name = QMetaType::typeName(type); +#ifndef QT_NO_QOBJECT + if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(ptr))) + return true; +#endif + if (value.isVariant() && name.endsWith('*')) { + int valueType = QMetaType::type(name.left(name.size()-1)); + QVariant &var = value.variantValue(); + if (valueType == var.userType()) { + *reinterpret_cast<void* *>(ptr) = var.data(); + return true; + } else { + // look in the prototype chain + QScriptValueImpl proto = value.prototype(); + while (proto.isObject()) { + bool canCast = false; + if (proto.isVariant()) { + canCast = (type == proto.variantValue().userType()) + || (valueType && (valueType == proto.variantValue().userType())); + } +#ifndef QT_NO_QOBJECT + else if (proto.isQObject()) { + QByteArray className = name.left(name.size()-1); + if (QObject *qobject = proto.toQObject()) + canCast = qobject->qt_metacast(className) != 0; + } +#endif + if (canCast) { + QByteArray varTypeName = QMetaType::typeName(var.userType()); + if (varTypeName.endsWith('*')) + *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data()); + else + *reinterpret_cast<void* *>(ptr) = var.data(); + return true; + } + proto = proto.prototype(); + } + } + } else if (value.isNull() && name.endsWith('*')) { + *reinterpret_cast<void* *>(ptr) = 0; + return true; + } else if (type == qMetaTypeId<QScriptValue>()) { + if (!eng) + return false; + *reinterpret_cast<QScriptValue*>(ptr) = eng->toPublic(value); + return true; + } else if (name == "QVariant") { + *reinterpret_cast<QVariant*>(ptr) = value.toVariant(); + return true; + } + + // lazy registration of some common list types +#ifndef QT_NO_QOBJECT + else if (type == qMetaTypeId<QObjectList>()) { + if (!eng) + return false; + qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func()); + return convert(value, type, ptr, eng); + } +#endif + else if (type == qMetaTypeId<QList<int> >()) { + if (!eng) + return false; + qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func()); + return convert(value, type, ptr, eng); + } + +#if 0 + if (!name.isEmpty()) { + qWarning("QScriptEngine::convert: unable to convert value to type `%s'", + name.constData()); + } +#endif + return false; +} + +QScriptValuePrivate *QScriptEnginePrivate::registerValue(const QScriptValueImpl &value) +{ + if (value.isString()) { + QScriptNameIdImpl *id = value.stringValue(); + QScriptValuePrivate *p = m_stringHandles.value(id); + if (p) + return p; + p = m_handleRepository.get(); + p->engine = q_func(); + p->value = value; + m_stringHandles.insert(id, p); + return p; + } else if (value.isObject()) { + QScriptObject *instance = value.objectValue(); + QScriptValuePrivate *p = m_objectHandles.value(instance); + if (p) + return p; + p = m_handleRepository.get(); + p->engine = q_func(); + p->value = value; + m_objectHandles.insert(instance, p); + return p; + } + QScriptValuePrivate *p = m_handleRepository.get(); + p->engine = q_func(); + p->value = value; + m_otherHandles.append(p); + return p; +} + +QScriptEnginePrivate::QScriptEnginePrivate() +{ + m_undefinedValue = QScriptValueImpl(QScriptValue::UndefinedValue); + m_nullValue = QScriptValueImpl(QScriptValue::NullValue); + + m_evaluating = false; + m_abort = false; + m_callDepth = 0; +#if defined(Q_OS_WIN) + m_maxCallDepth = 88; +#elif defined(Q_OS_MAC) + m_maxCallDepth = 640; +#elif defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6) + m_maxCallDepth = 360; +#else + m_maxCallDepth = 512; +#endif + m_oldStringRepositorySize = 0; + m_oldTempStringRepositorySize = 0; + m_newAllocatedStringRepositoryChars = 0; + m_newAllocatedTempStringRepositoryChars = 0; + m_context = 0; + m_abstractSyntaxTree = 0; + m_lexer = 0; + m_scriptCounter = 0; + m_agent = 0; + m_objectGeneration = 0; + m_class_prev_id = QScriptClassInfo::CustomType; + m_next_object_id = 0; + m_gc_depth = -1; + + objectConstructor = 0; + numberConstructor = 0; + booleanConstructor = 0; + stringConstructor = 0; + dateConstructor = 0; + functionConstructor = 0; + arrayConstructor = 0; + regexpConstructor = 0; + errorConstructor = 0; + enumerationConstructor = 0; + variantConstructor = 0; + qobjectConstructor = 0; + qmetaObjectConstructor = 0; + + m_processEventsInterval = -1; + m_nextProcessEvents = 0; + m_processEventIncr = 0; + + m_stringRepository.reserve(DefaultHashSize); + m_string_hash_size = DefaultHashSize; + m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size]; + memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size); + + tempStackBegin = 0; +} + +void QScriptEnginePrivate::init() +{ + qMetaTypeId<QScriptValue>(); + qMetaTypeId<QList<int> >(); +#ifndef QT_NO_QOBJECT + qMetaTypeId<QObjectList>(); +#endif + + m_class_prev_id = QScriptClassInfo::CustomType; + m_class_object = registerClass(QLatin1String("Object"), QScriptClassInfo::ObjectType); + m_class_function = registerClass(QLatin1String("Function"), QScriptClassInfo::FunctionType); + m_class_activation = registerClass(QLatin1String("activation"), QScriptClassInfo::ActivationType); + + m_class_arguments = registerClass(QLatin1String("arguments"), QScript::ObjectType); + m_class_arguments->setData(new QScript::ArgumentsClassData()); + + m_class_with = registerClass(QLatin1String("__qscript_internal_with"), QScript::ObjectType); + + // public name ids + m_id_table.id_constructor = nameId(QLatin1String("constructor"), true); + m_id_table.id_false = nameId(QLatin1String("false"), true); + m_id_table.id_null = nameId(QLatin1String("null"), true); + m_id_table.id_object = nameId(QLatin1String("object"), true); + m_id_table.id_pointer = nameId(QLatin1String("pointer"), true); + m_id_table.id_prototype = nameId(QLatin1String("prototype"), true); + m_id_table.id_arguments = nameId(QLatin1String("arguments"), true); + m_id_table.id_this = nameId(QLatin1String("this"), true); + m_id_table.id_toString = nameId(QLatin1String("toString"), true); + m_id_table.id_true = nameId(QLatin1String("true"), true); + m_id_table.id_undefined = nameId(QLatin1String("undefined"), true); + m_id_table.id_valueOf = nameId(QLatin1String("valueOf"), true); + m_id_table.id_length = nameId(QLatin1String("length"), true); + m_id_table.id_callee = nameId(QLatin1String("callee"), true); + m_id_table.id___proto__ = nameId(QLatin1String("__proto__"), true); + m_id_table.id___qt_sender__ = nameId(QLatin1String("__qt_sender__"), true); + + const int TEMP_STACK_SIZE = 10 * 1024; + tempStackBegin = new QScriptValueImpl[TEMP_STACK_SIZE]; + tempStackEnd = tempStackBegin + TEMP_STACK_SIZE; + tempStackBegin[0] = m_undefinedValue; + + objectAllocator.blockGC(true); + + QScript::Ecma::Global::construct(&m_globalObject, this); + + // create the prototypes first... + objectConstructor = new QScript::Ecma::Object(this, m_class_object); + functionConstructor = new QScript::Ecma::Function(this, m_class_function); + // ... then we can initialize + functionConstructor->initialize(); + objectConstructor->initialize(); + + numberConstructor = new QScript::Ecma::Number(this); + booleanConstructor = new QScript::Ecma::Boolean(this); + stringConstructor = new QScript::Ecma::String(this); + dateConstructor = new QScript::Ecma::Date(this); + arrayConstructor = new QScript::Ecma::Array(this); + regexpConstructor = new QScript::Ecma::RegExp(this); + errorConstructor = new QScript::Ecma::Error(this); + + QScript::Ecma::Global::initialize(&m_globalObject, this); + + const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration; + + m_globalObject.setProperty(QLatin1String("Object"), + objectConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Function"), + functionConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Number"), + numberConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Boolean"), + booleanConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("String"), + stringConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Date"), + dateConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Array"), + arrayConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("RegExp"), + regexpConstructor->ctor, flags); + m_globalObject.setProperty(QLatin1String("Error"), + errorConstructor->ctor, flags); + + m_globalObject.setProperty(QLatin1String("EvalError"), + errorConstructor->evalErrorCtor, flags); + m_globalObject.setProperty(QLatin1String("RangeError"), + errorConstructor->rangeErrorCtor, flags); + m_globalObject.setProperty(QLatin1String("ReferenceError"), + errorConstructor->referenceErrorCtor, flags); + m_globalObject.setProperty(QLatin1String("SyntaxError"), + errorConstructor->syntaxErrorCtor, flags); + m_globalObject.setProperty(QLatin1String("TypeError"), + errorConstructor->typeErrorCtor, flags); + m_globalObject.setProperty(QLatin1String("URIError"), + errorConstructor->uriErrorCtor, flags); + + QScriptValueImpl tmp; // ### fixme + m_evalFunction = new QScript::EvalFunction(this); + functionConstructor->newFunction(&tmp, m_evalFunction); + m_globalObject.setProperty(QLatin1String("eval"), tmp, flags); + + QScriptValueImpl mathObject; + QScript::Ecma::Math::construct(&mathObject, this); + m_globalObject.setProperty(QLatin1String("Math"), mathObject, flags); + + enumerationConstructor = new QScript::Ext::Enumeration(this); + + variantConstructor = new QScript::Ext::Variant(this); + +#ifndef QT_NO_QOBJECT + qobjectConstructor = new QScript::ExtQObject(this); + qmetaObjectConstructor = new QScript::ExtQMetaObject(this); +#endif + + objectAllocator.blockGC(false); + + QScriptContextPrivate *context_p = pushContext(); + context_p->setActivationObject(m_globalObject); + context_p->setThisObject(m_globalObject); +} + +#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY) +static QScriptValueImpl __setupPackage__(QScriptContextPrivate *ctx, + QScriptEnginePrivate *eng, + QScriptClassInfo *) +{ + QString path = ctx->argument(0).toString(); + QStringList components = path.split(QLatin1Char('.')); + QScriptValueImpl o = eng->globalObject(); + for (int i = 0; i < components.count(); ++i) { + QString name = components.at(i); + QScriptValueImpl oo = o.property(name); + if (!oo.isValid()) { + oo = eng->newObject(); + o.setProperty(name, oo); + } + o = oo; + } + return o; +} +#endif + +QScriptValueImpl QScriptEnginePrivate::importExtension(const QString &extension) +{ +#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) + Q_UNUSED(extension); +#else + Q_Q(QScriptEngine); + if (m_importedExtensions.contains(extension)) + return undefinedValue(); // already imported + + QScriptContextPrivate *context = currentContext(); + QCoreApplication *app = QCoreApplication::instance(); + if (!app) + return context->throwError(QLatin1String("No application object")); + + QObjectList staticPlugins = QPluginLoader::staticInstances(); + QStringList libraryPaths = app->libraryPaths(); + QString dot = QLatin1String("."); + QStringList pathComponents = extension.split(dot); + QString initDotJs = QLatin1String("__init__.js"); + + QString ext; + for (int i = 0; i < pathComponents.count(); ++i) { + if (!ext.isEmpty()) + ext.append(dot); + ext.append(pathComponents.at(i)); + if (m_importedExtensions.contains(ext)) + continue; // already imported + + if (m_extensionsBeingImported.contains(ext)) { + return context->throwError(QString::fromLatin1("recursive import of %0") + .arg(extension)); + } + m_extensionsBeingImported.insert(ext); + + QScriptExtensionInterface *iface = 0; + QString initjsContents; + QString initjsFileName; + + // look for the extension in static plugins + for (int j = 0; j < staticPlugins.size(); ++j) { + iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j)); + if (!iface) + continue; + if (iface->keys().contains(ext)) + break; // use this one + else + iface = 0; // keep looking + } + + { + // look for __init__.js resource + QString path = QString::fromLatin1(":/qtscriptextension"); + for (int j = 0; j <= i; ++j) { + path.append(QLatin1Char('/')); + path.append(pathComponents.at(j)); + } + path.append(QLatin1Char('/')); + path.append(initDotJs); + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + QTextStream ts(&file); + initjsContents = ts.readAll(); + initjsFileName = path; + file.close(); + } + } + + if (!iface && initjsContents.isEmpty()) { + // look for the extension in library paths + for (int j = 0; j < libraryPaths.count(); ++j) { + QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script"); + QDir dir(libPath); + if (!dir.exists(dot)) + continue; + + // look for C++ plugin + QFileInfoList files = dir.entryInfoList(QDir::Files); + for (int k = 0; k < files.count(); ++k) { + QFileInfo entry = files.at(k); + QString filePath = entry.canonicalFilePath(); + QPluginLoader loader(filePath); + iface = qobject_cast<QScriptExtensionInterface*>(loader.instance()); + if (iface) { + if (iface->keys().contains(ext)) + break; // use this one + else + iface = 0; // keep looking + } + } + + // look for __init__.js in the corresponding dir + QDir dirdir(libPath); + bool dirExists = dirdir.exists(); + for (int k = 0; dirExists && (k <= i); ++k) + dirExists = dirdir.cd(pathComponents.at(k)); + if (dirExists && dirdir.exists(initDotJs)) { + QFile file(dirdir.canonicalPath() + + QDir::separator() + initDotJs); + if (file.open(QIODevice::ReadOnly)) { + QTextStream ts(&file); + initjsContents = ts.readAll(); + initjsFileName = file.fileName(); + file.close(); + } + } + + if (iface || !initjsContents.isEmpty()) + break; + } + } + + if (!iface && initjsContents.isEmpty()) { + m_extensionsBeingImported.remove(ext); + return context->throwError( + QString::fromLatin1("Unable to import %0: no such extension") + .arg(extension)); + } + + // initialize the extension in a new context + QScriptContextPrivate *ctx_p = pushContext(); + ctx_p->setThisObject(globalObject()); + newActivation(&ctx_p->m_activation); + QScriptObject *activation_data = ctx_p->m_activation.m_object_value; + activation_data->m_scope = globalObject(); + + activation_data->m_members.resize(4); + activation_data->m_values.resize(4); + activation_data->m_members[0].object( + nameId(QLatin1String("__extension__")), 0, + QScriptValue::ReadOnly | QScriptValue::Undeletable); + activation_data->m_values[0] = QScriptValueImpl(this, ext); + activation_data->m_members[1].object( + nameId(QLatin1String("__setupPackage__")), 1, 0); + activation_data->m_values[1] = createFunction(__setupPackage__, 0, 0); + activation_data->m_members[2].object( + nameId(QLatin1String("__all__")), 2, 0); + activation_data->m_values[2] = undefinedValue(); + activation_data->m_members[3].object( + nameId(QLatin1String("__postInit__")), 3, 0); + activation_data->m_values[3] = undefinedValue(); + + // the script is evaluated first + if (!initjsContents.isEmpty()) { + evaluate(ctx_p, initjsContents, /*lineNumber=*/1, initjsFileName); + if (hasUncaughtException()) { + QScriptValueImpl r = ctx_p->returnValue(); + popContext(); + m_extensionsBeingImported.remove(ext); + return r; + } + } + + // next, the C++ plugin is called + if (iface) { + iface->initialize(ext, q); + if (hasUncaughtException()) { + QScriptValueImpl r = ctx_p->returnValue(); + popContext(); + m_extensionsBeingImported.remove(ext); + return r; + } + } + + // if the __postInit__ function has been set, we call it + QScriptValueImpl postInit = ctx_p->m_activation.property(QLatin1String("__postInit__")); + if (postInit.isFunction()) { + postInit.call(globalObject()); + if (hasUncaughtException()) { + QScriptValueImpl r = ctx_p->returnValue(); + popContext(); + m_extensionsBeingImported.remove(ext); + return r; + } + } + + popContext(); + + m_importedExtensions.insert(ext); + m_extensionsBeingImported.remove(ext); + } // for (i) +#endif // QT_NO_QOBJECT + return undefinedValue(); +} + +QStringList QScriptEnginePrivate::availableExtensions() const +{ +#if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) + return QStringList(); +#else + QCoreApplication *app = QCoreApplication::instance(); + if (!app) + return QStringList(); + + QSet<QString> result; + + QObjectList staticPlugins = QPluginLoader::staticInstances(); + for (int i = 0; i < staticPlugins.size(); ++i) { + QScriptExtensionInterface *iface; + iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i)); + if (iface) { + QStringList keys = iface->keys(); + for (int j = 0; j < keys.count(); ++j) + result << keys.at(j); + } + } + + QStringList libraryPaths = app->libraryPaths(); + for (int i = 0; i < libraryPaths.count(); ++i) { + QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script"); + QDir dir(libPath); + if (!dir.exists()) + continue; + + // look for C++ plugins + QFileInfoList files = dir.entryInfoList(QDir::Files); + for (int j = 0; j < files.count(); ++j) { + QFileInfo entry = files.at(j); + QString filePath = entry.canonicalFilePath(); + QPluginLoader loader(filePath); + QScriptExtensionInterface *iface; + iface = qobject_cast<QScriptExtensionInterface*>(loader.instance()); + if (iface) { + QStringList keys = iface->keys(); + for (int k = 0; k < keys.count(); ++k) + result << keys.at(k); + } + } + + // look for scripts + QString initDotJs = QLatin1String("__init__.js"); + QList<QFileInfo> stack; + stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + while (!stack.isEmpty()) { + QFileInfo entry = stack.takeLast(); + QDir dd(entry.canonicalFilePath()); + if (dd.exists(initDotJs)) { + QString rpath = dir.relativeFilePath(dd.canonicalPath()); + QStringList components = rpath.split(QLatin1Char('/')); + result << components.join(QLatin1String(".")); + stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + } + } + } + + QStringList lst = result.toList(); + qSort(lst); + return lst; +#endif +} + +QStringList QScriptEnginePrivate::importedExtensions() const +{ + QStringList lst = m_importedExtensions.toList(); + qSort(lst); + return lst; +} + +void QScriptEnginePrivate::gc() +{ + if (!objectAllocator.blocked()) { + // do the GC now + maybeGC_helper(/*do_string_gc=*/true); + } else { + // GC will be performed the next time maybeGC() + // is called and the allocator is not blocked + objectAllocator.requestGC(); + } +} + +QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const +{ + QScriptValueImpl value = uncaughtException(); + if (!value.isError()) + return m_exceptionBacktrace; + return QScript::Ecma::Error::backtrace(value); +} + +void QScriptEnginePrivate::clearExceptions() +{ + m_exceptionBacktrace = QStringList(); + QScriptContextPrivate *ctx_p = currentContext(); + while (ctx_p) { + ctx_p->m_state = QScriptContext::NormalState; + ctx_p = ctx_p->parentContext(); + } +} + +#ifndef QT_NO_QOBJECT +void QScriptEnginePrivate::emitSignalHandlerException() +{ + Q_Q(QScriptEngine); + emit q->signalHandlerException(toPublic(uncaughtException())); +} +#endif + +void QScriptEnginePrivate::processEvents() +{ +#ifndef QT_NO_QOBJECT + Q_ASSERT(m_processEventTracker.isValid()); + int elapsed = m_processEventTracker.elapsed(); + if (m_nextProcessEvents < elapsed) { + do { + m_nextProcessEvents = m_nextProcessEvents + m_processEventsInterval; + } while (m_nextProcessEvents < elapsed); + QCoreApplication::processEvents(); + } +#endif +} + +void QScriptEnginePrivate::setupProcessEvents() +{ + if (m_processEventsInterval > 0) { + m_nextProcessEvents = m_processEventsInterval; + m_processEventIncr = 0; + m_processEventTracker.restart(); + } +} + +void QScriptEnginePrivate::abortEvaluation(const QScriptValueImpl &result) +{ + m_abort = true; + currentContext()->setReturnValue(result); +} + +#ifndef QT_NO_QOBJECT + +void QScriptEnginePrivate::newQObject(QScriptValueImpl *out, QObject *object, + QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options, + bool setDefaultPrototype) +{ + if (!object) { + *out = m_nullValue; + return; + } + Q_ASSERT(qobjectConstructor != 0); + QScriptQObjectData *data = qobjectData(object); + bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0; + QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject; + QScriptValueImpl existingWrapper; + bool hasExisting = data->findWrapper(ownership, opt, &existingWrapper); + if (preferExisting) { + if (hasExisting) { + *out = existingWrapper; + } else { + qobjectConstructor->newQObject(out, object, ownership, opt); + data->registerWrapper(*out, ownership, opt); + } + } else { + qobjectConstructor->newQObject(out, object, ownership, opt); + if (!hasExisting) + data->registerWrapper(*out, ownership, opt); + } + + if (setDefaultPrototype) { + const QMetaObject *meta = object->metaObject(); + while (meta) { + QByteArray typeString = meta->className(); + typeString.append('*'); + int typeId = QMetaType::type(typeString); + if (typeId != 0) { + QScriptValueImpl proto = defaultPrototype(typeId); + if (proto.isValid()) { + out->setPrototype(proto); + break; + } + } + meta = meta->superClass(); + } + } +} + +QScriptQObjectData *QScriptEnginePrivate::qobjectData(QObject *object) +{ + QHash<QObject*, QScriptQObjectData*>::const_iterator it; + it = m_qobjectData.constFind(object); + if (it != m_qobjectData.constEnd()) + return it.value(); + + QScriptQObjectData *data = new QScriptQObjectData(); + m_qobjectData.insert(object, data); + QObject::connect(object, SIGNAL(destroyed(QObject*)), + q_func(), SLOT(_q_objectDestroyed(QObject *))); + return data; +} + +void QScriptEnginePrivate::_q_objectDestroyed(QObject *object) +{ + QHash<QObject*, QScriptQObjectData*>::iterator it; + it = m_qobjectData.find(object); + Q_ASSERT(it != m_qobjectData.end()); + QScriptQObjectData *data = it.value(); + m_qobjectData.erase(it); + delete data; +} + +void QScriptEnginePrivate::disposeQObject(QObject *object) +{ + if (isCollecting()) { + // wait until we're done with GC before deleting it + int index = m_qobjectsToBeDeleted.indexOf(object); + if (index == -1) + m_qobjectsToBeDeleted.append(object); + } else { + delete object; + } +} + +void QScriptEnginePrivate::deletePendingQObjects() +{ + while (!m_qobjectsToBeDeleted.isEmpty()) + delete m_qobjectsToBeDeleted.takeFirst(); +} + +bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function) +{ + Q_ASSERT(sender); + Q_ASSERT(signal); + const QMetaObject *meta = sender->metaObject(); + int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1)); + if (index == -1) + return false; + return scriptConnect(sender, index, receiver, function); +} + +bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function) +{ + Q_ASSERT(sender); + Q_ASSERT(signal); + const QMetaObject *meta = sender->metaObject(); + int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1)); + if (index == -1) + return false; + return scriptDisconnect(sender, index, receiver, function); +} + +bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function, + const QScriptValueImpl &senderWrapper) +{ + QScriptQObjectData *data = qobjectData(sender); + return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper); +} + +bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function) +{ + QScriptQObjectData *data = qobjectData(sender); + if (!data) + return false; + return data->removeSignalHandler(sender, signalIndex, receiver, function); +} + +bool QScriptEnginePrivate::scriptConnect(const QScriptValueImpl &signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function) +{ + QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction()); + int index = fun->mostGeneralMethod(); + return scriptConnect(fun->qobject(), index, receiver, function, fun->object()); +} + +bool QScriptEnginePrivate::scriptDisconnect(const QScriptValueImpl &signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function) +{ + QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction()); + int index = fun->mostGeneralMethod(); + return scriptDisconnect(fun->qobject(), index, receiver, function); +} + +bool QScriptEnginePrivate::convertToNativeQObject(const QScriptValueImpl &value, + const QByteArray &targetType, + void **result) +{ + if (!targetType.endsWith('*')) + return false; + if (QObject *qobject = value.toQObject()) { + int start = targetType.startsWith("const ") ? 6 : 0; + QByteArray className = targetType.mid(start, targetType.size()-start-1); + if (void *instance = qobject->qt_metacast(className)) { + *result = instance; + return true; + } + } + return false; +} + +#endif // QT_NO_QOBJECT + +void QScriptEnginePrivate::setAgent(QScriptEngineAgent *agent) +{ + Q_Q(QScriptEngine); + if (agent && (agent->engine() != q)) { + qWarning("QScriptEngine::setAgent(): " + "cannot set agent belonging to different engine"); + return; + } + if (agent) { + int index = m_agents.indexOf(agent); + if (index == -1) + m_agents.append(agent); + } + m_agent = agent; +} + +QScriptEngineAgent *QScriptEnginePrivate::agent() const +{ + return m_agent; +} + +void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent) +{ + m_agents.removeOne(agent); + if (m_agent == agent) + m_agent = 0; +} + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY +qint64 QScriptEnginePrivate::nextScriptId() +{ + // ### reuse IDs by using a pool + return m_scriptCounter++; +} + +void QScriptEnginePrivate::notifyScriptLoad_helper(qint64 id, const QString &program, + const QString &fileName, int lineNumber) +{ + m_agent->scriptLoad(id, program, fileName, lineNumber); +} + +void QScriptEnginePrivate::notifyScriptUnload_helper(qint64 id) +{ + m_agent->scriptUnload(id); +} + +void QScriptEnginePrivate::notifyPositionChange_helper(QScriptContextPrivate *ctx) +{ + m_agent->positionChange(ctx->scriptId(), ctx->currentLine, ctx->currentColumn); +} + +void QScriptEnginePrivate::notifyContextPush_helper() +{ + m_agent->contextPush(); +} + +void QScriptEnginePrivate::notifyContextPop_helper() +{ + m_agent->contextPop(); +} + +void QScriptEnginePrivate::notifyFunctionEntry_helper(QScriptContextPrivate *ctx) +{ + m_agent->functionEntry(ctx->scriptId()); +} + +void QScriptEnginePrivate::notifyFunctionExit_helper(QScriptContextPrivate *ctx) +{ + m_agent->functionExit(ctx->scriptId(), toPublic(ctx->returnValue())); +} + +void QScriptEnginePrivate::notifyException_helper(QScriptContextPrivate *ctx) +{ + bool hasHandler = (ctx->exceptionHandlerContext() != 0); + m_agent->exceptionThrow(ctx->scriptId(), toPublic(ctx->returnValue()), hasHandler); +} + +void QScriptEnginePrivate::notifyExceptionCatch_helper(QScriptContextPrivate *ctx) +{ + m_agent->exceptionCatch(ctx->scriptId(), toPublic(ctx->returnValue())); +} + +void QScriptEnginePrivate::notifyDebugger(QScriptContextPrivate *ctx) +{ + if (m_agent && m_agent->supportsExtension(QScriptEngineAgent::DebuggerInvocationRequest)) { + QVariantList args; + args.append(ctx->scriptId()); + args.append(ctx->currentLine); + args.append(ctx->currentColumn); + QVariant ret = m_agent->extension(QScriptEngineAgent::DebuggerInvocationRequest, args); + QScriptValueImpl val = valueFromVariant(ret); + if (val.isValid()) + ctx->m_result = val; + } +} + +#endif // Q_SCRIPT_NO_EVENT_NOTIFY + +QScriptString QScriptEnginePrivate::internedString(const QString &str) +{ + return internedString(nameId(str, /*persistent=*/false)); +} + +QScriptString QScriptEnginePrivate::internedString(QScriptNameIdImpl *nid) +{ + if (!nid) + return QScriptString(); + QScriptStringPrivate *d = m_internedStrings.value(nid); + if (!d) { + d = m_internedStringRepository.get(); + d->nameId = nid; + d->engine = this; + m_internedStrings.insert(d->nameId, d); + } + QScriptString result; + QScriptStringPrivate::init(result, d); + return result; +} + +void QScriptEnginePrivate::uninternString(QScriptStringPrivate *d) +{ + Q_ASSERT(d->nameId); + QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::iterator it; + it = m_internedStrings.find(d->nameId); + Q_ASSERT(it != m_internedStrings.end()); + m_internedStrings.erase(it); + m_internedStringRepository.release(d); +} + +QScriptValueImpl QScriptEnginePrivate::toImpl_helper(const QScriptValue &value) +{ + QScriptValuePrivate *p = QScriptValuePrivate::get(value); + Q_ASSERT(p != 0); + Q_ASSERT(p->value.type() == QScript::LazyStringType); + QString str = *p->value.m_lazy_string_value; + if (!p->ref.deref()) + delete p; + QScriptValueImpl v; + newString(&v, str); + p = registerValue(v); + QScriptValuePrivate::init(const_cast<QScriptValue&>(value), p); + return v; +} + +QScriptValueImpl QScriptEnginePrivate::newObject(QScriptClass *scriptClass, + const QScriptValueImpl &data) +{ + if (!scriptClass) + return QScriptValueImpl(); + QScriptValueImpl v; + QScriptValueImpl proto = toImpl(scriptClass->prototype()); + if (!proto.isObject()) + proto = objectConstructor->publicPrototype; + newObject(&v, proto); + QScriptClassPrivate *cls_p = QScriptClassPrivate::get(scriptClass); + QScriptClassInfo *info = cls_p->classInfo(); + v.setClassInfo(info); + if (info->type() & QScriptClassInfo::FunctionBased) { + QScriptFunction *fun = cls_p->newFunction(); + v.setObjectData(fun); + } + v.setInternalValue(data); + return v; +} + +int QScriptEnginePrivate::registerCustomClassType() +{ + return ++m_class_prev_id; +} + +QScriptValueImpl QScriptEnginePrivate::objectById(qint64 id) const +{ + QScript::GCAlloc<QScriptObject>::const_iterator it; + for (it = objectAllocator.constBegin(); it != objectAllocator.constEnd(); ++it) { + const QScriptObject *obj = it.data(); + if (obj->m_id == id) { + QScriptValueImpl ret; + ret.m_type = QScript::ObjectType; + ret.m_object_value = const_cast<QScriptObject*>(obj); + return ret; + } + } + return QScriptValueImpl(); +} + +namespace QScript { + +static QScriptValueImpl qsTranslate(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + if (ctx->argumentCount() < 2) + return ctx->throwError(QString::fromLatin1("qsTranslate() requires at least two arguments")); + if (!ctx->argument(0).isString()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): first argument (context) must be a string")); + if (!ctx->argument(1).isString()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): second argument (text) must be a string")); + if ((ctx->argumentCount() > 2) && !ctx->argument(2).isString()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (comment) must be a string")); + if ((ctx->argumentCount() > 3) && !ctx->argument(3).isString()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): fourth argument (encoding) must be a string")); + if ((ctx->argumentCount() > 4) && !ctx->argument(4).isNumber()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): fifth argument (n) must be a number")); +#ifndef QT_NO_QOBJECT + QString context = ctx->argument(0).toString(); +#endif + QString text = ctx->argument(1).toString(); +#ifndef QT_NO_QOBJECT + QString comment; + if (ctx->argumentCount() > 2) + comment = ctx->argument(2).toString(); + QCoreApplication::Encoding encoding = QCoreApplication::CodecForTr; + if (ctx->argumentCount() > 3) { + QString encStr = ctx->argument(3).toString(); + if (encStr == QLatin1String("CodecForTr")) + encoding = QCoreApplication::CodecForTr; + else if (encStr == QLatin1String("UnicodeUTF8")) + encoding = QCoreApplication::UnicodeUTF8; + else + return ctx->throwError(QString::fromLatin1("qsTranslate(): invalid encoding '%s'").arg(encStr)); + } + int n = -1; + if (ctx->argumentCount() > 4) + n = ctx->argument(4).toInt32(); +#endif + QString result; +#ifndef QT_NO_QOBJECT + result = QCoreApplication::translate(context.toLatin1().constData(), + text.toLatin1().constData(), + comment.toLatin1().constData(), + encoding, n); +#else + result = text; +#endif + return QScriptValueImpl(eng, result); +} + +static QScriptValueImpl qTranslateNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *) +{ + return ctx->argument(1); +} + +static QScriptValueImpl qsTr(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *) +{ + if (ctx->argumentCount() < 1) + return ctx->throwError(QString::fromLatin1("qsTr() requires at least one argument")); + if (!ctx->argument(0).isString()) + return ctx->throwError(QString::fromLatin1("qsTr(): first argument (text) must be a string")); + if ((ctx->argumentCount() > 1) && !ctx->argument(1).isString()) + return ctx->throwError(QString::fromLatin1("qsTr(): second argument (comment) must be a string")); + if ((ctx->argumentCount() > 2) && !ctx->argument(2).isNumber()) + return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (n) must be a number")); +#ifndef QT_NO_QOBJECT + QString context; + if (ctx->parentContext()) + context = QFileInfo(ctx->parentContext()->fileName()).baseName(); +#endif + QString text = ctx->argument(0).toString(); +#ifndef QT_NO_QOBJECT + QString comment; + if (ctx->argumentCount() > 1) + comment = ctx->argument(1).toString(); + int n = -1; + if (ctx->argumentCount() > 2) + n = ctx->argument(2).toInt32(); +#endif + QString result; +#ifndef QT_NO_QOBJECT + result = QCoreApplication::translate(context.toLatin1().constData(), + text.toLatin1().constData(), + comment.toLatin1().constData(), + QCoreApplication::CodecForTr, n); +#else + result = text; +#endif + return QScriptValueImpl(eng, result); +} + +static QScriptValueImpl qTrNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *) +{ + return ctx->argument(0); +} + +} // namespace QScript + +void QScriptEnginePrivate::installTranslatorFunctions(QScriptValueImpl &object) +{ + Q_ASSERT(object.isObject()); + const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration; + object.setProperty(QLatin1String("qsTranslate"), + createFunction(QScript::qsTranslate, /*length=*/5, /*classInfo=*/0), + flags); + object.setProperty(QLatin1String("QT_TRANSLATE_NOOP"), + createFunction(QScript::qTranslateNoOp, /*length=*/2, /*classInfo=*/0), + flags); + object.setProperty(QLatin1String("qsTr"), + createFunction(QScript::qsTr, /*length=*/3, /*classInfo=*/0), + flags); + object.setProperty(QLatin1String("QT_TR_NOOP"), + createFunction(QScript::qTrNoOp, /*length=*/1, /*classInfo=*/0), + flags); + + stringConstructor->addPrototypeFunction(QLatin1String("arg"), QScript::Ecma::String::method_ext_arg, 1); +} + +bool QScriptEnginePrivate::canEvaluate(const QString &program) +{ + QScript::SyntaxChecker checker; + QScript::SyntaxChecker::Result result = checker.checkSyntax(program); + return (result.state != QScript::SyntaxChecker::Intermediate); +} + +QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program) +{ + QScript::SyntaxChecker checker; + QScript::SyntaxChecker::Result result = checker.checkSyntax(program); + QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate(); + switch (result.state) { + case QScript::SyntaxChecker::Error: + p->state = QScriptSyntaxCheckResult::Error; + break; + case QScript::SyntaxChecker::Intermediate: + p->state = QScriptSyntaxCheckResult::Intermediate; + break; + case QScript::SyntaxChecker::Valid: + p->state = QScriptSyntaxCheckResult::Valid; + break; + } + p->errorLineNumber = result.errorLineNumber; + p->errorColumnNumber = result.errorColumnNumber; + p->errorMessage = result.errorMessage; + return QScriptSyntaxCheckResult(p); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptengine_p.h b/src/script/qscriptengine_p.h new file mode 100644 index 0000000..3d13628 --- /dev/null +++ b/src/script/qscriptengine_p.h @@ -0,0 +1,828 @@ +/**************************************************************************** +** +** 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 QSCRIPTENGINE_P_H +#define QSCRIPTENGINE_P_H + +#include "qscriptenginefwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include <QtCore/QDateTime> +#include <QtCore/QMutex> +#include <QtCore/QLinkedList> +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QHash> +#include <QtCore/qnumeric.h> + +#include "qscriptengine.h" +#include "qscriptnameid_p.h" +#include "qscriptobjectfwd_p.h" +#include "qscriptrepository_p.h" +#include "qscriptgc_p.h" +#include "qscriptecmaarray_p.h" +#include "qscriptecmadate_p.h" +#include "qscriptecmaobject_p.h" +#include "qscriptecmaboolean_p.h" +#include "qscriptecmanumber_p.h" +#include "qscriptecmastring_p.h" +#include "qscriptecmafunction_p.h" +#include "qscriptextvariant_p.h" +#include "qscriptextqobject_p.h" +#include "qscriptvalue_p.h" +#include "qscriptcontextfwd_p.h" + +#include <math.h> + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +namespace QScript { + +class ArgumentsObjectData: public QScriptObjectData +{ +public: + ArgumentsObjectData() : length(0) {} + virtual ~ArgumentsObjectData() {} + +public: // attributes + QScriptValueImpl activation; + uint length; +}; + +} // namespace QScript + +inline QScriptEnginePrivate *QScriptEnginePrivate::get(QScriptEngine *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline const QScriptEnginePrivate *QScriptEnginePrivate::get(const QScriptEngine *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline QScriptEngine *QScriptEnginePrivate::get(QScriptEnginePrivate *d) +{ + return d->q_func(); +} + +inline QString QScriptEnginePrivate::toString(QScriptNameIdImpl *id) +{ + if (! id) + return QString(); + + return id->s; +} + +inline QString QScriptEnginePrivate::memberName(const QScript::Member &member) const +{ + return toString(member.nameId()); +} + +inline void QScriptEnginePrivate::newReference(QScriptValueImpl *o, int mode) +{ + Q_ASSERT(o); + o->m_type = QScript::ReferenceType; + o->m_int_value = (mode); +} + +inline void QScriptEnginePrivate::newActivation(QScriptValueImpl *o) +{ + Q_ASSERT(o); + newObject(o, nullValue(), m_class_activation); +} + +inline void QScriptEnginePrivate::newPointer(QScriptValueImpl *o, void *ptr) +{ + Q_ASSERT(o); + o->m_type = QScript::PointerType; + o->m_ptr_value = ptr; +} + +inline void QScriptEnginePrivate::newInteger(QScriptValueImpl *o, int i) +{ + Q_ASSERT(o); + o->m_type = QScript::IntegerType; + o->m_int_value = (i); +} + +inline void QScriptEnginePrivate::newNameId(QScriptValueImpl *o, const QString &s) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + o->m_string_value = (nameId(s, /*persistent=*/false)); +} + +inline void QScriptEnginePrivate::newString(QScriptValueImpl *o, const QString &s) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + QScriptNameIdImpl *entry = new QScriptNameIdImpl(s); + m_tempStringRepository.append(entry); + o->m_string_value = (entry); + m_newAllocatedTempStringRepositoryChars += s.length(); +} + +inline void QScriptEnginePrivate::newNameId(QScriptValueImpl *o, QScriptNameIdImpl *id) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + o->m_string_value = (id); +} + +inline const QScript::IdTable *QScriptEnginePrivate::idTable() const +{ + return &m_id_table; +} + +inline qsreal QScriptEnginePrivate::convertToNativeDouble(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isNumber()) + return value.m_number_value; + + return convertToNativeDouble_helper(value); +} + +inline qint32 QScriptEnginePrivate::convertToNativeInt32(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + return toInt32 (convertToNativeDouble(value)); +} + + +inline bool QScriptEnginePrivate::convertToNativeBoolean(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isBoolean()) + return value.m_bool_value; + + return convertToNativeBoolean_helper(value); +} + +inline QString QScriptEnginePrivate::convertToNativeString(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isString()) + return value.m_string_value->s; + + return convertToNativeString_helper(value); +} + +inline qsreal QScriptEnginePrivate::toInteger(qsreal n) +{ + if (qIsNaN(n)) + return 0; + + if (n == 0 || qIsInf(n)) + return n; + + int sign = n < 0 ? -1 : 1; + return sign * ::floor(::fabs(n)); +} + +inline qint32 QScriptEnginePrivate::toInt32(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D32); + const double D31 = D32 / 2.0; + + if (sign == -1 && n < -D31) + n += D32; + + else if (sign != -1 && n >= D31) + n -= D32; + + return qint32 (n); +} + +inline quint32 QScriptEnginePrivate::toUint32(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D32); + + if (n < 0) + n += D32; + + return quint32 (n); +} + +inline quint16 QScriptEnginePrivate::toUint16(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D16); + + if (n < 0) + n += D16; + + return quint16 (n); +} + +inline QScript::AST::Node *QScriptEnginePrivate::abstractSyntaxTree() const +{ + return m_abstractSyntaxTree; +} + +inline QScript::MemoryPool *QScriptEnginePrivate::nodePool() +{ + return m_pool; +} + +inline void QScriptEnginePrivate::setNodePool(QScript::MemoryPool *pool) +{ + m_pool = pool; +} + +inline QScript::Lexer *QScriptEnginePrivate::lexer() +{ + return m_lexer; +} + +inline void QScriptEnginePrivate::setLexer(QScript::Lexer *lexer) +{ + m_lexer = lexer; +} + +inline QScriptObject *QScriptEnginePrivate::allocObject() +{ + return objectAllocator(m_objectGeneration); +} + +inline QScriptContextPrivate *QScriptEnginePrivate::currentContext() const +{ + return m_context; +} + +inline QScriptContextPrivate *QScriptEnginePrivate::pushContext() +{ + QScriptContext *context = m_frameRepository.get(); + QScriptContextPrivate *ctx_p = QScriptContextPrivate::get(context); + ctx_p->init(m_context); + m_context = ctx_p; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + notifyContextPush(); +#endif + return m_context; +} + +inline void QScriptEnginePrivate::popContext() +{ + Q_ASSERT(m_context != 0); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + notifyContextPop(); +#endif + QScriptContextPrivate *context = m_context; + m_context = context->parentContext(); + if (m_context) { + QScriptContextPrivate *p1 = m_context; + QScriptContextPrivate *p2 = context; + if ((p1->m_state != QScriptContext::ExceptionState) + || (p2->m_state == QScriptContext::ExceptionState)) { + // propagate the state + p1->m_result = p2->m_result; + p1->m_state = p2->m_state; + // only update errorLineNumber if there actually was an exception + if (p2->m_state == QScriptContext::ExceptionState) { + if (p2->errorLineNumber != -1) + p1->errorLineNumber = p2->errorLineNumber; + else + p1->errorLineNumber = p1->currentLine; + } + } + } + m_frameRepository.release(QScriptContextPrivate::get(context)); +} + +inline void QScriptEnginePrivate::maybeGC() +{ + if (objectAllocator.blocked()) + return; + + bool do_string_gc = ((m_stringRepository.size() - m_oldStringRepositorySize) > 256) + || (m_newAllocatedStringRepositoryChars > 0x800000); + do_string_gc |= ((m_tempStringRepository.size() - m_oldTempStringRepositorySize) > 1024) + || (m_newAllocatedTempStringRepositoryChars > 0x800000); + + if (! do_string_gc && ! objectAllocator.poll()) + return; + + maybeGC_helper(do_string_gc); +} + +inline void QScriptEnginePrivate::adjustBytesAllocated(int bytes) +{ + objectAllocator.adjustBytesAllocated(bytes); +} + +inline bool QScriptEnginePrivate::blockGC(bool block) +{ + return objectAllocator.blockGC(block); +} + +inline void QScriptEnginePrivate::markString(QScriptNameIdImpl *id, int /*generation*/) +{ + id->used = true; +} + +inline QScriptValueImpl QScriptEnginePrivate::createFunction(QScriptFunction *fun) +{ + QScriptValueImpl v; + newFunction(&v, fun); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::newArray(const QScript::Array &value) +{ + QScriptValueImpl v; + newArray(&v, value); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::newArray(uint length) +{ + QScriptValueImpl v; + QScript::Array a(this); + a.resize(length); + newArray(&v, a); + return v; +} + +inline QScriptClassInfo *QScriptEnginePrivate::registerClass(const QString &pname, int type) +{ + if (type == -1) + type = ++m_class_prev_id; + + QScriptClassInfo *oc = new QScriptClassInfo(this, QScriptClassInfo::Type(type), pname); + m_allocated_classes.append(oc); + + return oc; +} + +inline QScriptClassInfo *QScriptEnginePrivate::registerClass(const QString &name) +{ + return registerClass(name, -1); +} + +inline QScriptValueImpl QScriptEnginePrivate::createFunction(QScriptInternalFunctionSignature fun, + int length, QScriptClassInfo *classInfo, const QString &name) +{ + return createFunction(new QScript::C2Function(fun, length, classInfo, name)); +} + +inline void QScriptEnginePrivate::newFunction(QScriptValueImpl *o, QScriptFunction *function) +{ + QScriptValueImpl proto; + if (functionConstructor) + proto = functionConstructor->publicPrototype; + else { + // creating the Function prototype object + Q_ASSERT(objectConstructor); + proto = objectConstructor->publicPrototype; + } + newObject(o, proto, m_class_function); + o->setObjectData(function); +} + +inline void QScriptEnginePrivate::newConstructor(QScriptValueImpl *ctor, + QScriptFunction *function, + QScriptValueImpl &proto) +{ + newFunction(ctor, function); + ctor->setProperty(m_id_table.id_prototype, proto, + QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration); + proto.setProperty(m_id_table.id_constructor, *ctor, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); +} + +inline void QScriptEnginePrivate::newArguments(QScriptValueImpl *object, + const QScriptValueImpl &activation, + uint length, + const QScriptValueImpl &callee) +{ + QScript::ArgumentsObjectData *data = new QScript::ArgumentsObjectData(); + data->activation = activation; + data->length = length; + newObject(object, m_class_arguments); + object->setObjectData(data); + object->setProperty(m_id_table.id_callee, callee, + QScriptValue::SkipInEnumeration); + object->setProperty(m_id_table.id_length, QScriptValueImpl(length), + QScriptValue::SkipInEnumeration); +} + +inline QScriptFunction *QScriptEnginePrivate::convertToNativeFunction(const QScriptValueImpl &object) +{ + if (object.isFunction()) + return static_cast<QScriptFunction*> (object.objectData()); + return 0; +} + +inline QScriptValue QScriptEnginePrivate::toPublic(const QScriptValueImpl &value) +{ + if (!value.isValid()) + return QScriptValue(); + + QScriptValuePrivate *p = registerValue(value); + QScriptValue v; + QScriptValuePrivate::init(v, p); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::toImpl(const QScriptValue &value) +{ + QScriptValuePrivate *p = QScriptValuePrivate::get(value); + if (!p) + return QScriptValueImpl(); + if (p->value.type() == QScript::LazyStringType) + return toImpl_helper(value); + return p->value; +} + +inline QScriptValueImplList QScriptEnginePrivate::toImplList(const QScriptValueList &lst) +{ + QScriptValueImplList result; + QScriptValueList::const_iterator it; + for (it = lst.constBegin(); it != lst.constEnd(); ++it) + result.append(toImpl(*it)); + return result; +} + +inline QScriptValueImpl QScriptEnginePrivate::toObject(const QScriptValueImpl &value) +{ + if (value.isObject() || !value.isValid()) + return value; + return toObject_helper(value); +} + +inline QScriptValueImpl QScriptEnginePrivate::toPrimitive(const QScriptValueImpl &object, + QScriptValueImpl::TypeHint hint) +{ + Q_ASSERT(object.isValid()); + + if (! object.isObject()) + return object; + + return toPrimitive_helper(object, hint); +} + +inline QDateTime QScriptEnginePrivate::toDateTime(const QScriptValueImpl &value) const +{ + return dateConstructor->toDateTime(value); +} + +inline void QScriptEnginePrivate::newArray(QScriptValueImpl *object, const QScript::Array &value) +{ + arrayConstructor->newArray(object, value); +} + +inline void QScriptEnginePrivate::newObject(QScriptValueImpl *o, const QScriptValueImpl &proto, + QScriptClassInfo *oc) +{ + Q_ASSERT(o != 0); + + QScriptObject *od = allocObject(); + od->reset(); + od->m_id = ++m_next_object_id; + if (proto.isValid()) + od->m_prototype = proto; + else { + Q_ASSERT(objectConstructor); + od->m_prototype = objectConstructor->publicPrototype; + } + + o->m_type = QScript::ObjectType; + od->m_class = (oc ? oc : m_class_object); + o->m_object_value = od; +} + +inline void QScriptEnginePrivate::newObject(QScriptValueImpl *o, QScriptClassInfo *oc) +{ + newObject(o, objectConstructor->publicPrototype, oc); +} + +inline QScriptValueImpl QScriptEnginePrivate::newObject() +{ + QScriptValueImpl v; + newObject(&v); + return v; +} + +inline void QScriptEnginePrivate::newVariant(QScriptValueImpl *out, + const QVariant &value, + bool setDefaultPrototype) +{ + Q_ASSERT(variantConstructor != 0); + variantConstructor->newVariant(out, value); + if (setDefaultPrototype) { + QScriptValueImpl proto = defaultPrototype(value.userType()); + if (proto.isValid()) + out->setPrototype(proto); + } +} + +#ifndef QT_NO_QOBJECT +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE +inline QScriptMetaObject *QScriptEnginePrivate::cachedMetaObject(const QMetaObject *meta) +{ + QScriptMetaObject *value = m_cachedMetaObjects.value(meta); + if (!value) { + value = new QScriptMetaObject; + m_cachedMetaObjects.insert(meta, value); + } + return value; +} +# endif +#endif // !QT_NO_QOBJECT + +inline QScriptNameIdImpl *QScriptEnginePrivate::nameId(const QString &str, bool persistent) +{ + QScriptNameIdImpl *entry = toStringEntry(str); + if (! entry) + entry = insertStringEntry(str); + + Q_ASSERT(entry->unique); + + if (persistent) + entry->persistent = true; + + return entry; +} + +inline QScriptNameIdImpl *QScriptEnginePrivate::intern(const QChar *u, int s) +{ + QString tmp(u, s); + return nameId(tmp, /*persistent=*/ true); +} + +inline QScriptValueImpl QScriptEnginePrivate::valueFromVariant(const QVariant &v) +{ + QScriptValueImpl result = create(v.userType(), v.data()); + Q_ASSERT(result.isValid()); + return result; +} + +inline QScriptValueImpl QScriptEnginePrivate::undefinedValue() +{ + return m_undefinedValue; +} + +inline QScriptValueImpl QScriptEnginePrivate::nullValue() +{ + return m_nullValue; +} + +inline QScriptValueImpl QScriptEnginePrivate::defaultPrototype(int metaTypeId) const +{ + QScriptCustomTypeInfo info = m_customTypes.value(metaTypeId); + return info.prototype; +} + +inline void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, const QScriptValueImpl &prototype) +{ + QScriptCustomTypeInfo info = m_customTypes.value(metaTypeId); + info.prototype = prototype; + m_customTypes.insert(metaTypeId, info); +} + +inline uint _q_scriptHash(const QString &key) +{ + const QChar *p = key.unicode(); + int n = qMin(key.size(), 128); + uint h = key.size(); + uint g; + + while (n--) { + h = (h << 4) + (*p++).unicode(); + if ((g = (h & 0xf0000000)) != 0) + h ^= g >> 23; + h &= ~g; + } + return h; +} + +inline QScriptNameIdImpl *QScriptEnginePrivate::toStringEntry(const QString &s) +{ + uint h = _q_scriptHash(s) % m_string_hash_size; + + for (QScriptNameIdImpl *entry = m_string_hash_base[h]; entry && entry->h == h; entry = entry->next) { + if (entry->s == s) + return entry; + } + + return 0; +} + +inline bool QScriptEnginePrivate::lessThan(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::lt_cmp(lhs, rhs); +} + +inline bool QScriptEnginePrivate::equals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::eq_cmp(lhs, rhs); +} + +inline bool QScriptEnginePrivate::strictlyEquals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::strict_eq_cmp(lhs, rhs); +} + +inline void QScriptEnginePrivate::unregisterValue(QScriptValuePrivate *p) +{ + QScriptValueImpl &v = p->value; + Q_ASSERT(v.isValid()); + if (v.isString()) { + QScriptNameIdImpl *id = v.stringValue(); + m_stringHandles.remove(id); + } else if (v.isObject()) { + QScriptObject *instance = v.objectValue(); + m_objectHandles.remove(instance); + } else { + int i = m_otherHandles.indexOf(p); + Q_ASSERT(i != -1); + m_otherHandles.remove(i); + } + m_handleRepository.release(p); +} + +inline QScriptValueImpl QScriptEnginePrivate::globalObject() const +{ + return m_globalObject; +} + +inline bool QScriptEnginePrivate::hasUncaughtException() const +{ + return (currentContext()->state() == QScriptContext::ExceptionState); +} + +inline QScriptValueImpl QScriptEnginePrivate::uncaughtException() const +{ + if (!hasUncaughtException()) + return QScriptValueImpl(); + return currentContext()->returnValue(); +} + +inline void QScriptEnginePrivate::maybeProcessEvents() +{ + if (m_processEventsInterval > 0 && ++m_processEventIncr > 512) { + m_processEventIncr = 0; + processEvents(); + } +} + +inline bool QScriptEnginePrivate::shouldAbort() const +{ + return m_abort; +} + +inline void QScriptEnginePrivate::resetAbortFlag() +{ + m_abort = false; +} + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + +inline bool QScriptEnginePrivate::shouldNotify() const +{ + return m_agent != 0; +} + +inline void QScriptEnginePrivate::notifyScriptLoad( + qint64 id, const QString &program, + const QString &fileName, int lineNumber) +{ + if (shouldNotify()) + notifyScriptLoad_helper(id, program, fileName, lineNumber); +} + +inline void QScriptEnginePrivate::notifyScriptUnload(qint64 id) +{ + if (shouldNotify()) + notifyScriptUnload_helper(id); +} + +inline void QScriptEnginePrivate::notifyPositionChange(QScriptContextPrivate *ctx) +{ + Q_ASSERT(m_agent != 0); + notifyPositionChange_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyContextPush() +{ + if (shouldNotify()) + notifyContextPush_helper(); +} + +inline void QScriptEnginePrivate::notifyContextPop() +{ + if (shouldNotify()) + notifyContextPop_helper(); +} + +inline void QScriptEnginePrivate::notifyFunctionEntry(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyFunctionEntry_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyFunctionExit(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyFunctionExit_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyException(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyException_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyExceptionCatch(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyExceptionCatch_helper(ctx); +} + +#endif // Q_SCRIPT_NO_EVENT_NOTIFY + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptengineagent.cpp b/src/script/qscriptengineagent.cpp new file mode 100644 index 0000000..bda94ae --- /dev/null +++ b/src/script/qscriptengineagent.cpp @@ -0,0 +1,444 @@ +/**************************************************************************** +** +** 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 "qscriptengineagent.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalue.h" +#include "qscriptengineagent_p.h" +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptvalueimpl_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.4 + \class QScriptEngineAgent + + \brief The QScriptEngineAgent class provides an interface to report events pertaining to QScriptEngine execution. + + \ingroup script + \mainclass + + The QScriptEngineAgent class is the basis of tools that monitor and/or control the execution of a + QScriptEngine, such as debuggers and profilers. + + To process script loading and unloading events, reimplement the + scriptLoad() and scriptUnload() functions. scriptLoad() is called + after the input to QScriptEngine::evaluate() has been parsed, right + before the given script is executed. The engine assigns each + script an ID, which is available as one of the arguments to + scriptLoad(); subsequently, other event handlers can use the ID to + identify a particular script. One common usage of scriptLoad() is + to retain the script text, filename and base line number (the + original input to QScriptEngine::evaluate()), so that other event + handlers can e.g. map a line number to the corresponding line of + text. + + scriptUnload() is called when the QScriptEngine has no further use + for a script; the QScriptEngineAgent may at this point safely + discard any resources associated with the script (such as the + script text). Note that after scriptUnload() has been called, the + QScriptEngine may reuse the relevant script ID for new scripts + (i.e. as argument to a subsequent call to scriptLoad()). + + Evaluating the following script will result in scriptUnload() + being called immediately after evaluation has completed: + + \snippet doc/src/snippets/code/src_script_qscriptengineagent.cpp 0 + + Evaluating the following script will \b{not} result in a call to + scriptUnload() when evaluation has completed: + + \snippet doc/src/snippets/code/src_script_qscriptengineagent.cpp 1 + + The script isn't unloaded because it defines a function (\c{cube}) + that remains in the script environment after evaluation has + completed. If a subsequent script removed the \c{cube} function + (e.g. by setting it to \c{null}), scriptUnload() would be called + when the function is garbage collected. In general terms, a script + isn't unloaded until the engine has determined that none of its + contents is referenced. + + To process script function calls and returns, reimplement the + functionEntry() and functionExit() functions. functionEntry() is + called when a script function is about to be executed; + functionExit() is called when a script function is about to return, + either normally or due to an exception. + + To process individual script statements, reimplement + positionChange(). positionChange() is called each time the engine is + about to execute a new statement of a script, and thus offers the + finest level of script monitoring. + + To process exceptions, reimplement exceptionThrow() and + exceptionCatch(). exceptionThrow() is called when a script exception + is thrown, before it has been handled. exceptionCatch() is called + when an exception handler is present, and execution is about to be + resumed at the handler code. + + \sa QScriptEngine::setAgent(), QScriptContextInfo +*/ + +/*! + \enum QScriptEngineAgent::Extension + + This enum specifies the possible extensions to a QScriptEngineAgent. + + \value DebuggerInvocationRequest The agent handles \c{debugger} script statements. + + \sa extension() +*/ + +QScriptEngineAgentPrivate::QScriptEngineAgentPrivate() + : engine(0), q_ptr(0) +{ +} + +QScriptEngineAgentPrivate::~QScriptEngineAgentPrivate() +{ + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + eng_p->agentDeleted(q_ptr); +} + +/*! + Constructs a QScriptEngineAgent object for the given \a engine. + + The engine takes ownership of the agent. + + Call QScriptEngine::setAgent() to make this agent the active + agent. +*/ +QScriptEngineAgent::QScriptEngineAgent(QScriptEngine *engine) + : d_ptr(new QScriptEngineAgentPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->engine = engine; +} + +/*! + \internal +*/ +QScriptEngineAgent::QScriptEngineAgent(QScriptEngineAgentPrivate &dd, QScriptEngine *engine) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; + d_ptr->engine = engine; +} + +/*! + Destroys this QScriptEngineAgent. +*/ +QScriptEngineAgent::~QScriptEngineAgent() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + + This function is called when the engine has parsed a script and has + associated it with the given \a id. The id can be used to identify + this particular script in subsequent event notifications. + + \a program, \a fileName and \a baseLineNumber are the original + arguments to the QScriptEngine::evaluate() call that triggered this + event. + + This function is called just before the script is about to be + evaluated. + + You can reimplement this function to record information about the + script; for example, by retaining the script text, you can obtain + the line of text corresponding to a line number in a subsequent + call to positionChange(). + + The default implementation does nothing. + + \sa scriptUnload() +*/ +void QScriptEngineAgent::scriptLoad(qint64 id, const QString &program, + const QString &fileName, int baseLineNumber) +{ + Q_UNUSED(id); + Q_UNUSED(program); + Q_UNUSED(fileName); + Q_UNUSED(baseLineNumber); +} + +/*! + This function is called when the engine has discarded the script + identified by the given \a id. + + You can reimplement this function to clean up any resources you have + associated with the script. + + The default implementation does nothing. + + \sa scriptLoad() +*/ +void QScriptEngineAgent::scriptUnload(qint64 id) +{ + Q_UNUSED(id); +} + +/*! + This function is called when a new script context has been pushed. + + The default implementation does nothing. + + \sa contextPop(), functionEntry() +*/ +void QScriptEngineAgent::contextPush() +{ +} + +/*! + This function is called when the current script context is about to + be popped. + + The default implementation does nothing. + + \sa contextPush(), functionExit() +*/ +void QScriptEngineAgent::contextPop() +{ +} + +/*! + This function is called when a script function is called in the + engine. If the script function is not a native Qt Script function, + it resides in the script identified by \a scriptId; otherwise, \a + scriptId is -1. + + This function is called just before execution of the script function + begins. You can obtain the QScriptContext associated with the + function call with QScriptEngine::currentContext(). The arguments + passed to the function are available. + + Reimplement this function to handle this event. For example, a + debugger implementation could reimplement this function (and + functionExit()) to keep track of the call stack and provide + step-over functionality. + + The default implementation does nothing. + + \sa functionExit(), positionChange(), QScriptEngine::currentContext() +*/ +void QScriptEngineAgent::functionEntry(qint64 scriptId) +{ + Q_UNUSED(scriptId); +} + +/*! + This function is called when the currently executing script function + is about to return. If the script function is not a native Qt Script + function, it resides in the script identified by \a scriptId; + otherwise, \a scriptId is -1. The \a returnValue is the value that + the script function will return. + + This function is called just before the script function returns. + You can still access the QScriptContext associated with the + script function call with QScriptEngine::currentContext(). + + If the engine's + \l{QScriptEngine::hasUncaughtException()}{hasUncaughtException}() + function returns true, the script function is exiting due to an + exception; otherwise, the script function is returning normally. + + Reimplement this function to handle this event; typically you will + then also want to reimplement functionEntry(). + + The default implementation does nothing. + + \sa functionEntry(), QScriptEngine::hasUncaughtException() +*/ +void QScriptEngineAgent::functionExit(qint64 scriptId, + const QScriptValue &returnValue) +{ + Q_UNUSED(scriptId); + Q_UNUSED(returnValue); +} + +/*! + This function is called when the engine is about to execute a new + statement in the script identified by \a scriptId. The statement + begins on the line and column specified by \a lineNumber and \a + columnNumber. This event is not generated for native Qt Script + functions. + + Reimplement this function to handle this event. For example, a + debugger implementation could reimplement this function to provide + line-by-line stepping, and a profiler implementation could use it to + count the number of times each statement is executed. + + The default implementation does nothing. + + \sa scriptLoad(), functionEntry() +*/ +void QScriptEngineAgent::positionChange(qint64 scriptId, + int lineNumber, int columnNumber) +{ + Q_UNUSED(scriptId); + Q_UNUSED(lineNumber); + Q_UNUSED(columnNumber); +} + +/*! + This function is called when the given \a exception has occurred in + the engine, in the script identified by \a scriptId. If the + exception was thrown by a native Qt Script function, \a scriptId is + -1. + + If \a hasHandler is true, there is a \c{catch} or \c{finally} block + that will handle the exception. If \a hasHandler is false, there is + no handler for the exception. + + Reimplement this function if you want to handle this event. For + example, a debugger can notify the user when an uncaught exception + occurs (i.e. \a hasHandler is false). + + The default implementation does nothing. + + \sa exceptionCatch() +*/ +void QScriptEngineAgent::exceptionThrow(qint64 scriptId, + const QScriptValue &exception, + bool hasHandler) +{ + Q_UNUSED(scriptId); + Q_UNUSED(exception); + Q_UNUSED(hasHandler); +} + +/*! + This function is called when the given \a exception is about to be + caught, in the script identified by \a scriptId. + + Reimplement this function if you want to handle this event. + + The default implementation does nothing. + + \sa exceptionThrow() +*/ +void QScriptEngineAgent::exceptionCatch(qint64 scriptId, + const QScriptValue &exception) +{ + Q_UNUSED(scriptId); + Q_UNUSED(exception); +} + +#if 0 +/*! + This function is called when a property of the given \a object has + been added, changed or removed. + + Reimplement this function if you want to handle this event. + + The default implementation does nothing. +*/ +void QScriptEngineAgent::propertyChange(qint64 scriptId, + const QScriptValue &object, + const QString &propertyName, + PropertyChange change) +{ + Q_UNUSED(scriptId); + Q_UNUSED(object); + Q_UNUSED(propertyName); + Q_UNUSED(change); +} +#endif + +/*! + Returns true if the QScriptEngineAgent supports the given \a + extension; otherwise, false is returned. By default, no extensions + are supported. + + \sa extension() +*/ +bool QScriptEngineAgent::supportsExtension(Extension extension) const +{ + Q_UNUSED(extension); + return false; +} + +/*! + This virtual function can be reimplemented in a QScriptEngineAgent + subclass to provide support for extensions. The optional \a argument + can be provided as input to the \a extension; the result must be + returned in the form of a QVariant. You can call supportsExtension() + to check if an extension is supported by the QScriptEngineAgent. By + default, no extensions are supported, and this function returns an + invalid QVariant. + + If you implement the DebuggerInvocationRequest extension, Qt Script + will call this function when a \c{debugger} statement is encountered + in a script. The \a argument is a QVariantList containing three + items: The first item is the scriptId (a qint64), the second item is + the line number (an int), and the third item is the column number + (an int). + + \sa supportsExtension() +*/ +QVariant QScriptEngineAgent::extension(Extension extension, + const QVariant &argument) +{ + Q_UNUSED(extension); + Q_UNUSED(argument); + return QVariant(); +} + +/*! + Returns the QScriptEngine that this agent is associated with. +*/ +QScriptEngine *QScriptEngineAgent::engine() const +{ + Q_D(const QScriptEngineAgent); + return d->engine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptengineagent.h b/src/script/qscriptengineagent.h new file mode 100644 index 0000000..3334bc0 --- /dev/null +++ b/src/script/qscriptengineagent.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 QSCRIPTENGINEAGENT_H +#define QSCRIPTENGINEAGENT_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptEngine; +class QScriptValue; + +class QScriptEngineAgentPrivate; +class Q_SCRIPT_EXPORT QScriptEngineAgent +{ +public: + enum Extension { + DebuggerInvocationRequest + }; + + QScriptEngineAgent(QScriptEngine *engine); + virtual ~QScriptEngineAgent(); + + virtual void scriptLoad(qint64 id, const QString &program, + const QString &fileName, int baseLineNumber); + virtual void scriptUnload(qint64 id); + + virtual void contextPush(); + virtual void contextPop(); + + virtual void functionEntry(qint64 scriptId); + virtual void functionExit(qint64 scriptId, + const QScriptValue &returnValue); + + virtual void positionChange(qint64 scriptId, + int lineNumber, int columnNumber); + + virtual void exceptionThrow(qint64 scriptId, + const QScriptValue &exception, + bool hasHandler); + virtual void exceptionCatch(qint64 scriptId, + const QScriptValue &exception); + + virtual bool supportsExtension(Extension extension) const; + virtual QVariant extension(Extension extension, + const QVariant &argument = QVariant()); + + QScriptEngine *engine() const; + +protected: + QScriptEngineAgent(QScriptEngineAgentPrivate &dd, QScriptEngine *engine); + QScriptEngineAgentPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QScriptEngineAgent) + Q_DISABLE_COPY(QScriptEngineAgent) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptengineagent_p.h b/src/script/qscriptengineagent_p.h new file mode 100644 index 0000000..f0b3969 --- /dev/null +++ b/src/script/qscriptengineagent_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 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 QSCRIPTENGINEAGENT_P_H +#define QSCRIPTENGINEAGENT_P_H + +#include <QtCore/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +// +// 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 QScriptEngine; + +class QScriptEngineAgent; +class Q_SCRIPT_EXPORT QScriptEngineAgentPrivate +{ + Q_DECLARE_PUBLIC(QScriptEngineAgent) +public: + QScriptEngineAgentPrivate(); + virtual ~QScriptEngineAgentPrivate(); + + QScriptEngine *engine; + + QScriptEngineAgent *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptenginefwd_p.h b/src/script/qscriptenginefwd_p.h new file mode 100644 index 0000000..2ea66c5 --- /dev/null +++ b/src/script/qscriptenginefwd_p.h @@ -0,0 +1,559 @@ +/**************************************************************************** +** +** 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 QSCRIPTENGINEFWD_P_H +#define QSCRIPTENGINEFWD_P_H + +#ifndef QT_NO_QOBJECT +#include "private/qobject_p.h" +#endif + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qobjectdefs.h> + +#include <QtCore/QHash> +#include <QtCore/QList> +#include <QtCore/QRegExp> +#include <QtCore/QSet> +#include <QtCore/QStringList> +#include <QtCore/QTime> +#include <QtCore/QVector> + +#include "qscriptengine.h" +#include "qscriptrepository_p.h" +#include "qscriptgc_p.h" +#include "qscriptobjectfwd_p.h" +#include "qscriptclassinfo_p.h" +#include "qscriptstring_p.h" + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptClass; +class QScriptContext; + +namespace QScript { + +namespace AST { + class Node; +} // namespace AST + +namespace Ecma { + class Object; + class Number; + class Boolean; + class String; + class Math; + class Date; + class Function; + class Array; + class RegExp; + class Error; +} // namespace Ecma + +namespace Ext { + class Enumeration; + class Variant; +} // namespace Ext + +class ExtQObject; +class ExtQMetaObject; + +class Array; +class Lexer; +class Code; +class CompilationUnit; +class IdTable; +class MemoryPool; + +class IdTable +{ +public: + inline IdTable() + : id_constructor(0), id_false(0), id_null(0), + id_object(0), id_pointer(0), id_prototype(0), + id_arguments(0), id_this(0), id_toString(0), + id_true(0), id_undefined(0), id_valueOf(0), + id_length(0), id_callee(0), id___proto__(0), + id___qt_sender__(0) + {} + + QScriptNameIdImpl *id_constructor; + QScriptNameIdImpl *id_false; + QScriptNameIdImpl *id_null; + QScriptNameIdImpl *id_object; + QScriptNameIdImpl *id_pointer; + QScriptNameIdImpl *id_prototype; + QScriptNameIdImpl *id_arguments; + QScriptNameIdImpl *id_this; + QScriptNameIdImpl *id_toString; + QScriptNameIdImpl *id_true; + QScriptNameIdImpl *id_undefined; + QScriptNameIdImpl *id_valueOf; + QScriptNameIdImpl *id_length; + QScriptNameIdImpl *id_callee; + QScriptNameIdImpl *id___proto__; + QScriptNameIdImpl *id___qt_sender__; +}; + +} // namespace QScript + +#ifndef QT_NO_QOBJECT +class QScriptQObjectData; +class QScriptMetaObject; +#endif + +class QScriptCustomTypeInfo +{ +public: + QScriptCustomTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0) + { prototype.invalidate(); } + + QByteArray signature; + QScriptEngine::MarshalFunction marshal; + QScriptEngine::DemarshalFunction demarshal; + QScriptValueImpl prototype; +}; + +class QScriptEnginePrivate +#ifndef QT_NO_QOBJECT + : public QObjectPrivate +#endif +{ + Q_DECLARE_PUBLIC(QScriptEngine) + + enum { + DefaultHashSize = 1021 + }; + +public: + QScriptEnginePrivate(); + virtual ~QScriptEnginePrivate(); + + void init(); + void initStringRepository(); + + static inline QScriptEnginePrivate *get(QScriptEngine *q); + static inline const QScriptEnginePrivate *get(const QScriptEngine *q); + static inline QScriptEngine *get(QScriptEnginePrivate *d); + + QScript::AST::Node *createAbstractSyntaxTree( + const QString &source, int lineNumber, + QString *errorMessage, int *errorLineNumber); + QScript::AST::Node *changeAbstractSyntaxTree(QScript::AST::Node *program); + + inline QScript::AST::Node *abstractSyntaxTree() const; + inline bool hasUncaughtException() const; + inline QScriptValueImpl uncaughtException() const; + QStringList uncaughtExceptionBacktrace() const; + void clearExceptions(); +#ifndef QT_NO_QOBJECT + void emitSignalHandlerException(); +#endif + + static bool canEvaluate(const QString &program); + static QScriptSyntaxCheckResult checkSyntax(const QString &program); + + inline QScriptContextPrivate *currentContext() const; + inline QScriptContextPrivate *pushContext(); + inline void popContext(); + + inline QScript::MemoryPool *nodePool(); + inline QScript::Lexer *lexer(); + inline QScriptObject *allocObject(); + + inline void maybeGC(); + + void maybeGC_helper(bool do_string_gc); + + inline bool blockGC(bool block); + + void gc(); + bool isCollecting() const; + void processMarkStack(int generation); + + inline void adjustBytesAllocated(int bytes); + + void markObject(const QScriptValueImpl &object, int generation); + void markFrame(QScriptContextPrivate *context, int generation); + + inline void markString(QScriptNameIdImpl *id, int generation); + + inline QScriptValueImpl createFunction(QScriptFunction *fun); + inline QScriptValueImpl newArray(const QScript::Array &value); + inline QScriptValueImpl newArray(uint length = 0); + + void evaluate(QScriptContextPrivate *context, const QString &contents, + int lineNumber, const QString &fileName = QString()); + + inline void setLexer(QScript::Lexer *lexer); + + inline void setNodePool(QScript::MemoryPool *pool); + + inline QScriptClassInfo *registerClass(const QString &pname, int type); + + inline QScriptClassInfo *registerClass(const QString &name); + + int registerCustomClassType(); + + inline QScriptValueImpl createFunction(QScriptInternalFunctionSignature fun, + int length, QScriptClassInfo *classInfo, + const QString &name = QString()); + + static inline QString toString(QScriptNameIdImpl *id); + inline QString memberName(const QScript::Member &member) const; + inline void newReference(QScriptValueImpl *object, int mode); + inline void newActivation(QScriptValueImpl *object); + inline void newFunction(QScriptValueImpl *object, QScriptFunction *function); + inline void newConstructor(QScriptValueImpl *ctor, QScriptFunction *function, + QScriptValueImpl &proto); + inline void newInteger(QScriptValueImpl *object, int i); + inline void newPointer(QScriptValueImpl *object, void *ptr); + inline void newNameId(QScriptValueImpl *object, const QString &s); + inline void newNameId(QScriptValueImpl *object, QScriptNameIdImpl *id); + inline void newString(QScriptValueImpl *object, const QString &s); + inline void newArguments(QScriptValueImpl *object, const QScriptValueImpl &activation, + uint length, const QScriptValueImpl &callee); + static inline QString convertToNativeString(const QScriptValueImpl &value); + static QString convertToNativeString_helper(const QScriptValueImpl &value); + static inline qsreal convertToNativeDouble(const QScriptValueImpl &value); + static qsreal convertToNativeDouble_helper(const QScriptValueImpl &value); + static inline bool convertToNativeBoolean(const QScriptValueImpl &value); + static bool convertToNativeBoolean_helper(const QScriptValueImpl &value); + static inline qint32 convertToNativeInt32(const QScriptValueImpl &value); + static inline QScriptFunction *convertToNativeFunction(const QScriptValueImpl &value); + + inline QScriptValue toPublic(const QScriptValueImpl &value); + inline QScriptValueImpl toImpl(const QScriptValue &value); + QScriptValueImpl toImpl_helper(const QScriptValue &value); + inline QScriptValueImplList toImplList(const QScriptValueList &lst); + + inline const QScript::IdTable *idTable() const; + + inline QScriptValueImpl toObject(const QScriptValueImpl &value); + QScriptValueImpl toObject_helper(const QScriptValueImpl &value); + + inline QScriptValueImpl toPrimitive(const QScriptValueImpl &object, + QScriptValueImpl::TypeHint hint = QScriptValueImpl::NoTypeHint); + QScriptValueImpl toPrimitive_helper(const QScriptValueImpl &object, + QScriptValueImpl::TypeHint hint); + + static const qsreal D16; + static const qsreal D32; + + inline static qsreal toInteger(qsreal n); + inline static qint32 toInt32(qsreal m); + inline static quint32 toUint32(qsreal n); + inline static quint16 toUint16(qsreal n); + + inline QDateTime toDateTime(const QScriptValueImpl &value) const; + + inline void newArray(QScriptValueImpl *object, const QScript::Array &value); + + inline void newObject(QScriptValueImpl *o, const QScriptValueImpl &proto, + QScriptClassInfo *oc = 0); + inline void newObject(QScriptValueImpl *o, QScriptClassInfo *oc = 0); + QScriptValueImpl newObject(QScriptClass *scriptClass, const QScriptValueImpl &data); + + inline QScriptValueImpl newObject(); + + inline void newVariant(QScriptValueImpl *out, const QVariant &value, + bool setDefaultPrototype = true); + +#ifndef QT_NO_QOBJECT + void newQObject(QScriptValueImpl *out, QObject *object, + QScriptEngine::ValueOwnership ownership = QScriptEngine::QtOwnership, + const QScriptEngine::QObjectWrapOptions &options = 0, + bool setDefaultPrototype = true); + +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + inline QScriptMetaObject *cachedMetaObject(const QMetaObject *meta); +# endif +#endif + + inline QScriptNameIdImpl *nameId(const QString &str, bool persistent = false); + + inline QScriptNameIdImpl *intern(const QChar *u, int s); + + QScriptString internedString(const QString &str); + QScriptString internedString(QScriptNameIdImpl *nid); + void uninternString(QScriptStringPrivate *d); + + inline QScriptValueImpl valueFromVariant(const QVariant &v); + + inline QScriptValueImpl undefinedValue(); + + inline QScriptValueImpl nullValue(); + + inline QScriptValueImpl defaultPrototype(int metaTypeId) const; + + inline void setDefaultPrototype(int metaTypeId, const QScriptValueImpl &prototype); + + QScriptValueImpl call(const QScriptValueImpl &callee, const QScriptValueImpl &thisObject, + const QScriptValueImplList &args, bool asConstructor); + QScriptValueImpl call(const QScriptValueImpl &callee, const QScriptValueImpl &thisObject, + const QScriptValueImpl &args, bool asConstructor); + + void rehashStringRepository(bool resize = true); + inline QScriptNameIdImpl *toStringEntry(const QString &s); + QScriptNameIdImpl *insertStringEntry(const QString &s); + + QScriptValueImpl create(int type, const void *ptr); + static bool convert(const QScriptValueImpl &value, int type, void *ptr, + QScriptEnginePrivate *eng); + + QScriptValueImpl arrayFromStringList(const QStringList &lst); + static QStringList stringListFromArray(const QScriptValueImpl &arr); + + QScriptValueImpl arrayFromVariantList(const QVariantList &lst); + static QVariantList variantListFromArray(const QScriptValueImpl &arr); + + QScriptValueImpl objectFromVariantMap(const QVariantMap &vmap); + static QVariantMap variantMapFromObject(const QScriptValueImpl &obj); + + static inline bool lessThan(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs); + static inline bool equals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs); + static inline bool strictlyEquals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs); + + QScriptValuePrivate *registerValue(const QScriptValueImpl &value); + inline void unregisterValue(QScriptValuePrivate *p); + + inline QScriptValueImpl globalObject() const; + + QScriptValueImpl objectById(qint64 id) const; + + QScriptValueImpl importExtension(const QString &extension); + QStringList availableExtensions() const; + QStringList importedExtensions() const; + + inline void maybeProcessEvents(); + void setupProcessEvents(); + void processEvents(); + +#ifndef QT_NO_QOBJECT + QScriptQObjectData *qobjectData(QObject *object); + + bool scriptConnect(QObject *sender, const char *signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function); + bool scriptDisconnect(QObject *sender, const char *signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function); + + bool scriptConnect(QObject *sender, int index, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function, + const QScriptValueImpl &senderWrapper = QScriptValueImpl()); + bool scriptDisconnect(QObject *sender, int index, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function); + + bool scriptConnect(const QScriptValueImpl &signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function); + bool scriptDisconnect(const QScriptValueImpl &signal, + const QScriptValueImpl &receiver, + const QScriptValueImpl &function); + + void _q_objectDestroyed(QObject *object); + + void disposeQObject(QObject *object); + void deletePendingQObjects(); + + static bool convertToNativeQObject(const QScriptValueImpl &value, + const QByteArray &targetType, + void **result); +#endif + + void abortEvaluation(const QScriptValueImpl &result); + inline bool shouldAbort() const; + inline void resetAbortFlag(); + + void setAgent(QScriptEngineAgent *agent); + QScriptEngineAgent *agent() const; + + void agentDeleted(QScriptEngineAgent *agent); + + void installTranslatorFunctions(QScriptValueImpl &object); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + qint64 nextScriptId(); + inline bool shouldNotify() const; + inline void notifyScriptLoad(qint64 id, const QString &program, + const QString &fileName, int lineNumber); + void notifyScriptLoad_helper(qint64 id, const QString &program, + const QString &fileName, int lineNumber); + inline void notifyScriptUnload(qint64 id); + void notifyScriptUnload_helper(qint64 id); + inline void notifyPositionChange(QScriptContextPrivate *ctx); + void notifyPositionChange_helper(QScriptContextPrivate *ctx); + inline void notifyContextPush(); + void notifyContextPush_helper(); + inline void notifyContextPop(); + void notifyContextPop_helper(); + inline void notifyFunctionEntry(QScriptContextPrivate *ctx); + void notifyFunctionEntry_helper(QScriptContextPrivate *ctx); + inline void notifyFunctionExit(QScriptContextPrivate *ctx); + void notifyFunctionExit_helper(QScriptContextPrivate *ctx); + inline void notifyException(QScriptContextPrivate *ctx); + void notifyException_helper(QScriptContextPrivate *ctx); + inline void notifyExceptionCatch(QScriptContextPrivate *ctx); + void notifyExceptionCatch_helper(QScriptContextPrivate *ctx); + void notifyDebugger(QScriptContextPrivate *ctx); +#endif // Q_SCRIPT_NO_EVENT_NOTIFY + +public: // attributes + bool m_evaluating; + bool m_abort; + int m_callDepth; + int m_maxCallDepth; + int m_gc_depth; + QList<QScriptValueImpl> m_markStack; + QScriptValueImpl m_globalObject; + int m_oldStringRepositorySize; + int m_oldTempStringRepositorySize; + QVector<QScriptNameIdImpl*> m_stringRepository; + int m_newAllocatedStringRepositoryChars; + QVector<QScriptNameIdImpl*> m_tempStringRepository; + int m_newAllocatedTempStringRepositoryChars; + QScriptNameIdImpl **m_string_hash_base; + int m_string_hash_size; + QScript::GCAlloc<QScriptObject> objectAllocator; + int m_objectGeneration; + QScript::Repository<QScriptContext, QScriptContextPrivate> m_frameRepository; + QScriptContextPrivate *m_context; + QScriptValueImpl *tempStackBegin; + QScriptValueImpl *tempStackEnd; + QScript::AST::Node *m_abstractSyntaxTree; + QScript::Lexer *m_lexer; + QScript::MemoryPool *m_pool; + QStringList m_exceptionBacktrace; + qint64 m_scriptCounter; + + QScriptValueImpl m_undefinedValue; + QScriptValueImpl m_nullValue; + + QScript::Ecma::Object *objectConstructor; + QScript::Ecma::Number *numberConstructor; + QScript::Ecma::Boolean *booleanConstructor; + QScript::Ecma::String *stringConstructor; + QScript::Ecma::Date *dateConstructor; + QScript::Ecma::Function *functionConstructor; + QScript::Ecma::Array *arrayConstructor; + QScript::Ecma::RegExp *regexpConstructor; + QScript::Ecma::Error *errorConstructor; + QScript::Ext::Enumeration *enumerationConstructor; + QScript::Ext::Variant *variantConstructor; + QScript::ExtQObject *qobjectConstructor; + QScript::ExtQMetaObject *qmetaObjectConstructor; + + QHash<int, QScriptCustomTypeInfo> m_customTypes; + + QScriptFunction *m_evalFunction; + + QList<QScriptClassInfo*> m_allocated_classes; + QScriptClassInfo *m_class_object; + QScriptClassInfo *m_class_function; + QScriptClassInfo *m_class_with; + QScriptClassInfo *m_class_arguments; + QScriptClassInfo *m_class_activation; + + int m_class_prev_id; + qint64 m_next_object_id; + + QScript::Repository<QScriptValuePrivate, QScriptValuePrivate> m_handleRepository; + QHash<QScriptObject*, QScriptValuePrivate*> m_objectHandles; + QHash<QScriptNameIdImpl*, QScriptValuePrivate*> m_stringHandles; + QVector<QScriptValuePrivate*> m_otherHandles; + + QScript::Repository<QScriptStringPrivate, + QScriptStringPrivate> m_internedStringRepository; + QHash<QScriptNameIdImpl*, QScriptStringPrivate*> m_internedStrings; + + QSet<QScriptObject*> visitedArrayElements; + +#ifndef QT_NO_REGEXP + QHash<QString, QRegExp> m_regExpLiterals; +#endif + + QScript::IdTable m_id_table; + + QSet<QString> m_importedExtensions; + QSet<QString> m_extensionsBeingImported; + + int m_processEventsInterval; + int m_nextProcessEvents; + int m_processEventIncr; + QTime m_processEventTracker; + + QList<QScriptEngineAgent*> m_agents; + QScriptEngineAgent *m_agent; + +#ifndef QT_NO_QOBJECT + QList<QObject*> m_qobjectsToBeDeleted; + QHash<QObject*, QScriptQObjectData*> m_qobjectData; + +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + QHash<const QMetaObject*, QScriptMetaObject*> m_cachedMetaObjects; +# endif +#endif + +#ifdef QT_NO_QOBJECT + QScriptEngine *q_ptr; +#endif +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptextensioninterface.h b/src/script/qscriptextensioninterface.h new file mode 100644 index 0000000..35dc7ed --- /dev/null +++ b/src/script/qscriptextensioninterface.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 QSCRIPTEXTENSIONINTERFACE_H +#define QSCRIPTEXTENSIONINTERFACE_H + +#include <QtCore/qfactoryinterface.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptEngine; + +struct Q_SCRIPT_EXPORT QScriptExtensionInterface + : public QFactoryInterface +{ + virtual void initialize(const QString &key, QScriptEngine *engine) = 0; +}; + +Q_DECLARE_INTERFACE(QScriptExtensionInterface, + "com.trolltech.Qt.QScriptExtensionInterface/1.0") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTEXTENSIONINTERFACE_H diff --git a/src/script/qscriptextensionplugin.cpp b/src/script/qscriptextensionplugin.cpp new file mode 100644 index 0000000..1c85606 --- /dev/null +++ b/src/script/qscriptextensionplugin.cpp @@ -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 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 "qscriptextensionplugin.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalue.h" +#include "qscriptengine.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptExtensionPlugin + \brief The QScriptExtensionPlugin class provides an abstract base for custom QScript extension plugins. + + \ingroup plugins + + QScriptExtensionPlugin is a plugin interface that makes it + possible to offer extensions that can be loaded dynamically into + applications using the QScriptEngine class. + + Writing a script extension plugin is achieved by subclassing this + base class, reimplementing the pure virtual keys() and initialize() + functions, and exporting the class using the Q_EXPORT_PLUGIN2() + macro. See \l {How to Create Qt Plugins} for details. + + \sa QScriptEngine::importExtension(), {Creating QtScript Extensions} +*/ + +/*! + \fn QStringList QScriptExtensionPlugin::keys() const + + Returns the list of keys this plugin supports. + + These keys are usually the names of the "modules" or "packages" + that are implemented in the plugin (e.g. \c{com.mycompany.MyProduct}). + + \sa initialize() +*/ + +/*! + \fn void QScriptExtensionPlugin::initialize(const QString& key, QScriptEngine *engine) + + Initializes the extension specified by \a key in the given \a engine. + The key must come from the set of keys(). + + \sa keys() +*/ + +/*! + Constructs a script extension plugin with the given \a parent. + + Note that this constructor is invoked automatically by the + Q_EXPORT_PLUGIN2() macro, so there is no need for calling it + explicitly. +*/ +QScriptExtensionPlugin::QScriptExtensionPlugin(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the script extension plugin. + + Note that Qt destroys a plugin automatically when it is no longer + used, so there is no need for calling the destructor explicitly. +*/ +QScriptExtensionPlugin::~QScriptExtensionPlugin() +{ +} + +/*! + + This function is provided for convenience when reimplementing + initialize(). It splits the given \a key on \c{'.'} (dot), and + ensures that there's a corresponding path of objects in the + environment of the given \a engine, creating new objects to complete + the path if necessary. E.g. if the key is "com.trolltech", after + the call to setupPackage() the script expression \c{com.trolltech} + will evaluate to an object. More specifically, the engine's Global + Object will have a property called "com", which in turn has a + property called "trolltech". + + Use this function to avoid global namespace pollution when installing + your extensions in the engine. + + \sa initialize() +*/ +QScriptValue QScriptExtensionPlugin::setupPackage( + const QString &key, QScriptEngine *engine) const +{ + QStringList components = key.split(QLatin1Char('.')); + QScriptValue o = engine->globalObject(); + for (int i = 0; i < components.count(); ++i) { + QScriptValue oo = o.property(components.at(i)); + if (!oo.isValid()) { + oo = engine->newObject(); + o.setProperty(components.at(i), oo); + } + o = oo; + } + return o; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptextensionplugin.h b/src/script/qscriptextensionplugin.h new file mode 100644 index 0000000..e646b54 --- /dev/null +++ b/src/script/qscriptextensionplugin.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 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 QSCRIPTEXTENSIONPLUGIN_H +#define QSCRIPTEXTENSIONPLUGIN_H + +#include <QtCore/qplugin.h> + +#ifndef QT_NO_SCRIPT + +#include <QtScript/qscriptextensioninterface.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptValue; + +class Q_SCRIPT_EXPORT QScriptExtensionPlugin : public QObject, + public QScriptExtensionInterface +{ + Q_OBJECT + Q_INTERFACES(QScriptExtensionInterface:QFactoryInterface) +public: + explicit QScriptExtensionPlugin(QObject *parent = 0); + ~QScriptExtensionPlugin(); + + virtual QStringList keys() const = 0; + virtual void initialize(const QString &key, QScriptEngine *engine) = 0; + + QScriptValue setupPackage(const QString &key, QScriptEngine *engine) const; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTEXTENSIONPLUGIN_H diff --git a/src/script/qscriptextenumeration.cpp b/src/script/qscriptextenumeration.cpp new file mode 100644 index 0000000..4b043a9 --- /dev/null +++ b/src/script/qscriptextenumeration.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 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 "qscriptextenumeration_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptvalueiteratorimpl_p.h" + +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ext { + +EnumerationClassData::EnumerationClassData(QScriptClassInfo *classInfo): + m_classInfo(classInfo) +{ +} + +EnumerationClassData::~EnumerationClassData() +{ +} + +void EnumerationClassData::mark(const QScriptValueImpl &object, int generation) +{ + Q_ASSERT(object.isValid()); + + QScriptEnginePrivate *eng = object.engine(); + + if (Enumeration::Instance *instance = Enumeration::Instance::get(object, classInfo())) { + eng->markObject(instance->object, generation); + if (instance->it) + eng->markObject(instance->it->object(), generation); + } +} + +Enumeration::Enumeration(QScriptEnginePrivate *eng): + Ecma::Core(eng, QLatin1String("Enumeration"), QScriptClassInfo::EnumerationType) +{ + classInfo()->setData(new EnumerationClassData(classInfo())); + + newEnumeration(&publicPrototype, eng->newArray()); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toFront"), method_toFront, 0); + addPrototypeFunction(QLatin1String("hasNext"), method_hasNext, 0); + addPrototypeFunction(QLatin1String("next"), method_next, 0); +} + +Enumeration::~Enumeration() +{ +} + +Enumeration::Instance *Enumeration::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + +void Enumeration::execute(QScriptContextPrivate *context) +{ + if (context->argumentCount() > 0) { + newEnumeration(&context->m_result, context->argument(0)); + } else { + context->throwError(QScriptContext::TypeError, + QLatin1String("Enumeration.execute")); + } +} + +void Enumeration::newEnumeration(QScriptValueImpl *result, const QScriptValueImpl &object) +{ + Instance *instance = new Instance(); + instance->object = object; + if (object.isObject()) { + instance->it = new QScriptValueIteratorImpl(object); + instance->it->setIgnoresDontEnum(false); + instance->it->setEnumeratePrototype(true); + } else { + instance->it = 0; + } + engine()->newObject(result, publicPrototype, classInfo()); + result->setObjectData(instance); +} + +QScriptValueImpl Enumeration::method_toFront(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + if (instance->it) + instance->it->toFront(); + return eng->undefinedValue(); + } else { + return context->throwError(QScriptContext::TypeError, + QLatin1String("Enumeration.toFront")); + } +} + +QScriptValueImpl Enumeration::method_hasNext(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + Instance *instance = Instance::get(context->thisObject(), classInfo); + if (!instance) { + return context->throwError(QScriptContext::TypeError, + QLatin1String("Enumeration.hasNext")); + } + + QScriptValueImpl v; + instance->hasNext(context, &v); + return v; +} + +QScriptValueImpl Enumeration::method_next(QScriptContextPrivate *context, QScriptEnginePrivate *, QScriptClassInfo *classInfo) +{ + Instance *instance = Instance::get(context->thisObject(), classInfo); + if (!instance) { + return context->throwError(QScriptContext::TypeError, + QLatin1String("Enumeration.next")); + } + + QScriptValueImpl v; + instance->next(context, &v); + return v; +} + +Enumeration::Instance::~Instance() +{ + if (it) { + delete it; + it = 0; + } +} + +void Enumeration::Instance::toFront() +{ + if (it) + it->toFront(); +} + +void Enumeration::Instance::hasNext(QScriptContextPrivate *, QScriptValueImpl *result) +{ + *result = QScriptValueImpl(it && it->hasNext()); +} + +void Enumeration::Instance::next(QScriptContextPrivate *context, QScriptValueImpl *result) +{ + QScriptEnginePrivate *eng = context->engine(); + Q_ASSERT(it != 0); + it->next(); + QScript::Member *member = it->member(); + if (member->isObjectProperty() || member->nameId()) + eng->newNameId(result, member->nameId()); + + else if (member->isNativeProperty() && !member->nameId()) + *result = QScriptValueImpl(uint(member->id())); + + else + *result = eng->undefinedValue(); +} + +} } // namespace QScript::Ext + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptextenumeration_p.h b/src/script/qscriptextenumeration_p.h new file mode 100644 index 0000000..4c49f74 --- /dev/null +++ b/src/script/qscriptextenumeration_p.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 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 QSCRIPTEXTENUMERATION_P_H +#define QSCRIPTEXTENUMERATION_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 "qscriptecmacore_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SCRIPT + +class QScriptValueIteratorImpl; + +namespace QScript { namespace Ext { + +class EnumerationClassData: public QScriptClassData +{ + QScriptClassInfo *m_classInfo; + +public: + EnumerationClassData(QScriptClassInfo *classInfo); + virtual ~EnumerationClassData(); + + inline QScriptClassInfo *classInfo() const + { return m_classInfo; } + + virtual void mark(const QScriptValueImpl &object, int generation); +}; + +class Enumeration: public QScript::Ecma::Core +{ +public: + Enumeration(QScriptEnginePrivate *engine); + virtual ~Enumeration(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptObjectData { + public: + Instance() : it(0) {} + virtual ~Instance(); + + static Instance *get(const QScriptValueImpl &object, + QScriptClassInfo *klass); + + void toFront(); + void hasNext(QScriptContextPrivate *context, QScriptValueImpl *result); + void next(QScriptContextPrivate *context, QScriptValueImpl *result); + + public: // attributes + QScriptValueIteratorImpl *it; + QScriptValueImpl object; + }; + + void newEnumeration(QScriptValueImpl *result, const QScriptValueImpl &value); + + inline Instance *get(const QScriptValueImpl &object) const + { + return Instance::get(object, classInfo()); + } + +protected: + static QScriptValueImpl method_toFront(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_hasNext(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_next(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ext + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif diff --git a/src/script/qscriptextqobject.cpp b/src/script/qscriptextqobject.cpp new file mode 100644 index 0000000..d18c3da --- /dev/null +++ b/src/script/qscriptextqobject.cpp @@ -0,0 +1,2209 @@ +/**************************************************************************** +** +** 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/qglobal.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptable.h" +#include "qscriptable_p.h" +#include "qscriptextqobject_p.h" + +#include <QtCore/QtDebug> +#include <QtCore/QMetaMethod> +#include <QtCore/QRegExp> +#include <QtCore/QVarLengthArray> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +// we use bits 15..12 of property flags +enum { + PROPERTY_ID = 0 << 12, + DYNAPROPERTY_ID = 1 << 12, + METHOD_ID = 2 << 12, + CHILD_ID = 3 << 12, + ID_MASK = 7 << 12, + MAYBE_OVERLOADED = 8 << 12 +}; + +static const bool GeneratePropertyFunctions = true; + +int QScriptMetaType::typeId() const +{ + if (isVariant()) + return QMetaType::type("QVariant"); + return isMetaEnum() ? 2/*int*/ : m_typeId; +} + +QByteArray QScriptMetaType::name() const +{ + if (!m_name.isEmpty()) + return m_name; + else if (m_kind == Variant) + return "QVariant"; + return QMetaType::typeName(typeId()); +} + +namespace QScript { + +class QObjectNotifyCaller : public QObject +{ +public: + void callConnectNotify(const char *signal) + { connectNotify(signal); } + void callDisconnectNotify(const char *signal) + { disconnectNotify(signal); } +}; + +class QtPropertyFunction: public QScriptFunction +{ +public: + QtPropertyFunction(const QMetaObject *meta, int index) + : m_meta(meta), m_index(index) + { } + + ~QtPropertyFunction() { } + + virtual void execute(QScriptContextPrivate *context); + + virtual Type type() const { return QScriptFunction::QtProperty; } + + virtual QString functionName() const; + +private: + const QMetaObject *m_meta; + int m_index; +}; + +class QObjectPrototype : public QObject +{ + Q_OBJECT +public: + QObjectPrototype(QObject *parent = 0) + : QObject(parent) { } + ~QObjectPrototype() { } +}; + +static inline QByteArray methodName(const QMetaMethod &method) +{ + QByteArray signature = method.signature(); + return signature.left(signature.indexOf('(')); +} + +static inline QVariant variantFromValue(QScriptEnginePrivate *eng, + int targetType, const QScriptValueImpl &value) +{ + QVariant v(targetType, (void *)0); + Q_ASSERT(eng); + if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng)) + return v; + if (uint(targetType) == QVariant::LastType) + return value.toVariant(); + if (value.isVariant()) { + v = value.toVariant(); + if (v.canConvert(QVariant::Type(targetType))) { + v.convert(QVariant::Type(targetType)); + return v; + } + QByteArray typeName = v.typeName(); + if (typeName.endsWith('*') + && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) { + return QVariant(targetType, *reinterpret_cast<void* *>(v.data())); + } + } + + return QVariant(); +} + +void ExtQObject::Instance::finalize(QScriptEnginePrivate *eng) +{ + switch (ownership) { + case QScriptEngine::QtOwnership: + break; + case QScriptEngine::ScriptOwnership: + if (value) + eng->disposeQObject(value); + break; + case QScriptEngine::AutoOwnership: + if (value && !value->parent()) + eng->disposeQObject(value); + break; + } +} + +ExtQObject::Instance *ExtQObject::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + + +static inline QScriptable *scriptableFromQObject(QObject *qobj) +{ + void *ptr = qobj->qt_metacast("QScriptable"); + return reinterpret_cast<QScriptable*>(ptr); +} + +static bool isObjectProperty(const QScriptValueImpl &object, const char *name) +{ + QScriptEnginePrivate *eng = object.engine(); + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); + QScript::Member member; + QScriptValueImpl base; + return object.resolve(nameId, &member, &base, QScriptValue::ResolveLocal, QScript::Read) + && member.testFlags(QScript::Member::ObjectProperty); +} + +static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt) +{ + return (method.access() != QMetaMethod::Private) + && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater)); +} + +static bool isEnumerableMetaProperty(const QMetaProperty &prop, + const QMetaObject *mo, int index) +{ + return prop.isScriptable() && prop.isValid() + // the following lookup is to ensure that we have the + // "most derived" occurrence of the property with this name + && (mo->indexOfProperty(prop.name()) == index); +} + +static uint flagsForMetaProperty(const QMetaProperty &prop) +{ + return (QScriptValue::Undeletable + | (!prop.isWritable() + ? QScriptValue::ReadOnly + : QScriptValue::PropertyFlag(0)) + | (GeneratePropertyFunctions + ? (QScriptValue::PropertyGetter + | QScriptValue::PropertySetter) + : QScriptValue::PropertyFlag(0)) + | QScriptValue::QObjectMember + | PROPERTY_ID); +} + + +static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str) +{ + QByteArray scope; + QByteArray name; + int scopeIdx = str.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = str.left(scopeIdx); + name = str.mid(scopeIdx + 2); + } else { + name = str; + } + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) + return i; + } + return -1; +} + +static QMetaMethod metaMethod(const QMetaObject *meta, + QMetaMethod::MethodType type, + int index) +{ + if (type != QMetaMethod::Constructor) + return meta->method(index); + else + return meta->constructor(index); +} + +static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType callType, + QObject *thisQObject, const QMetaObject *meta, int initialIndex, + bool maybeOverloaded) +{ + QScriptValueImpl result; + QScriptEnginePrivate *engine = context->engine(); + + int limit; +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + int lastFoundIndex = initialIndex; + QScriptMetaObject *metaCache = engine->cachedMetaObject(meta); + if (callType != QMetaMethod::Constructor) + limit = metaCache->methodLowerBound(initialIndex); + else + limit = 0; +#else + limit = 0; +#endif + + QByteArray funName; + QScriptMetaMethod chosenMethod; + int chosenIndex = -1; + QVarLengthArray<QVariant, 9> args; + QVector<QScriptMetaArguments> candidates; + QVector<QScriptMetaArguments> unresolved; + QVector<int> tooFewArgs; + QVector<int> conversionFailed; + int index; + for (index = initialIndex; index >= limit; --index) { + QScriptMetaMethod mtd; +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + if (callType != QMetaMethod::Constructor) + mtd = metaCache->findMethod(index); + if (!mtd.isValid()) +#endif + { + QMetaMethod method = metaMethod(meta, callType, index); + + QVector<QScriptMetaType> types; + // resolve return type + QByteArray returnTypeName = method.typeName(); + int rtype = QMetaType::type(returnTypeName); + if ((rtype == 0) && !returnTypeName.isEmpty()) { + if (returnTypeName == "QVariant") { + types.append(QScriptMetaType::variant()); + } else { + int enumIndex = indexOfMetaEnum(meta, returnTypeName); + if (enumIndex != -1) + types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName)); + else + types.append(QScriptMetaType::unresolved(returnTypeName)); + } + } else { + if (callType == QMetaMethod::Constructor) + types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*")); + else if (returnTypeName == "QVariant") + types.append(QScriptMetaType::variant()); + else + types.append(QScriptMetaType::metaType(rtype, returnTypeName)); + } + // resolve argument types + QList<QByteArray> parameterTypeNames = method.parameterTypes(); + for (int i = 0; i < parameterTypeNames.count(); ++i) { + QByteArray argTypeName = parameterTypeNames.at(i); + int atype = QMetaType::type(argTypeName); + if (atype == 0) { + if (argTypeName == "QVariant") { + types.append(QScriptMetaType::variant()); + } else { + int enumIndex = indexOfMetaEnum(meta, argTypeName); + if (enumIndex != -1) + types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName)); + else + types.append(QScriptMetaType::unresolved(argTypeName)); + } + } else { + if (argTypeName == "QVariant") + types.append(QScriptMetaType::variant()); + else + types.append(QScriptMetaType::metaType(atype, argTypeName)); + } + } + + mtd = QScriptMetaMethod(methodName(method), types); + +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + if (mtd.fullyResolved() && (callType != QMetaMethod::Constructor)) + metaCache->registerMethod(index, mtd); +#endif + } + + if (index == initialIndex) + funName = mtd.name(); + else { + if (mtd.name() != funName) + continue; +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + lastFoundIndex = index; +#endif + } + + if (context->argumentCount() < mtd.argumentCount()) { + tooFewArgs.append(index); + continue; + } + + if (!mtd.fullyResolved()) { + // remember it so we can give an error message later, if necessary + unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index, + mtd, QVarLengthArray<QVariant, 9>())); + if (mtd.hasUnresolvedReturnType()) + continue; + } + + if (args.count() != mtd.count()) + args.resize(mtd.count()); + + QScriptMetaType retType = mtd.returnType(); + args[0] = QVariant(retType.typeId(), (void *)0); // the result + + // try to convert arguments + bool converted = true; + int matchDistance = 0; + for (int i = 0; converted && i < mtd.argumentCount(); ++i) { + QScriptValueImpl actual = context->argument(i); + QScriptMetaType argType = mtd.argumentType(i); + int tid = -1; + QVariant v; + if (argType.isUnresolved()) { + v = QVariant(QMetaType::QObjectStar, (void *)0); + converted = engine->convertToNativeQObject( + actual, argType.name(), reinterpret_cast<void* *>(v.data())); + } else if (argType.isVariant()) { + if (actual.isVariant()) { + v = actual.variantValue(); + } else { + v = actual.toVariant(); + converted = v.isValid() || actual.isUndefined() || actual.isNull(); + } + } else { + tid = argType.typeId(); + v = QVariant(tid, (void *)0); + converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine); + if (engine->hasUncaughtException()) + return; + } + + if (!converted) { + if (actual.isVariant()) { + if (tid == -1) + tid = argType.typeId(); + QVariant &vv = actual.variantValue(); + if (vv.canConvert(QVariant::Type(tid))) { + v = vv; + converted = v.convert(QVariant::Type(tid)); + if (converted && (vv.userType() != tid)) + matchDistance += 10; + } else { + QByteArray vvTypeName = vv.typeName(); + if (vvTypeName.endsWith('*') + && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) { + v = QVariant(tid, *reinterpret_cast<void* *>(vv.data())); + converted = true; + matchDistance += 10; + } + } + } else if (actual.isNumber()) { + // see if it's an enum value + QMetaEnum m; + if (argType.isMetaEnum()) { + m = meta->enumerator(argType.enumeratorIndex()); + } else { + int mi = indexOfMetaEnum(meta, argType.name()); + if (mi != -1) + m = meta->enumerator(mi); + } + if (m.isValid()) { + int ival = actual.toInt32(); + if (m.valueToKey(ival) != 0) { + qVariantSetValue(v, ival); + converted = true; + matchDistance += 10; + } + } + } + } else { + // determine how well the conversion matched + if (actual.isNumber()) { + switch (tid) { + case QMetaType::Double: + // perfect + break; + case QMetaType::Float: + matchDistance += 1; + break; + case QMetaType::LongLong: + case QMetaType::ULongLong: + matchDistance += 2; + break; + case QMetaType::Long: + case QMetaType::ULong: + matchDistance += 3; + break; + case QMetaType::Int: + case QMetaType::UInt: + matchDistance += 4; + break; + case QMetaType::Short: + case QMetaType::UShort: + matchDistance += 5; + break; + case QMetaType::Char: + case QMetaType::UChar: + matchDistance += 6; + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isString()) { + switch (tid) { + case QMetaType::QString: + // perfect + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isBoolean()) { + switch (tid) { + case QMetaType::Bool: + // perfect + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isDate()) { + switch (tid) { + case QMetaType::QDateTime: + // perfect + break; + case QMetaType::QDate: + matchDistance += 1; + break; + case QMetaType::QTime: + matchDistance += 2; + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isRegExp()) { + switch (tid) { + case QMetaType::QRegExp: + // perfect + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isVariant()) { + if (argType.isVariant() + || (actual.variantValue().userType() == tid)) { + // perfect + } else { + matchDistance += 10; + } + } else if (actual.isArray()) { + switch (tid) { + case QMetaType::QStringList: + case QMetaType::QVariantList: + matchDistance += 5; + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isQObject()) { + switch (tid) { + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + // perfect + break; + default: + matchDistance += 10; + break; + } + } else if (actual.isNull()) { + switch (tid) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + // perfect + break; + default: + if (!argType.name().endsWith('*')) + matchDistance += 10; + break; + } + } else { + matchDistance += 10; + } + } + + if (converted) + args[i+1] = v; + } + + if (converted) { + if ((context->argumentCount() == mtd.argumentCount()) + && (matchDistance == 0)) { + // perfect match, use this one + chosenMethod = mtd; + chosenIndex = index; + break; + } else { + bool redundant = false; + if ((callType != QMetaMethod::Constructor) + && (index < meta->methodOffset())) { + // it is possible that a virtual method is redeclared in a subclass, + // in which case we want to ignore the superclass declaration + for (int i = 0; i < candidates.size(); ++i) { + const QScriptMetaArguments &other = candidates.at(i); + if (mtd.types() == other.method.types()) { + redundant = true; + break; + } + } + } + if (!redundant) { + QScriptMetaArguments metaArgs(matchDistance, index, mtd, args); + if (candidates.isEmpty()) { + candidates.append(metaArgs); + } else { + const QScriptMetaArguments &otherArgs = candidates.at(0); + if ((args.count() > otherArgs.args.count()) + || ((args.count() == otherArgs.args.count()) + && (matchDistance <= otherArgs.matchDistance))) { + candidates.prepend(metaArgs); + } else { + candidates.append(metaArgs); + } + } + } + } + } else if (mtd.fullyResolved()) { + conversionFailed.append(index); + } + + if (!maybeOverloaded) + break; + } + +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + if ((index == -1) && (lastFoundIndex != limit) && maybeOverloaded + && (callType != QMetaMethod::Constructor)) { + metaCache->setMethodLowerBound(initialIndex, lastFoundIndex); + } +#endif + + if ((chosenIndex == -1) && candidates.isEmpty()) { + context->calleeMetaIndex = initialIndex; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine->notifyFunctionEntry(context); +#endif + if (!conversionFailed.isEmpty()) { + QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n") + .arg(QLatin1String(funName)); + for (int i = 0; i < conversionFailed.size(); ++i) { + if (i > 0) + message += QLatin1String("\n"); + QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i)); + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); + } + result = context->throwError(QScriptContext::TypeError, message); + } else if (!unresolved.isEmpty()) { + QScriptMetaArguments argsInstance = unresolved.first(); + int unresolvedIndex = argsInstance.method.firstUnresolvedIndex(); + Q_ASSERT(unresolvedIndex != -1); + QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex); + QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name()); + QString message = QString::fromLatin1("cannot call %0(): ") + .arg(QString::fromLatin1(funName)); + if (unresolvedIndex > 0) { + message.append(QString::fromLatin1("argument %0 has unknown type `%1'"). + arg(unresolvedIndex).arg(unresolvedTypeName)); + } else { + message.append(QString::fromLatin1("unknown return type `%0'") + .arg(unresolvedTypeName)); + } + message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())")); + result = context->throwError(QScriptContext::TypeError, message); + } else { + QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n") + .arg(QLatin1String(funName)); + for (int i = 0; i < tooFewArgs.size(); ++i) { + if (i > 0) + message += QLatin1String("\n"); + QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i)); + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); + } + result = context->throwError(QScriptContext::SyntaxError, message); + } + } else { + if (chosenIndex == -1) { + QScriptMetaArguments metaArgs = candidates.at(0); + if ((candidates.size() > 1) + && (metaArgs.args.count() == candidates.at(1).args.count()) + && (metaArgs.matchDistance == candidates.at(1).matchDistance)) { + // ambiguous call + QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n") + .arg(QLatin1String(funName)); + for (int i = 0; i < candidates.size(); ++i) { + if (i > 0) + message += QLatin1String("\n"); + QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index); + message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); + } + result = context->throwError(QScriptContext::TypeError, message); + } else { + chosenMethod = metaArgs.method; + chosenIndex = metaArgs.index; + args = metaArgs.args; + } + } + + if (chosenIndex != -1) { + // call it + context->calleeMetaIndex = chosenIndex; + + QVarLengthArray<void*, 9> array(args.count()); + void **params = array.data(); + for (int i = 0; i < args.count(); ++i) { + const QVariant &v = args[i]; + switch (chosenMethod.type(i).kind()) { + case QScriptMetaType::Variant: + params[i] = const_cast<QVariant*>(&v); + break; + case QScriptMetaType::MetaType: + case QScriptMetaType::MetaEnum: + case QScriptMetaType::Unresolved: + params[i] = const_cast<void*>(v.constData()); + break; + default: + Q_ASSERT(0); + } + } + + QScriptable *scriptable = 0; + if (thisQObject) + scriptable = scriptableFromQObject(thisQObject); + QScriptEngine *oldEngine = 0; + if (scriptable) { + oldEngine = QScriptablePrivate::get(scriptable)->engine; + QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); + } + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine->notifyFunctionEntry(context); +#endif + + if (callType == QMetaMethod::Constructor) { + Q_ASSERT(meta != 0); + meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params); + } else { + Q_ASSERT(thisQObject != 0); + thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params); + } + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + if (context->state() == QScriptContext::ExceptionState) { + result = context->returnValue(); // propagate + } else { + QScriptMetaType retType = chosenMethod.returnType(); + if (retType.isVariant()) { + result = engine->valueFromVariant(*(QVariant *)params[0]); + } else if (retType.typeId() != 0) { + result = engine->create(retType.typeId(), params[0]); + if (!result.isValid()) + engine->newVariant(&result, QVariant(retType.typeId(), params[0])); + } else { + result = engine->undefinedValue(); + } + } + } + } + + context->m_result = result; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + engine->notifyFunctionExit(context); +#endif +} + + +class ExtQObjectDataIterator: public QScriptClassDataIterator +{ +public: + ExtQObjectDataIterator(const QScriptValueImpl &object); + virtual ~ExtQObjectDataIterator(); + + virtual bool hasNext() const; + virtual void next(QScript::Member *member); + + virtual bool hasPrevious() const; + virtual void previous(QScript::Member *member); + + virtual void toFront(); + virtual void toBack(); + +private: + enum State { + MetaProperties, + DynamicProperties, + MetaMethods + }; + + QScriptValueImpl m_object; + int m_index; + State m_state; +}; + +ExtQObjectDataIterator::ExtQObjectDataIterator(const QScriptValueImpl &object) +{ + m_object = object; + toFront(); +} + +ExtQObjectDataIterator::~ExtQObjectDataIterator() +{ +} + +bool ExtQObjectDataIterator::hasNext() const +{ + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return false; + const QMetaObject *meta = inst->value->metaObject(); + int i = m_index; + + switch (m_state) { + case MetaProperties: { + for ( ; i < meta->propertyCount(); ++i) { + QMetaProperty prop = meta->property(i); + if (isEnumerableMetaProperty(prop, meta, i) + && !isObjectProperty(m_object, prop.name())) { + return true; + } + } + i = 0; + // fall-through + } + + case DynamicProperties: { + QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); + for ( ; i < dpNames.count(); ++i) { + if (!isObjectProperty(m_object, dpNames.at(i))) { + return true; + } + } + if (inst->options & QScriptEngine::SkipMethodsInEnumeration) + return false; + i = (inst->options & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + // fall-through + } + + case MetaMethods: { + for ( ; i < meta->methodCount(); ++i) { + QMetaMethod method = meta->method(i); + if (hasMethodAccess(method, i, inst->options) + && !isObjectProperty(m_object, method.signature())) { + return true; + } + } + } + + } // switch + + return false; +} + +void ExtQObjectDataIterator::next(QScript::Member *member) +{ + QScriptEnginePrivate *eng = m_object.engine(); + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return; + const QMetaObject *meta = inst->value->metaObject(); + int i = m_index; + + switch (m_state) { + case MetaProperties: { + for ( ; i < meta->propertyCount(); ++i) { + QMetaProperty prop = meta->property(i); + if (isEnumerableMetaProperty(prop, meta, i) + && !isObjectProperty(m_object, prop.name())) { + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name())); + member->native(nameId, i, flagsForMetaProperty(prop)); + m_index = i + 1; + return; + } + } + m_state = DynamicProperties; + m_index = 0; + i = m_index; + // fall-through + } + + case DynamicProperties: { + QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); + for ( ; i < dpNames.count(); ++i) { + if (!isObjectProperty(m_object, dpNames.at(i))) { + QByteArray name = dpNames.at(i); + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); + member->native(nameId, i, + QScriptValue::QObjectMember + | DYNAPROPERTY_ID); + m_index = i + 1; + return; + } + } + m_state = MetaMethods; + m_index = (inst->options & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + i = m_index; + // fall-through + } + + case MetaMethods: { + for ( ; i < meta->methodCount(); ++i) { + QMetaMethod method = meta->method(i); + if (hasMethodAccess(method, i, inst->options) + && !isObjectProperty(m_object, method.signature())) { + QMetaMethod method = meta->method(i); + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature())); + member->native(nameId, i, + QScriptValue::QObjectMember + | METHOD_ID); + m_index = i + 1; + return; + } + } + } + + } // switch + + member->invalidate(); +} + +bool ExtQObjectDataIterator::hasPrevious() const +{ + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return false; + const QMetaObject *meta = inst->value->metaObject(); + int i = m_index - 1; + + switch (m_state) { + case MetaMethods: { + int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + for ( ; i >= limit; --i) { + QMetaMethod method = meta->method(i); + if (hasMethodAccess(method, i, inst->options) + && !isObjectProperty(m_object, method.signature())) { + return true; + } + } + i = inst->value->dynamicPropertyNames().count() - 1; + // fall-through + } + + case DynamicProperties: { + QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); + for ( ; i >= 0; --i) { + if (!isObjectProperty(m_object, dpNames.at(i))) { + return true; + } + } + i = meta->propertyCount() - 1; + // fall-through + } + + case MetaProperties: { + int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties) + ? meta->propertyOffset() : 0; + for ( ; i >= limit; --i) { + QMetaProperty prop = meta->property(i); + if (isEnumerableMetaProperty(prop, meta, i) + && !isObjectProperty(m_object, prop.name())) { + return true; + } + } + } + + } // switch + + return false; +} + +void ExtQObjectDataIterator::previous(QScript::Member *member) +{ + QScriptEnginePrivate *eng = m_object.engine(); + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return; + const QMetaObject *meta = inst->value->metaObject(); + int i = m_index - 1; + + switch (m_state) { + case MetaMethods: { + int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + for ( ; i >= limit; --i) { + QMetaMethod method = meta->method(i); + if (hasMethodAccess(method, i, inst->options) + && !isObjectProperty(m_object, method.signature())) { + QMetaMethod method = meta->method(i); + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature())); + member->native(nameId, i, + QScriptValue::QObjectMember + | METHOD_ID); + m_index = i; + return; + } + } + m_state = DynamicProperties; + m_index = inst->value->dynamicPropertyNames().count() - 1; + i = m_index; + // fall-through + } + + case DynamicProperties: { + QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); + for ( ; i >= 0; --i) { + if (!isObjectProperty(m_object, dpNames.at(i))) { + QByteArray name = dpNames.at(i); + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); + member->native(nameId, i, + QScriptValue::QObjectMember + | DYNAPROPERTY_ID); + m_index = i; + return; + } + } + m_state = MetaProperties; + m_index = meta->propertyCount() - 1; + i = m_index; + // fall-through + } + + case MetaProperties: { + int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties) + ? meta->propertyOffset() : 0; + for ( ; i >= limit; --i) { + QMetaProperty prop = meta->property(i); + if (isEnumerableMetaProperty(prop, meta, i) + && !isObjectProperty(m_object, prop.name())) { + QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name())); + member->native(nameId, i, flagsForMetaProperty(prop)); + m_index = i; + return; + } + } + } + + } // switch + + member->invalidate(); +} + +void ExtQObjectDataIterator::toFront() +{ + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return; + m_state = MetaProperties; + const QMetaObject *meta = inst->value->metaObject(); + m_index = (inst->options & QScriptEngine::ExcludeSuperClassProperties) + ? meta->propertyOffset() : 0; +} + +void ExtQObjectDataIterator::toBack() +{ + ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); + if (!inst->value) + return; + if (inst->options & QScriptEngine::SkipMethodsInEnumeration) { + m_state = DynamicProperties; + m_index = inst->value->dynamicPropertyNames().count(); + } else { + m_state = MetaMethods; + const QMetaObject *meta = inst->value->metaObject(); + m_index = meta->methodCount(); + } +} + +class ExtQObjectData: public QScriptClassData +{ +public: + ExtQObjectData(QScriptClassInfo *classInfo) + : m_classInfo(classInfo) + { + } + + virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *, + QScript::AccessMode access) + { + ExtQObject::Instance *inst = ExtQObject::Instance::get(object, m_classInfo); + QObject *qobject = inst->value; + if (! qobject) { + // the object was deleted. We return true so we can + // throw an error in get()/put() + member->native(nameId, /*id=*/-1, /*flags=*/0); + return true; + } + + const QScriptEngine::QObjectWrapOptions &opt = inst->options; + const QMetaObject *meta = qobject->metaObject(); + + QScriptEnginePrivate *eng = object.engine(); + +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + QScriptMetaObject *metaCache = eng->cachedMetaObject(meta); + if (metaCache->findMember(nameId, member)) { + bool ignore = false; + switch (member->flags() & ID_MASK) { + case PROPERTY_ID: + ignore = (opt & QScriptEngine::ExcludeSuperClassProperties) + && (member->id() < meta->propertyOffset()); + break; + case METHOD_ID: + ignore = ((opt & QScriptEngine::ExcludeSuperClassMethods) + && (member->id() < meta->methodOffset())) + || ((opt & QScriptEngine::ExcludeDeleteLater) + && (member->id() == 2)); + break; + // we don't cache dynamic properties nor children, + // so no need to handle DYNAPROPERTY_ID and CHILD_ID + default: + break; + } + if (!ignore) + return true; + } +#endif + + QString memberName = eng->toString(nameId); + QByteArray name = memberName.toLatin1(); + + int index = -1; + + if (name.contains('(')) { + QByteArray normalized = QMetaObject::normalizedSignature(name); + if (-1 != (index = meta->indexOfMethod(normalized))) { + QMetaMethod method = meta->method(index); + if (hasMethodAccess(method, index, opt)) { + member->native(nameId, index, + QScriptValue::QObjectMember + | METHOD_ID); +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + metaCache->registerMember(nameId, *member); +#endif + if (!(opt & QScriptEngine::ExcludeSuperClassMethods) + || (index >= meta->methodOffset())) { + return true; + } + } + } + } + + index = meta->indexOfProperty(name); + if (index != -1) { + QMetaProperty prop = meta->property(index); + if (prop.isScriptable()) { + member->native(nameId, index, flagsForMetaProperty(prop)); +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + metaCache->registerMember(nameId, *member); +#endif + if (!(opt & QScriptEngine::ExcludeSuperClassProperties) + || (index >= meta->propertyOffset())) { + return true; + } + } + } + + index = qobject->dynamicPropertyNames().indexOf(name); + if (index != -1) { + member->native(nameId, index, + QScriptValue::QObjectMember + | DYNAPROPERTY_ID); + // not cached because it can be removed + return true; + } + + const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + for (index = meta->methodCount() - 1; index >= offset; --index) { + QMetaMethod method = meta->method(index); + if (hasMethodAccess(method, index, opt) + && (methodName(method) == name)) { + member->native(nameId, index, + QScriptValue::QObjectMember + | METHOD_ID + | MAYBE_OVERLOADED); +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + metaCache->registerMember(nameId, *member); +#endif + return true; + } + } + + if (!(opt & QScriptEngine::ExcludeChildObjects)) { + QList<QObject*> children = qobject->children(); + for (index = 0; index < children.count(); ++index) { + QObject *child = children.at(index); + if (child->objectName() == memberName) { + member->native(nameId, index, + QScriptValue::ReadOnly + | QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration + | CHILD_ID); + // not cached because it can be removed or change name + return true; + } + } + } + + if ((access & QScript::Write) && (opt & QScriptEngine::AutoCreateDynamicProperties)) { + member->native(nameId, -1, DYNAPROPERTY_ID); + return true; + } + + return false; + } + + virtual bool get(const QScriptValueImpl &obj, const QScript::Member &member, QScriptValueImpl *result) + { + if (! member.isNativeProperty()) + return false; + + QScriptEnginePrivate *eng = obj.engine(); + + ExtQObject::Instance *inst = ExtQObject::Instance::get(obj, m_classInfo); + QObject *qobject = inst->value; + if (!qobject) { + QScriptContextPrivate *ctx = eng->currentContext(); + *result = ctx->throwError( + QString::fromLatin1("cannot access member `%0' of deleted QObject") + .arg(member.nameId()->s)); + return true; + } + + switch (member.flags() & ID_MASK) { + case PROPERTY_ID: { + const QMetaObject *meta = qobject->metaObject(); + const int propertyIndex = member.id(); + QMetaProperty prop = meta->property(propertyIndex); + Q_ASSERT(prop.isScriptable()); + if (GeneratePropertyFunctions) { + QScriptValueImpl accessor; +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + QScriptMetaObject *metaCache = eng->cachedMetaObject(meta); + accessor = metaCache->findPropertyAccessor(propertyIndex); + if (!accessor.isValid()) { +#endif + accessor = eng->createFunction(new QtPropertyFunction(meta, propertyIndex)); +#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE + metaCache->registerPropertyAccessor(propertyIndex, accessor); + } +#endif + *result = accessor; + } else { + QVariant v = prop.read(qobject); + *result = eng->valueFromVariant(v); + } + } break; + + case DYNAPROPERTY_ID: { + if (member.id() != -1) { + QVariant v = qobject->property(member.nameId()->s.toLatin1()); + *result = eng->valueFromVariant(v); + } else { + *result = eng->undefinedValue(); + } + } break; + + case METHOD_ID: { + QScript::Member m; + bool maybeOverloaded = (member.flags() & MAYBE_OVERLOADED) != 0; + *result = eng->createFunction(new QtFunction(obj, member.id(), + maybeOverloaded)); + // make it persist (otherwise Function.prototype.disconnect() would fail) + uint flags = QScriptValue::QObjectMember; + if (inst->options & QScriptEngine::SkipMethodsInEnumeration) + flags |= QScriptValue::SkipInEnumeration; + QScriptObject *instance = obj.objectValue(); + if (!instance->findMember(member.nameId(), &m)) + instance->createMember(member.nameId(), &m, flags); + instance->put(m, *result); + } break; + + case CHILD_ID: { + QObject *child = qobject->children().at(member.id()); + result->invalidate(); + QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; + eng->newQObject(result, child, QScriptEngine::QtOwnership, opt); + } break; + + } // switch + + return true; + } + + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, const QScriptValueImpl &value) + { + if (! member.isNativeProperty() || ! member.isWritable()) + return false; + + ExtQObject::Instance *inst = ExtQObject::Instance::get(*object, m_classInfo); + QObject *qobject = inst->value; + if (!qobject) { + QScriptEnginePrivate *eng = object->engine(); + QScriptContextPrivate *ctx = eng->currentContext(); + ctx->throwError(QString::fromLatin1("cannot access member `%0' of deleted QObject") + .arg(member.nameId()->s)); + return true; + } + + switch (member.flags() & ID_MASK) { + case CHILD_ID: + return false; + + case METHOD_ID: { + QScript::Member m; + QScriptObject *instance = object->objectValue(); + if (!instance->findMember(member.nameId(), &m)) { + instance->createMember(member.nameId(), &m, + /*flags=*/0); + } + instance->put(m, value); + return true; + } + + case PROPERTY_ID: + if (GeneratePropertyFunctions) { + // we shouldn't get here, QScriptValueImpl::setProperty() messed up + Q_ASSERT_X(0, "put", "Q_PROPERTY access cannot be overridden"); + return false; + } else { + const QMetaObject *meta = qobject->metaObject(); + QMetaProperty prop = meta->property(member.id()); + Q_ASSERT(prop.isScriptable()); + QVariant v = variantFromValue(object->engine(), prop.userType(), value); + bool ok = prop.write(qobject, v); + return ok; + } + + case DYNAPROPERTY_ID: { + QVariant v = value.toVariant(); + return ! qobject->setProperty(member.nameId()->s.toLatin1(), v); + } + + } // switch + return false; + } + + virtual bool removeMember(const QScriptValueImpl &object, + const QScript::Member &member) + { + QObject *qobject = object.toQObject(); + if (!qobject || !member.isNativeProperty() || !member.isDeletable()) + return false; + + if ((member.flags() & ID_MASK) == DYNAPROPERTY_ID) { + qobject->setProperty(member.nameId()->s.toLatin1(), QVariant()); + return true; + } + + return false; + } + + virtual void mark(const QScriptValueImpl &, int) + { + } + + virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object) + { + return new ExtQObjectDataIterator(object); + } + +private: + QScriptClassInfo *m_classInfo; +}; + +struct QObjectConnection +{ + int slotIndex; + QScriptValueImpl receiver; + QScriptValueImpl slot; + QScriptValueImpl senderWrapper; + + QObjectConnection(int i, const QScriptValueImpl &r, const QScriptValueImpl &s, + const QScriptValueImpl &sw) + : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {} + QObjectConnection() : slotIndex(-1) {} + + bool hasTarget(const QScriptValueImpl &r, const QScriptValueImpl &s) const + { + if (r.isObject() != receiver.isObject()) + return false; + if ((r.isObject() && receiver.isObject()) + && (r.objectValue() != receiver.objectValue())) { + return false; + } + return (s.objectValue() == slot.objectValue()); + } + + void mark(int generation) + { + if (senderWrapper.isValid() && !senderWrapper.isMarked(generation)) { + // see if the sender should be marked or not + ExtQObject::Instance *inst = ExtQObject::Instance::get(senderWrapper); + if ((inst->ownership == QScriptEngine::ScriptOwnership) + || ((inst->ownership == QScriptEngine::AutoOwnership) + && inst->value && !inst->value->parent())) { + senderWrapper.invalidate(); + } else { + senderWrapper.mark(generation); + } + } + if (receiver.isValid()) + receiver.mark(generation); + if (slot.isValid()) + slot.mark(generation); + } +}; + +class QObjectConnectionManager: public QObject +{ +public: + QObjectConnectionManager(); + ~QObjectConnectionManager(); + + bool addSignalHandler(QObject *sender, int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot, + const QScriptValueImpl &senderWrapper = QScriptValueImpl()); + bool removeSignalHandler( + QObject *sender, int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot); + + static const QMetaObject staticMetaObject; + virtual const QMetaObject *metaObject() const; + virtual void *qt_metacast(const char *); + virtual int qt_metacall(QMetaObject::Call, int, void **argv); + + void execute(int slotIndex, void **argv); + + void mark(int generation); + +private: + int m_slotCounter; + QVector<QVector<QObjectConnection> > connections; +}; + +} // ::QScript + + + +QScript::ExtQObject::ExtQObject(QScriptEnginePrivate *eng): + Ecma::Core(eng, QLatin1String("QObject"), QScriptClassInfo::QObjectType) +{ + newQObject(&publicPrototype, new QScript::QObjectPrototype(), + QScriptEngine::AutoOwnership, + QScriptEngine::ExcludeSuperClassMethods + | QScriptEngine::ExcludeSuperClassProperties + | QScriptEngine::ExcludeChildObjects); + + eng->newConstructor(&ctor, this, publicPrototype); + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("findChild"), method_findChild, 1); + addPrototypeFunction(QLatin1String("findChildren"), method_findChildren, 1); + + classInfo()->setData(new QScript::ExtQObjectData(classInfo())); +} + +QScript::ExtQObject::~ExtQObject() +{ +} + +void QScript::ExtQObject::execute(QScriptContextPrivate *context) +{ + QScriptValueImpl tmp; + newQObject(&tmp, 0); + context->setReturnValue(tmp); +} + +void QScript::ExtQObject::newQObject(QScriptValueImpl *result, QObject *value, + QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options) +{ + Instance *instance; + if (!result->isValid()) { + engine()->newObject(result, publicPrototype, classInfo()); + instance = new Instance(); + result->setObjectData(instance); + } else { + Q_ASSERT(result->isObject()); + if (result->classInfo() != classInfo()) { + result->destroyObjectData(); + result->setClassInfo(classInfo()); + instance = new Instance(); + result->setObjectData(instance); + } else { + instance = Instance::get(*result); + } + } + instance->value = value; + instance->ownership = ownership; + instance->options = options; +} + +QScriptValueImpl QScript::ExtQObject::method_findChild(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QObject *obj = instance->value; + QString name = context->argument(0).toString(); + QObject *child = qFindChild<QObject*>(obj, name); + QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; + QScriptValueImpl result; + eng->newQObject(&result, child, QScriptEngine::QtOwnership, opt); + return result; + } + return eng->undefinedValue(); +} + +QScriptValueImpl QScript::ExtQObject::method_findChildren(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QObject *obj = instance->value; + QList<QObject*> found; + QScriptValueImpl arg = context->argument(0); +#ifndef QT_NO_REGEXP + if (arg.isRegExp()) { + QRegExp re = arg.toRegExp(); + found = qFindChildren<QObject*>(obj, re); + } else +#endif + { + QString name = arg.isUndefined() ? QString() : arg.toString(); + found = qFindChildren<QObject*>(obj, name); + } + QScriptValueImpl result = eng->newArray(found.size()); + QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; + for (int i = 0; i < found.size(); ++i) { + QScriptValueImpl value; + eng->newQObject(&value, found.at(i), QScriptEngine::QtOwnership, opt); + result.setProperty(i, value); + } + return result; + } + return eng->undefinedValue(); +} + +QScriptValueImpl QScript::ExtQObject::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QObject *obj = instance->value; + const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject; + QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed"); + + QString str = QString::fromUtf8("%0(name = \"%1\")") + .arg(QLatin1String(meta->className())).arg(name); + return QScriptValueImpl(eng, str); + } + return eng->undefinedValue(); +} + + + +static const uint qt_meta_data_QObjectConnectionManager[] = { + + // content: + 1, // revision + 0, // classname + 0, 0, // classinfo + 1, 10, // methods + 0, 0, // properties + 0, 0, // enums/sets + + // slots: signature, parameters, type, tag, flags + 35, 34, 34, 34, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_QObjectConnectionManager[] = { + "QScript::QObjectConnectionManager\0\0execute()\0" +}; + +const QMetaObject QScript::QObjectConnectionManager::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager, + qt_meta_data_QObjectConnectionManager, 0 } +}; + +const QMetaObject *QScript::QObjectConnectionManager::metaObject() const +{ + return &staticMetaObject; +} + +void *QScript::QObjectConnectionManager::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager)) + return static_cast<void*>(const_cast<QObjectConnectionManager*>(this)); + return QObject::qt_metacast(_clname); +} + +int QScript::QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + execute(_id, _a); + _id -= m_slotCounter; + } + return _id; +} + +void QScript::QObjectConnectionManager::execute(int slotIndex, void **argv) +{ + QScriptValueImpl receiver; + QScriptValueImpl slot; + QScriptValueImpl senderWrapper; + int signalIndex = -1; + for (int i = 0; i < connections.size(); ++i) { + const QVector<QObjectConnection> &cs = connections.at(i); + for (int j = 0; j < cs.size(); ++j) { + const QObjectConnection &c = cs.at(j); + if (c.slotIndex == slotIndex) { + receiver = c.receiver; + slot = c.slot; + senderWrapper = c.senderWrapper; + signalIndex = i; + break; + } + } + } + Q_ASSERT(slot.isValid()); + + QScriptEnginePrivate *eng = slot.engine(); + + if (eng->isCollecting()) { + // we can't do a script function call during GC, + // so we're forced to ignore this signal + return; + } + + QScriptFunction *fun = eng->convertToNativeFunction(slot); + if (fun == 0) { + // the signal handler has been GC'ed. This can only happen when + // a QObject is owned by the engine, the engine is destroyed, and + // there is a script function connected to the destroyed() signal + Q_ASSERT(signalIndex <= 1); // destroyed(QObject*) + return; + } + + const QMetaObject *meta = sender()->metaObject(); + const QMetaMethod method = meta->method(signalIndex); + + QList<QByteArray> parameterTypes = method.parameterTypes(); + int argc = parameterTypes.count(); + + QScriptValueImpl activation; + eng->newActivation(&activation); + QScriptObject *activation_data = activation.objectValue(); + activation_data->m_scope = slot.scope(); + + int formalCount = fun->formals.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx + 1); + activation_data->m_values.resize(mx + 1); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId; + if (i < formalCount) + nameId = fun->formals.at(i); + else + nameId = 0; + activation_data->m_members[i].object(nameId, i, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + if (i < argc) { + int argType = QMetaType::type(parameterTypes.at(i)); + activation_data->m_values[i] = eng->create(argType, argv[i + 1]); + } else { + activation_data->m_values[i] = eng->undefinedValue(); + } + } + + QScriptValueImpl senderObject; + if (senderWrapper.isQObject()) { + senderObject = senderWrapper; + } else { + QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; + eng->newQObject(&senderObject, sender(), QScriptEngine::QtOwnership, opt); + } + activation_data->m_members[mx].object(eng->idTable()->id___qt_sender__, mx, + QScriptValue::SkipInEnumeration); + activation_data->m_values[mx] = senderObject; + + QScriptValueImpl thisObject; + if (receiver.isObject()) + thisObject = receiver; + else + thisObject = eng->globalObject(); + + QScriptContextPrivate *context_data = eng->pushContext(); + context_data->m_activation = activation; + context_data->m_callee = slot; + context_data->m_thisObject = thisObject; + context_data->argc = argc; + context_data->args = const_cast<QScriptValueImpl*> (activation_data->m_values.constData()); + + fun->execute(context_data); + + eng->popContext(); + if (eng->hasUncaughtException()) + eng->emitSignalHandlerException(); +} + +QScript::QObjectConnectionManager::QObjectConnectionManager() + : m_slotCounter(0) +{ +} + +QScript::QObjectConnectionManager::~QObjectConnectionManager() +{ +} + +void QScript::QObjectConnectionManager::mark(int generation) +{ + for (int i = 0; i < connections.size(); ++i) { + QVector<QObjectConnection> &cs = connections[i]; + for (int j = 0; j < cs.size(); ++j) + cs[j].mark(generation); + } +} + +bool QScript::QObjectConnectionManager::addSignalHandler( + QObject *sender, int signalIndex, const QScriptValueImpl &receiver, + const QScriptValueImpl &function, const QScriptValueImpl &senderWrapper) +{ + if (connections.size() <= signalIndex) + connections.resize(signalIndex+1); + QVector<QObjectConnection> &cs = connections[signalIndex]; + int absSlotIndex = m_slotCounter + metaObject()->methodOffset(); + bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex); + if (ok) { + cs.append(QScript::QObjectConnection(m_slotCounter++, receiver, function, senderWrapper)); + QMetaMethod signal = sender->metaObject()->method(signalIndex); + QByteArray signalString; + signalString.append('2'); // signal code + signalString.append(signal.signature()); + static_cast<QScript::QObjectNotifyCaller*>(sender)->callConnectNotify(signalString); + } + return ok; +} + +bool QScript::QObjectConnectionManager::removeSignalHandler( + QObject *sender, int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot) +{ + if (connections.size() <= signalIndex) + return false; + QVector<QObjectConnection> &cs = connections[signalIndex]; + for (int i = 0; i < cs.size(); ++i) { + const QObjectConnection &c = cs.at(i); + if (c.hasTarget(receiver, slot)) { + int absSlotIndex = c.slotIndex + metaObject()->methodOffset(); + bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex); + if (ok) { + cs.remove(i); + QMetaMethod signal = sender->metaObject()->method(signalIndex); + QByteArray signalString; + signalString.append('2'); // signal code + signalString.append(signal.signature()); + static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString); + } + return ok; + } + } + return false; +} + + + +QString QScript::QtPropertyFunction::functionName() const +{ + QMetaProperty prop = m_meta->property(m_index); + return QLatin1String(prop.name()); +} + +void QScript::QtPropertyFunction::execute(QScriptContextPrivate *context) +{ + context->calleeMetaIndex = m_index; + + QScriptEnginePrivate *eng_p = context->engine(); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionEntry(context); +#endif + QScriptValueImpl result = eng_p->undefinedValue(); + + QScriptValueImpl object = context->thisObject(); + QObject *qobject = object.toQObject(); + while ((!qobject || (qobject->metaObject() != m_meta)) + && object.prototype().isObject()) { + object = object.prototype(); + qobject = object.toQObject(); + } + Q_ASSERT(qobject); + + QMetaProperty prop = m_meta->property(m_index); + Q_ASSERT(prop.isScriptable()); + if (context->argumentCount() == 0) { + // get + if (prop.isValid()) { + QScriptable *scriptable = scriptableFromQObject(qobject); + QScriptEngine *oldEngine = 0; + if (scriptable) { + oldEngine = QScriptablePrivate::get(scriptable)->engine; + QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p); + } + + QVariant v = prop.read(qobject); + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + result = eng_p->valueFromVariant(v); + } + } else { + // set + QVariant v = variantFromValue(eng_p, prop.userType(), context->argument(0)); + + QScriptable *scriptable = scriptableFromQObject(qobject); + QScriptEngine *oldEngine = 0; + if (scriptable) { + oldEngine = QScriptablePrivate::get(scriptable)->engine; + QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p); + } + + prop.write(qobject, v); + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + result = context->argument(0); + } + if (!eng_p->hasUncaughtException()) + context->m_result = result; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); +#endif +} + +QString QScript::QtFunction::functionName() const +{ + const QMetaObject *meta = metaObject(); + if (!meta) + return QString(); + QMetaMethod method = meta->method(m_initialIndex); + return QLatin1String(methodName(method)); +} + +void QScript::QtFunction::mark(QScriptEnginePrivate *engine, int generation) +{ + if (m_object.isValid()) + engine->markObject(m_object, generation); + QScriptFunction::mark(engine, generation); +} + +void QScript::QtFunction::execute(QScriptContextPrivate *context) +{ + QScriptEnginePrivate *eng_p = context->engine(); + QObject *qobj = qobject(); + if (!qobj) { + context->calleeMetaIndex = m_initialIndex; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionEntry(context); +#endif + context->throwError(QLatin1String("cannot call function of deleted QObject")); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); +#endif + return; + } + + QScriptValueImpl result = eng_p->undefinedValue(); + + const QMetaObject *meta = qobj->metaObject(); + + QObject *thisQObject = context->thisObject().toQObject(); + if (!thisQObject) // ### TypeError + thisQObject = qobj; + + if (!meta->cast(thisQObject)) { +#if 0 + // ### find common superclass, see if initialIndex is + // in that class (or a superclass of that class), + // then it's still safe to execute it + funName = methodName(meta->method(m_initialIndex)); + context->throwError( + QString::fromUtf8("cannot execute %0: %1 does not inherit %2") + .arg(QLatin1String(funName)) + .arg(QLatin1String(thisQObject->metaObject()->className())) + .arg(QLatin1String(meta->className()))); + return; +#endif + // invoking a function in the prototype + thisQObject = qobj; + } + + callQtMethod(context, QMetaMethod::Method, thisQObject, + meta, m_initialIndex, m_maybeOverloaded); +} + +int QScript::QtFunction::mostGeneralMethod(QMetaMethod *out) const +{ + const QMetaObject *meta = metaObject(); + if (!meta) + return -1; + int index = m_initialIndex; + QMetaMethod method = meta->method(index); + if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) { + // find the most general method + do { + method = meta->method(--index); + } while (method.attributes() & QMetaMethod::Cloned); + } + if (out) + *out = method; + return index; +} + +QList<int> QScript::QtFunction::overloadedIndexes() const +{ + if (!maybeOverloaded()) + return QList<int>(); + QList<int> result; + QString name = functionName(); + const QMetaObject *meta = metaObject(); + for (int index = mostGeneralMethod() - 1; index >= 0; --index) { + QString otherName = QString::fromLatin1(methodName(meta->method(index))); + if (otherName == name) + result.append(index); + } + return result; +} + +///////////////////////////////////////////////////////// + +namespace QScript +{ + +ExtQMetaObject::Instance *ExtQMetaObject::Instance::get(const QScriptValueImpl &object, + QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + +void ExtQMetaObject::Instance::execute(QScriptContextPrivate *context) +{ + if (ctor.isFunction()) { + QScriptValueImplList args; + for (int i = 0; i < context->argumentCount(); ++i) + args << context->argument(i); + QScriptEnginePrivate *eng = context->engine(); + context->m_result = eng->call(ctor, context->thisObject(), args, + context->isCalledAsConstructor()); + } else { + if (value->constructorCount() > 0) { + callQtMethod(context, QMetaMethod::Constructor, /*thisQObject=*/0, + value, value->constructorCount()-1, /*maybeOverloaded=*/true); + if (context->state() == QScriptContext::NormalState) { + ExtQObject::Instance *inst = ExtQObject::Instance::get(context->m_result); + Q_ASSERT(inst != 0); + inst->ownership = QScriptEngine::AutoOwnership; + context->m_result.setPrototype(prototype); + } + } else { + context->m_result = context->throwError( + QScriptContext::TypeError, + QString::fromUtf8("no constructor for %0") + .arg(QLatin1String(value->className()))); + } + } +} + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + +class ExtQMetaObjectData: public QScriptClassData +{ +public: + ExtQMetaObjectData(QScriptEnginePrivate *, QScriptClassInfo *classInfo); + + virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, + QScript::Member *member, QScriptValueImpl *base, + QScript::AccessMode access); + virtual bool get(const QScriptValueImpl &object, const QScript::Member &member, + QScriptValueImpl *result); + virtual bool put(QScriptValueImpl *object, const QScript::Member &member, + const QScriptValueImpl &value); + virtual void mark(const QScriptValueImpl &object, int generation); + +private: + QScriptClassInfo *m_classInfo; +}; + +ExtQMetaObjectData::ExtQMetaObjectData(QScriptEnginePrivate *, + QScriptClassInfo *classInfo) + : m_classInfo(classInfo) +{ +} + +bool ExtQMetaObjectData::resolve(const QScriptValueImpl &object, + QScriptNameIdImpl *nameId, + QScript::Member *member, + QScriptValueImpl *base, + QScript::AccessMode /*access*/) +{ + const QMetaObject *meta = object.toQMetaObject(); + if (!meta) + return false; + + QScriptEnginePrivate *eng_p = object.engine(); + if (eng_p->idTable()->id_prototype == nameId) { + // prototype property is a proxy to constructor's prototype property + member->native(nameId, /*id=*/0, QScriptValue::Undeletable); + return true; + } + + QByteArray name = eng_p->toString(nameId).toLatin1(); + + for (int i = 0; i < meta->enumeratorCount(); ++i) { + QMetaEnum e = meta->enumerator(i); + + for (int j = 0; j < e.keyCount(); ++j) { + const char *key = e.key(j); + + if (! qstrcmp (key, name.constData())) { + member->native(nameId, e.value(j), QScriptValue::ReadOnly); + *base = object; + return true; + } + } + } + + return false; +} + +bool ExtQMetaObjectData::get(const QScriptValueImpl &object, + const QScript::Member &member, + QScriptValueImpl *result) +{ + if (! member.isNativeProperty()) + return false; + + QScriptEnginePrivate *eng_p = object.engine(); + if (eng_p->idTable()->id_prototype == member.nameId()) { + ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo); + if (inst->ctor.isFunction()) + *result = inst->ctor.property(eng_p->idTable()->id_prototype); + else + *result = inst->prototype; + } else { + *result = QScriptValueImpl(member.id()); + } + return true; +} + +bool ExtQMetaObjectData::put(QScriptValueImpl *object, const Member &member, + const QScriptValueImpl &value) +{ + if (! member.isNativeProperty()) + return false; + + QScriptEnginePrivate *eng_p = object->engine(); + if (eng_p->idTable()->id_prototype == member.nameId()) { + ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(*object, m_classInfo); + if (inst->ctor.isFunction()) + inst->ctor.setProperty(eng_p->idTable()->id_prototype, value); + else + inst->prototype = value; + } + + return true; +} + +void ExtQMetaObjectData::mark(const QScriptValueImpl &object, int generation) +{ + ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo); + if (inst->ctor.isObject() || inst->ctor.isString()) + inst->ctor.mark(generation); +} + +} // namespace QScript + +QScript::ExtQMetaObject::ExtQMetaObject(QScriptEnginePrivate *eng) + : Ecma::Core(eng, QLatin1String("QMetaObject"), QScriptClassInfo::QMetaObjectType) +{ + newQMetaObject(&publicPrototype, QScript::StaticQtMetaObject::get()); + + eng->newConstructor(&ctor, this, publicPrototype); + addPrototypeFunction(QLatin1String("className"), method_className, 0); + + classInfo()->setData(new QScript::ExtQMetaObjectData(eng, classInfo())); +} + +QScript::ExtQMetaObject::~ExtQMetaObject() +{ +} + +void QScript::ExtQMetaObject::execute(QScriptContextPrivate *context) +{ + QScriptValueImpl tmp; + newQMetaObject(&tmp, 0); + context->setReturnValue(tmp); +} + +void QScript::ExtQMetaObject::newQMetaObject(QScriptValueImpl *result, const QMetaObject *value, + const QScriptValueImpl &ctor) +{ + Instance *instance = new Instance(); + instance->value = value; + if (ctor.isFunction()) { + instance->ctor = ctor; + } else { + instance->prototype = engine()->newObject(); + instance->prototype.setPrototype(engine()->qobjectConstructor->publicPrototype); + } + + engine()->newObject(result, publicPrototype, classInfo()); + result->setObjectData(instance); +} + +QScriptValueImpl QScript::ExtQMetaObject::method_className(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + return QScriptValueImpl(eng, QString::fromLatin1(instance->value->className())); + } + return eng->undefinedValue(); +} + +QScriptQObjectData::QScriptQObjectData() + : m_connectionManager(0) +{ +} + +QScriptQObjectData::~QScriptQObjectData() +{ + if (m_connectionManager) { + delete m_connectionManager; + m_connectionManager = 0; + } +} + +bool QScriptQObjectData::addSignalHandler(QObject *sender, + int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot, + const QScriptValueImpl &senderWrapper) +{ + if (!m_connectionManager) + m_connectionManager = new QScript::QObjectConnectionManager(); + return m_connectionManager->addSignalHandler( + sender, signalIndex, receiver, slot, senderWrapper); +} + +bool QScriptQObjectData::removeSignalHandler(QObject *sender, + int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot) +{ + if (!m_connectionManager) + return false; + return m_connectionManager->removeSignalHandler( + sender, signalIndex, receiver, slot); +} + +bool QScriptQObjectData::findWrapper(QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options, + QScriptValueImpl *out) +{ + for (int i = 0; i < wrappers.size(); ++i) { + const QScriptQObjectWrapperInfo &info = wrappers.at(i); + if ((info.ownership == ownership) && (info.options == options)) { + *out = info.object; + return true; + } + } + return false; +} + +void QScriptQObjectData::registerWrapper(const QScriptValueImpl &wrapper, + QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options) +{ + wrappers.append(QScriptQObjectWrapperInfo(wrapper, ownership, options)); +} + +void QScriptQObjectData::mark(int generation) +{ + if (m_connectionManager) + m_connectionManager->mark(generation); + + { + QList<QScriptQObjectWrapperInfo>::iterator it; + for (it = wrappers.begin(); it != wrappers.end(); ) { + const QScriptQObjectWrapperInfo &info = *it; + if (info.object.isMarked(generation)) { + ++it; + } else { + it = wrappers.erase(it); + } + } + } +} + +QT_END_NAMESPACE + +#include "qscriptextqobject.moc" + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptextqobject_p.h b/src/script/qscriptextqobject_p.h new file mode 100644 index 0000000..537fa49 --- /dev/null +++ b/src/script/qscriptextqobject_p.h @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** 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 QSCRIPTEXTQOBJECT_P_H +#define QSCRIPTEXTQOBJECT_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. +// + +#ifndef QT_NO_QOBJECT + +#include "qscriptecmacore_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptclassdata_p.h" +#include "qscriptfunction_p.h" +#include "qscriptengine.h" +#include "qscriptmemberfwd_p.h" + +#include <QtCore/QHash> +#include <QtCore/QPointer> +#include <QtCore/QObject> +#include <QtCore/QVariant> +#include <QtCore/QVarLengthArray> +#include <QtCore/QVector> + +QT_BEGIN_NAMESPACE + +namespace QScript { + +class QObjectConnectionManager; + +class ExtQObject: public Ecma::Core +{ +public: + ExtQObject(QScriptEnginePrivate *engine); + virtual ~ExtQObject(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptObjectData { + public: + Instance() : ownership(QScriptEngine::QtOwnership) { } + virtual void finalize(QScriptEnginePrivate *engine); + virtual ~Instance() {} + + static Instance *get(const QScriptValueImpl &object, QScriptClassInfo *klass = 0); + + public: + QPointer<QObject> value; + QScriptEngine::ValueOwnership ownership; + QScriptEngine::QObjectWrapOptions options; + }; + + inline Instance *get(const QScriptValueImpl &object) const + { return Instance::get(object, classInfo()); } + + void newQObject(QScriptValueImpl *result, QObject *value, + QScriptEngine::ValueOwnership ownership = QScriptEngine::QtOwnership, + const QScriptEngine::QObjectWrapOptions &options = 0); + +protected: + static QScriptValueImpl method_findChild(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_findChildren(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); + static QScriptValueImpl method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); +}; + +class QtFunction: public QScriptFunction +{ +public: + QtFunction(const QScriptValueImpl &object, int initialIndex, bool maybeOverloaded) + : m_object(object), m_initialIndex(initialIndex), + m_maybeOverloaded(maybeOverloaded) + { } + + virtual ~QtFunction() { } + + virtual void execute(QScriptContextPrivate *context); + + virtual Type type() const { return QScriptFunction::Qt; } + + virtual QString functionName() const; + + virtual void mark(QScriptEnginePrivate *engine, int generation); + + inline QScriptValueImpl object() const { return m_object; } + + inline QObject *qobject() const { + if (!m_object.isQObject()) + return 0; + return m_object.toQObject(); + } + + inline const QMetaObject *metaObject() const { + if (!m_object.isQObject()) + return 0; + QObject *qobj = m_object.toQObject(); + if (!qobj) + return 0; + return qobj->metaObject(); + } + + int mostGeneralMethod(QMetaMethod *out = 0) const; + QList<int> overloadedIndexes() const; + + inline int initialIndex() const { return m_initialIndex; } + inline bool maybeOverloaded() const { return m_maybeOverloaded; } + +private: + QScriptValueImpl m_object; + int m_initialIndex; + bool m_maybeOverloaded; +}; + +class ExtQMetaObject: public Ecma::Core +{ +public: + ExtQMetaObject(QScriptEnginePrivate *engine); + virtual ~ExtQMetaObject(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptFunction { + public: + Instance() : value(0) { } + virtual ~Instance() { } + + static Instance *get(const QScriptValueImpl &object, QScriptClassInfo *klass); + + virtual void execute(QScriptContextPrivate *context); + + public: + const QMetaObject *value; + QScriptValueImpl ctor; + QScriptValueImpl prototype; + }; + + inline Instance *get(const QScriptValueImpl &object) const + { return Instance::get(object, classInfo()); } + + void newQMetaObject(QScriptValueImpl *result, const QMetaObject *value, + const QScriptValueImpl &ctor = QScriptValueImpl()); + +protected: + static QScriptValueImpl method_className(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo); +}; + +} // namespace QScript + +struct QScriptQObjectWrapperInfo +{ + QScriptQObjectWrapperInfo(const QScriptValueImpl &obj, + QScriptEngine::ValueOwnership own, + const QScriptEngine::QObjectWrapOptions &opt) + : object(obj), ownership(own), options(opt) {} + + QScriptValueImpl object; + QScriptEngine::ValueOwnership ownership; + QScriptEngine::QObjectWrapOptions options; +}; + +class QScriptQObjectData // : public QObjectUserData +{ +public: + QScriptQObjectData(); + ~QScriptQObjectData(); + + bool addSignalHandler(QObject *sender, + int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot, + const QScriptValueImpl &senderWrapper = QScriptValueImpl()); + bool removeSignalHandler(QObject *sender, + int signalIndex, + const QScriptValueImpl &receiver, + const QScriptValueImpl &slot); + + bool findWrapper(QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options, + QScriptValueImpl *out); + void registerWrapper(const QScriptValueImpl &wrapper, + QScriptEngine::ValueOwnership ownership, + const QScriptEngine::QObjectWrapOptions &options); + + void mark(int generation); + +private: + QScript::QObjectConnectionManager *m_connectionManager; + QList<QScriptQObjectWrapperInfo> wrappers; +}; + +class QScriptMetaType +{ +public: + enum Kind { + Invalid, + Variant, + MetaType, + Unresolved, + MetaEnum + }; + + inline QScriptMetaType() + : m_kind(Invalid), m_typeId(0) { } + + inline Kind kind() const + { return m_kind; } + + int typeId() const; + + inline bool isValid() const + { return (m_kind != Invalid); } + + inline bool isVariant() const + { return (m_kind == Variant); } + + inline bool isMetaType() const + { return (m_kind == MetaType); } + + inline bool isUnresolved() const + { return (m_kind == Unresolved); } + + inline bool isMetaEnum() const + { return (m_kind == MetaEnum); } + + QByteArray name() const; + + inline int enumeratorIndex() const + { Q_ASSERT(isMetaEnum()); return m_typeId; } + + inline bool operator==(const QScriptMetaType &other) const + { + return (m_kind == other.m_kind) && (m_typeId == other.m_typeId); + } + + static inline QScriptMetaType variant() + { return QScriptMetaType(Variant); } + + static inline QScriptMetaType metaType(int typeId, const QByteArray &name) + { return QScriptMetaType(MetaType, typeId, name); } + + static inline QScriptMetaType metaEnum(int enumIndex, const QByteArray &name) + { return QScriptMetaType(MetaEnum, enumIndex, name); } + + static inline QScriptMetaType unresolved(const QByteArray &name) + { return QScriptMetaType(Unresolved, /*typeId=*/0, name); } + +private: + inline QScriptMetaType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray()) + : m_kind(kind), m_typeId(typeId), m_name(name) { } + + Kind m_kind; + int m_typeId; + QByteArray m_name; +}; + +class QScriptMetaMethod +{ +public: + inline QScriptMetaMethod() + : m_firstUnresolvedIndex(-1) + { } + inline QScriptMetaMethod(const QByteArray &name, const QVector<QScriptMetaType> &types) + : m_name(name), m_types(types), m_firstUnresolvedIndex(-1) + { + QVector<QScriptMetaType>::const_iterator it; + for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) { + if ((*it).kind() == QScriptMetaType::Unresolved) { + m_firstUnresolvedIndex = it - m_types.constBegin(); + break; + } + } + } + inline bool isValid() const + { return !m_types.isEmpty(); } + + QByteArray name() const + { return m_name; } + + inline QScriptMetaType returnType() const + { return m_types.at(0); } + + inline int argumentCount() const + { return m_types.count() - 1; } + + inline QScriptMetaType argumentType(int arg) const + { return m_types.at(arg + 1); } + + inline bool fullyResolved() const + { return m_firstUnresolvedIndex == -1; } + + inline bool hasUnresolvedReturnType() const + { return (m_firstUnresolvedIndex == 0); } + + inline int firstUnresolvedIndex() const + { return m_firstUnresolvedIndex; } + + inline int count() const + { return m_types.count(); } + + inline QScriptMetaType type(int index) const + { return m_types.at(index); } + + inline QVector<QScriptMetaType> types() const + { return m_types; } + +private: + QByteArray m_name; + QVector<QScriptMetaType> m_types; + int m_firstUnresolvedIndex; +}; + +struct QScriptMetaArguments +{ + int matchDistance; + int index; + QScriptMetaMethod method; + QVarLengthArray<QVariant, 9> args; + + inline QScriptMetaArguments(int dist, int idx, const QScriptMetaMethod &mtd, + const QVarLengthArray<QVariant, 9> &as) + : matchDistance(dist), index(idx), method(mtd), args(as) { } + inline QScriptMetaArguments() + : matchDistance(0), index(-1) { } + + inline bool isValid() const + { return (index != -1); } +}; + +class QScriptMetaObject +{ +public: + inline QScriptMetaMethod findMethod(int index) const + { + return m_methods.value(index); + } + + inline void registerMethod(int index, const QScriptMetaMethod &method) + { + m_methods.insert(index, method); + } + + inline bool findMember(QScriptNameIdImpl *nameId, QScript::Member *member) const + { + QHash<QScriptNameIdImpl*, QScript::Member>::const_iterator it; + it = m_members.constFind(nameId); + if (it == m_members.constEnd()) + return false; + *member = it.value(); + return true; + } + + inline void registerMember(QScriptNameIdImpl *nameId, const QScript::Member &member) + { + m_members.insert(nameId, member); + } + + inline QList<QScriptNameIdImpl*> registeredMemberNames() const + { + return m_members.keys(); + } + + inline QScriptValueImpl findPropertyAccessor(int index) const + { + return m_propertyAccessors.value(index); + } + + inline void registerPropertyAccessor(int index, const QScriptValueImpl &accessor) + { + m_propertyAccessors.insert(index, accessor); + } + + inline QList<QScriptValueImpl> registeredPropertyAccessors() const + { + return m_propertyAccessors.values(); + } + + inline int methodLowerBound(int index) const + { + return m_methodBounds.value(index, 0); + } + + inline void setMethodLowerBound(int index, int bound) + { + m_methodBounds.insert(index, bound); + } + +private: + QHash<int, QScriptValueImpl> m_propertyAccessors; + QHash<int, QScriptMetaMethod> m_methods; + QHash<int, int> m_methodBounds; + QHash<QScriptNameIdImpl*, QScript::Member> m_members; +}; + +#endif // QT_NO_QOBJECT + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTEXTQOBJECT_P_H diff --git a/src/script/qscriptextvariant.cpp b/src/script/qscriptextvariant.cpp new file mode 100644 index 0000000..33c5edd --- /dev/null +++ b/src/script/qscriptextvariant.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 "qscriptextvariant_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +#include <QtCore/QtDebug> + +#include <QtCore/QStringList> + +#include <limits.h> + +QT_BEGIN_NAMESPACE + +namespace QScript { namespace Ext { + +Variant::Variant(QScriptEnginePrivate *eng): + Ecma::Core(eng, QLatin1String("QVariant"), QScriptClassInfo::VariantType) +{ + newVariant(&publicPrototype, QVariant()); + + eng->newConstructor(&ctor, this, publicPrototype); + + addPrototypeFunction(QLatin1String("toString"), method_toString, 0); + addPrototypeFunction(QLatin1String("valueOf"), method_valueOf, 0); +} + +Variant::~Variant() +{ +} + +Variant::Instance *Variant::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) +{ + if (! klass || klass == object.classInfo()) + return static_cast<Instance*> (object.objectData()); + + return 0; +} + +void Variant::execute(QScriptContextPrivate *context) +{ + QScriptValueImpl tmp; + newVariant(&tmp, QVariant()); + context->setReturnValue(tmp); +} + +void Variant::newVariant(QScriptValueImpl *result, const QVariant &value) +{ + Instance *instance; + if (!result->isValid()) { + engine()->newObject(result, publicPrototype, classInfo()); + instance = new Instance(); + result->setObjectData(instance); + } else { + Q_ASSERT(result->isObject()); + if (result->classInfo() != classInfo()) { + result->destroyObjectData(); + result->setClassInfo(classInfo()); + instance = new Instance(); + result->setObjectData(instance); + } else { + instance = Instance::get(*result, classInfo()); + } + } + instance->value = value; +} + +QScriptValueImpl Variant::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QString result; + QScriptValueImpl value = method_valueOf(context, eng, classInfo); + if (value.isObject()) { + result = instance->value.toString(); + if (result.isEmpty()) { + result = QString::fromLatin1("QVariant(%0)") + .arg(QLatin1String(instance->value.typeName())); + } + } else { + result = value.toString(); + } + return QScriptValueImpl(eng, result); + } + return context->throwError(QScriptContext::TypeError, + QLatin1String("QVariant.prototype.toString")); +} + +QScriptValueImpl Variant::method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) +{ + if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { + QVariant v = instance->value; + switch (v.type ()) { + case QVariant::Invalid: + return eng->undefinedValue(); + case QVariant::String: + return (QScriptValueImpl(eng, v.toString())); + + case QVariant::Int: + return (QScriptValueImpl(v.toInt())); + + case QVariant::Bool: + return (QScriptValueImpl(v.toBool())); + + case QVariant::Double: + return (QScriptValueImpl(v.toDouble())); // ### hmmm + + case QVariant::Char: + return (QScriptValueImpl(v.toChar().unicode())); + + case QVariant::UInt: + return (QScriptValueImpl(v.toUInt())); + + default: + return context->thisObject(); + } // switch + } + return context->thisObject(); +} + +} } // namespace QScript::Ecma + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptextvariant_p.h b/src/script/qscriptextvariant_p.h new file mode 100644 index 0000000..cac17e5 --- /dev/null +++ b/src/script/qscriptextvariant_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** 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 QSCRIPTEXTVARIANT_P_H +#define QSCRIPTEXTVARIANT_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/QVariant> + +#include "qscriptecmacore_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SCRIPT + +namespace QScript { namespace Ext { + +class Instance; + +class Variant: public Ecma::Core +{ +public: + Variant(QScriptEnginePrivate *engine); + virtual ~Variant(); + + virtual void execute(QScriptContextPrivate *context); + + class Instance: public QScriptObjectData { + public: + Instance() {} + virtual ~Instance() {} + + static Instance *get(const QScriptValueImpl &object, + QScriptClassInfo *klass); + + public: + QVariant value; + }; + + inline Instance *get(const QScriptValueImpl &object) const + { return Instance::get(object, classInfo()); } + + void newVariant(QScriptValueImpl *result, const QVariant &value); + +protected: + static QScriptValueImpl method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); + static QScriptValueImpl method_valueOf(QScriptContextPrivate *context, QScriptEnginePrivate *eng, + QScriptClassInfo *classInfo); +}; + +} } // namespace QScript::Ext + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTEXTVARIANT_P_H diff --git a/src/script/qscriptfunction.cpp b/src/script/qscriptfunction.cpp new file mode 100644 index 0000000..55d5e61 --- /dev/null +++ b/src/script/qscriptfunction.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** 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 "qscriptfunction_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +QScriptFunction::~QScriptFunction() +{ +} + +QString QScriptFunction::toString(QScriptContextPrivate *) const +{ + QString result; + result += QLatin1String("function () { [native] }"); + return result; +} + +QString QScriptFunction::fileName() const +{ + return QString(); +} + +QString QScriptFunction::functionName() const +{ + return QString(); +} + +int QScriptFunction::startLineNumber() const +{ + return -1; +} + +int QScriptFunction::endLineNumber() const +{ + return -1; +} + +void QScriptFunction::mark(QScriptEnginePrivate *engine, int generation) +{ + for (int i = 0; i < formals.count(); ++i) + engine->markString(formals.at(i), generation); +} + +// public API function +void QScript::CFunction::execute(QScriptContextPrivate *context) +{ + QScriptEnginePrivate *eng_p = context->engine(); + + context->m_result = eng_p->undefinedValue(); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionEntry(context); +#endif + + QScriptContext *publicContext = QScriptContextPrivate::get(eng_p->currentContext()); + QScriptEngine *publicEngine = QScriptEnginePrivate::get(eng_p); + QScriptValueImpl result = eng_p->toImpl((*m_funPtr)(publicContext, publicEngine)); + if (result.isValid() && !eng_p->shouldAbort() + && (context->state() == QScriptContext::NormalState)) { + context->m_result = result; + } + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); +#endif +} + +QString QScript::CFunction::functionName() const +{ + return QString(); +} + +// internal API function +void QScript::C2Function::execute(QScriptContextPrivate *context) +{ + QScriptEnginePrivate *eng_p = context->engine(); + + bool blocked = eng_p->blockGC(true); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionEntry(context); +#endif + + context->m_result = (*m_funPtr)(context, eng_p, m_classInfo); + Q_ASSERT(context->m_result.isValid()); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); +#endif + + eng_p->blockGC(blocked); +} + +QString QScript::C2Function::functionName() const +{ + if (!m_name.isEmpty()) + return m_name; + return QString(); +} + +void QScript::C3Function::execute(QScriptContextPrivate *context) +{ + QScriptEnginePrivate *eng_p = context->engine(); + + context->m_result = eng_p->undefinedValue(); + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionEntry(context); +#endif + + QScriptContext *publicContext = QScriptContextPrivate::get(eng_p->currentContext()); + QScriptEngine *publicEngine = QScriptEnginePrivate::get(eng_p); + QScriptValueImpl result = eng_p->toImpl((*m_funPtr)(publicContext, publicEngine, m_arg)); + if (result.isValid() && !eng_p->shouldAbort()) + context->m_result = result; + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyFunctionExit(context); +#endif +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptfunction_p.h b/src/script/qscriptfunction_p.h new file mode 100644 index 0000000..ec79f32 --- /dev/null +++ b/src/script/qscriptfunction_p.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** 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 QSCRIPTFUNCTION_P_H +#define QSCRIPTFUNCTION_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 "qscriptobjectdata_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptglobals_p.h" +#include "qscriptnodepool_p.h" + +#include <QtCore/QList> + +#ifndef QT_NO_QOBJECT +# include <QtCore/QPointer> +# include <QtCore/QMetaMethod> +#endif + +QT_BEGIN_NAMESPACE + +class QScriptContext; +class QScriptContextPrivate; +class QScriptNameIdImpl; + +class QScriptFunction: public QScriptObjectData +{ +public: + enum Type { + Unknown, + Script, + C, + C2, + C3, + Qt, + QtProperty + }; + + QScriptFunction(int len = 0) + : length(len) + { } + virtual ~QScriptFunction(); + + virtual void execute(QScriptContextPrivate *context) = 0; + virtual QString toString(QScriptContextPrivate *context) const; + + virtual Type type() const { return Unknown; } + + // name of the file the function is defined in + virtual QString fileName() const; + + virtual QString functionName() const; + + virtual int startLineNumber() const; + + virtual int endLineNumber() const; + + virtual void mark(QScriptEnginePrivate *engine, int generation); + +public: // ### private + int length; + QList<QScriptNameIdImpl*> formals; +}; + +namespace QScript { + +// public API function +class CFunction: public QScriptFunction +{ +public: + CFunction(QScriptFunctionSignature funPtr, int length) + : QScriptFunction(length), m_funPtr(funPtr) + { } + + virtual ~CFunction() { } + + virtual void execute(QScriptContextPrivate *context); + + virtual Type type() const { return QScriptFunction::C; } + + virtual QString functionName() const; + +private: + QScriptFunctionSignature m_funPtr; +}; + +// internal API function +class C2Function: public QScriptFunction +{ +public: + C2Function(QScriptInternalFunctionSignature funPtr, int length, + QScriptClassInfo *classInfo, const QString &name) + : QScriptFunction(length), m_funPtr(funPtr), + m_classInfo(classInfo), m_name(name) + { } + + virtual ~C2Function() {} + + virtual void execute(QScriptContextPrivate *context); + + virtual Type type() const { return QScriptFunction::C2; } + + virtual QString functionName() const; + +private: + QScriptInternalFunctionSignature m_funPtr; + QScriptClassInfo *m_classInfo; + QString m_name; +}; + +class C3Function: public QScriptFunction +{ +public: + C3Function(QScriptFunctionWithArgSignature funPtr, void *arg, int length) + : QScriptFunction(length), m_funPtr(funPtr), m_arg(arg) + { } + + virtual ~C3Function() { } + + virtual void execute(QScriptContextPrivate *context); + + virtual Type type() const { return QScriptFunction::C3; } + +private: + QScriptFunctionWithArgSignature m_funPtr; + void *m_arg; +}; + +namespace AST { + class FunctionExpression; +} + +// implemented in qscriptcontext_p.cpp +class ScriptFunction: public QScriptFunction +{ +public: + ScriptFunction(AST::FunctionExpression *definition, NodePool *astPool): + m_definition(definition), m_astPool(astPool), m_compiledCode(0) {} + + virtual ~ScriptFunction() {} + + virtual void execute(QScriptContextPrivate *context); + + virtual QString toString(QScriptContextPrivate *context) const; + + virtual Type type() const + { return QScriptFunction::Script; } + + virtual QString fileName() const; + + virtual QString functionName() const; + + virtual int startLineNumber() const; + + virtual int endLineNumber() const; + +private: + AST::FunctionExpression *m_definition; + QExplicitlySharedDataPointer<NodePool> m_astPool; + Code *m_compiledCode; +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTFUNCTION_P_H diff --git a/src/script/qscriptgc_p.h b/src/script/qscriptgc_p.h new file mode 100644 index 0000000..6ded5bd --- /dev/null +++ b/src/script/qscriptgc_p.h @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** 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 QSCRIPTGC_P_H +#define QSCRIPTGC_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> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/QtDebug> +#include <new> + +#include "qscriptmemorypool_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + +class GCBlock +{ +public: + GCBlock *next; + + union { + int generation; + uint flags; + }; + +public: + inline GCBlock(GCBlock *n): + next(n), flags(0) {} + + inline void *data() + { return reinterpret_cast<char *>(this) + sizeof(GCBlock); } + + inline static GCBlock *get(void *ptr) + { + char *where = reinterpret_cast<char *>(ptr); + return reinterpret_cast<GCBlock *>(where - sizeof(GCBlock)); + } +}; + +template <typename _Tp> +class GCAlloc +{ +private: + int m_new_allocated_blocks; + int m_free_blocks; + int m_new_allocated_extra_bytes; + GCBlock *m_head; + GCBlock *m_current; + GCBlock *m_free; + bool m_blocked_gc; + bool m_force_gc; + bool m_sweeping; + MemoryPool pool; + _Tp trivial; + +public: + enum { MaxNumberOfBlocks = 1 << 14 }; + enum { MaxNumberOfExtraBytes = 0x800000 }; + +public: + inline GCAlloc(): + m_new_allocated_blocks(0), + m_free_blocks(0), + m_new_allocated_extra_bytes(0), + m_head(0), + m_current(0), + m_free(0), + m_blocked_gc(false), + m_force_gc(false), + m_sweeping(false) { + trivial.reset(); + } + + inline ~GCAlloc() { + } + + inline void destruct() { + m_sweeping = true; + GCBlock *blk = m_free; + + if (! blk) { + blk = m_head; + m_head = 0; + } + + while (blk) { + GCBlock *was = blk; + blk = blk->next; + + Q_ASSERT(was->data()); + _Tp *data = reinterpret_cast<_Tp*>(was->data()); + data->~_Tp(); + blk->~GCBlock(); + + if (! blk && m_head) { + blk = m_head; + m_head = 0; + } + } + m_sweeping = false; + } + + inline int newAllocatedBlocks() const { return m_new_allocated_blocks; } + inline int freeBlocks() const { return m_free_blocks; } + + inline _Tp *operator()(int generation) + { + GCBlock *previous = m_current; + void *where = 0; + + if (! m_free) { + Q_ASSERT (m_free_blocks == 0); + where = pool.allocate(sizeof(GCBlock) + sizeof(_Tp)); + ++m_new_allocated_blocks; + (void) new (reinterpret_cast<char*>(where) + sizeof(GCBlock)) _Tp(); + } else { + --m_free_blocks; + where = m_free; + m_free = m_free->next; + + if (! m_free) + m_force_gc = true; + } + + m_current = new (where) GCBlock(0); + + if (! previous) { + Q_ASSERT(! m_head); + m_head = m_current; + } else { + previous->next = m_current; + } + m_current->generation = generation; + + return reinterpret_cast<_Tp*> (m_current->data()); + } + + inline bool blocked() const + { + return m_blocked_gc; + } + + inline bool sweeping() const + { + return m_sweeping; + } + + inline bool blockGC(bool block) + { + bool was = m_blocked_gc; + m_blocked_gc = block; + return was; + } + + inline void requestGC() + { + m_force_gc = true; + } + + inline void adjustBytesAllocated(int bytes) + { m_new_allocated_extra_bytes += bytes; } + + inline bool poll() + { + if (m_blocked_gc || ! m_head) + return false; + + else if (m_force_gc) { + m_force_gc = false; + return true; + } + + else if (m_free && ! m_free->next) + return true; + + return (m_new_allocated_blocks >= MaxNumberOfBlocks) + || ((m_new_allocated_extra_bytes >= MaxNumberOfExtraBytes) + && (m_new_allocated_blocks > 0)); + } + + inline int generation(_Tp *ptr) const + { return GCBlock::get(ptr)->generation; } + + inline GCBlock *head() const + { return m_head; } + + void sweep(int generation) + { + m_sweeping = true; + GCBlock *blk = m_head; + m_current = 0; + + m_new_allocated_blocks = 0; + m_new_allocated_extra_bytes = 0; + + while (blk != 0) { + if (blk->generation != generation) { + if (m_current) + m_current->next = blk->next; + + GCBlock *tmp = blk; + blk = blk->next; // advance the pointer + + tmp->next = m_free; // prepend the node to the free list... + m_free = tmp; + ++m_free_blocks; + + if (m_free == m_head) + m_head = blk; + + _Tp *data = reinterpret_cast<_Tp *>(tmp->data()); + data->finalize(); + tmp->~GCBlock(); + } else { + m_current = blk; + blk = blk->next; + } + } + + if (! m_current) + m_head = m_current; + m_sweeping = false; + } + + class const_iterator + { + public: + typedef _Tp value_type; + typedef const _Tp *pointer; + typedef const _Tp &reference; + inline const_iterator() : i(0) { } + inline const_iterator(GCBlock *block) : i(block) { } + inline const_iterator(const const_iterator &o) + { i = reinterpret_cast<const const_iterator &>(o).i; } + + inline const _Tp *data() const { return reinterpret_cast<_Tp*>(i->data()); } + inline const _Tp &value() const { return *reinterpret_cast<_Tp*>(i->data()); } + inline const _Tp &operator*() const { return *reinterpret_cast<_Tp*>(i->data()); } + inline const _Tp *operator->() const { return reinterpret_cast<_Tp*>(i->data()); } + inline bool operator==(const const_iterator &o) const { return i == o.i; } + inline bool operator!=(const const_iterator &o) const { return i != o.i; } + + inline const_iterator &operator++() { + i = i->next; + return *this; + } + private: + GCBlock *i; + }; + friend class const_iterator; + + inline const_iterator constBegin() const { return const_iterator(m_head); } + inline const_iterator constEnd() const { return const_iterator(0); } + +private: + Q_DISABLE_COPY(GCAlloc) +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT +#endif // QSCRIPT_GC_H diff --git a/src/script/qscriptglobals_p.h b/src/script/qscriptglobals_p.h new file mode 100644 index 0000000..c4bec42 --- /dev/null +++ b/src/script/qscriptglobals_p.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 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 QSCRIPTGLOBALS_P_H +#define QSCRIPTGLOBALS_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> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +class QScriptValue; +class QScriptValueImpl; +class QScriptClassInfo; +class QScriptEngine; +class QScriptEnginePrivate; +class QScriptContext; +class QScriptContextPrivate; + +typedef QScriptValueImpl (*QScriptInternalFunctionSignature)(QScriptContextPrivate *, QScriptEnginePrivate *, QScriptClassInfo *); +typedef QScriptValue (*QScriptFunctionSignature)(QScriptContext *, QScriptEngine *); +typedef QScriptValue (*QScriptFunctionWithArgSignature)(QScriptContext *, QScriptEngine *, void *); + +namespace QScript { + +enum Type { + InvalidType, + // standard types + UndefinedType, + NullType, + BooleanType, + StringType, + NumberType, + ObjectType, + // internal types + IntegerType, + ReferenceType, + PointerType, + LazyStringType +}; + +enum AccessMode { + Read = 0x01, + Write = 0x02, + ReadWrite = 0x03 +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTGLOBALS_P_H diff --git a/src/script/qscriptgrammar.cpp b/src/script/qscriptgrammar.cpp new file mode 100644 index 0000000..8b8a05d --- /dev/null +++ b/src/script/qscriptgrammar.cpp @@ -0,0 +1,975 @@ +// 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 "qscriptgrammar_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +const char *const QScriptGrammar::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", "switch", "this", "throw", "~", + "try", "typeof", "var", "void", "while", "with", "^", "^=", "null", "true", + "false", "const", "debugger", "reserved word", +#ifndef QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO +"Program", "PrimaryExpression", "ElisionOpt", "ElementList", "PropertyNameAndValueListOpt", "PropertyNameAndValueList", + "Expression", "AssignmentExpression", "Elision", "PropertyName", "ReservedIdentifier", "PropertyIdentifier", "MemberExpression", "FunctionExpression", "Arguments", "NewExpression", + "CallExpression", "ArgumentList", "LeftHandSideExpression", "PostfixExpression", "UnaryExpression", "MultiplicativeExpression", "AdditiveExpression", "ShiftExpression", "RelationalExpression", "RelationalExpressionNotIn", + "EqualityExpression", "EqualityExpressionNotIn", "BitwiseANDExpression", "BitwiseANDExpressionNotIn", "BitwiseXORExpression", "BitwiseXORExpressionNotIn", "BitwiseORExpression", "BitwiseORExpressionNotIn", "LogicalANDExpression", "LogicalANDExpressionNotIn", + "LogicalORExpression", "LogicalORExpressionNotIn", "ConditionalExpression", "ConditionalExpressionNotIn", "AssignmentExpressionNotIn", "AssignmentOperator", "ExpressionOpt", "ExpressionNotIn", "ExpressionNotInOpt", "Statement", + "Block", "VariableStatement", "EmptyStatement", "ExpressionStatement", "IfStatement", "IterationStatement", "ContinueStatement", "BreakStatement", "ReturnStatement", "WithStatement", + "LabelledStatement", "SwitchStatement", "ThrowStatement", "TryStatement", "DebuggerStatement", "StatementListOpt", "StatementList", "VariableDeclarationKind", "VariableDeclarationList", "VariableDeclaration", + "VariableDeclarationListNotIn", "VariableDeclarationNotIn", "InitialiserOpt", "InitialiserNotInOpt", "Initialiser", "InitialiserNotIn", "CaseBlock", "CaseClausesOpt", "DefaultClause", "CaseClauses", + "CaseClause", "Catch", "Finally", "FunctionDeclaration", "FormalParameterListOpt", "FunctionBodyOpt", "IdentifierOpt", "FormalParameterList", "FunctionBody", "SourceElements", + "SourceElement", "$accept" +#endif // QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO +}; + +const int QScriptGrammar::lhs [] = { + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 87, 87, 92, 92, 86, + 86, 89, 89, 93, 93, 93, 93, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, + 96, 96, 96, 96, 96, 99, 99, 100, 100, 100, + 100, 98, 98, 101, 101, 102, 102, 103, 103, 103, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 105, 105, 105, 105, 106, 106, 106, 107, 107, 107, + 107, 108, 108, 108, 108, 108, 108, 108, 109, 109, + 109, 109, 109, 109, 110, 110, 110, 110, 110, 111, + 111, 111, 111, 111, 112, 112, 113, 113, 114, 114, + 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, + 120, 120, 121, 121, 122, 122, 123, 123, 91, 91, + 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 90, 90, 126, 126, 127, 127, + 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 130, 146, 146, + 145, 145, 131, 131, 147, 147, 148, 148, 150, 150, + 149, 151, 154, 152, 152, 155, 153, 153, 132, 133, + 133, 134, 134, 135, 135, 135, 135, 135, 135, 135, + 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, + 139, 141, 156, 156, 159, 159, 157, 157, 160, 158, + 140, 142, 142, 143, 143, 143, 161, 162, 144, 144, + 163, 97, 167, 167, 164, 164, 165, 165, 168, 84, + 169, 169, 170, 170, 166, 166, 88, 88, 171}; + +const int QScriptGrammar:: rhs[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, + 3, 5, 3, 4, 3, 2, 4, 1, 2, 0, + 1, 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, 4, 3, 3, 1, 2, 2, 2, 4, + 3, 2, 3, 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, 4, 5, 2, 2, 2, + 8, 8, 1, 3, 0, 1, 0, 1, 1, 1, + 1, 2, 1, 1, 0, 1, 0, 1, 2}; + + +#ifndef QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO +const int QScriptGrammar::rule_info [] = { + 85, 67 + , 85, 29 + , 85, 78 + , 85, 79 + , 85, 80 + , 85, 47 + , 85, 65 + , 85, 12 + , 85, 13 + , 85, 34, 86, 56 + , 85, 34, 87, 56 + , 85, 34, 87, 8, 86, 56 + , 85, 33, 88, 55 + , 85, 33, 89, 8, 55 + , 85, 36, 90, 60 + , 87, 86, 91 + , 87, 87, 8, 86, 91 + , 92, 8 + , 92, 92, 8 + , 86 + , 86, 92 + , 89, 93, 7, 91 + , 89, 89, 8, 93, 7, 91 + , 93, 29 + , 93, 65 + , 93, 47 + , 93, 94 + , 94, 4 + , 94, 5 + , 94, 6 + , 94, 9 + , 94, 10 + , 94, 11 + , 94, 14 + , 94, 16 + , 94, 80 + , 94, 20 + , 94, 21 + , 94, 22 + , 94, 30 + , 94, 31 + , 94, 32 + , 94, 43 + , 94, 78 + , 94, 59 + , 94, 66 + , 94, 67 + , 94, 68 + , 94, 79 + , 94, 70 + , 94, 71 + , 94, 72 + , 94, 73 + , 94, 74 + , 94, 81 + , 94, 82 + , 94, 83 + , 94, 75 + , 95, 29 + , 95, 94 + , 96, 85 + , 96, 97 + , 96, 96, 34, 90, 56 + , 96, 96, 15, 95 + , 96, 43, 96, 98 + , 99, 96 + , 99, 43, 99 + , 100, 96, 98 + , 100, 100, 98 + , 100, 100, 34, 90, 56 + , 100, 100, 15, 95 + , 98, 36, 60 + , 98, 36, 101, 60 + , 101, 91 + , 101, 101, 8, 91 + , 102, 99 + , 102, 100 + , 103, 102 + , 103, 102, 53 + , 103, 102, 42 + , 104, 103 + , 104, 11, 104 + , 104, 73, 104 + , 104, 71, 104 + , 104, 53, 104 + , 104, 42, 104 + , 104, 51, 104 + , 104, 40, 104 + , 104, 69, 104 + , 104, 44, 104 + , 105, 104 + , 105, 105, 63, 104 + , 105, 105, 12, 104 + , 105, 105, 57, 104 + , 106, 105 + , 106, 106, 51, 105 + , 106, 106, 40, 105 + , 107, 106 + , 107, 107, 38, 106 + , 107, 107, 25, 106 + , 107, 107, 27, 106 + , 108, 107 + , 108, 108, 37, 107 + , 108, 108, 24, 107 + , 108, 108, 35, 107 + , 108, 108, 23, 107 + , 108, 108, 32, 107 + , 108, 108, 31, 107 + , 109, 107 + , 109, 109, 37, 107 + , 109, 109, 24, 107 + , 109, 109, 35, 107 + , 109, 109, 23, 107 + , 109, 109, 32, 107 + , 110, 108 + , 110, 110, 18, 108 + , 110, 110, 45, 108 + , 110, 110, 19, 108 + , 110, 110, 46, 108 + , 111, 109 + , 111, 111, 18, 109 + , 111, 111, 45, 109 + , 111, 111, 19, 109 + , 111, 111, 46, 109 + , 112, 110 + , 112, 112, 1, 110 + , 113, 111 + , 113, 113, 1, 111 + , 114, 112 + , 114, 114, 76, 112 + , 115, 113 + , 115, 115, 76, 113 + , 116, 114 + , 116, 116, 48, 114 + , 117, 115 + , 117, 117, 48, 115 + , 118, 116 + , 118, 118, 2, 116 + , 119, 117 + , 119, 119, 2, 117 + , 120, 118 + , 120, 120, 50, 118 + , 121, 119 + , 121, 121, 50, 119 + , 122, 120 + , 122, 120, 54, 91, 7, 91 + , 123, 121 + , 123, 121, 54, 124, 7, 124 + , 91, 122 + , 91, 102, 125, 91 + , 124, 123 + , 124, 102, 125, 124 + , 125, 17 + , 125, 64 + , 125, 13 + , 125, 58 + , 125, 52 + , 125, 41 + , 125, 39 + , 125, 26 + , 125, 28 + , 125, 3 + , 125, 77 + , 125, 49 + , 90, 91 + , 90, 90, 8, 91 + , 126 + , 126, 90 + , 127, 124 + , 127, 127, 8, 124 + , 128 + , 128, 127 + , 129, 130 + , 129, 131 + , 129, 132 + , 129, 133 + , 129, 134 + , 129, 135 + , 129, 136 + , 129, 137 + , 129, 138 + , 129, 139 + , 129, 140 + , 129, 141 + , 129, 142 + , 129, 143 + , 129, 144 + , 130, 33, 145, 55 + , 146, 129 + , 146, 146, 129 + , 145 + , 145, 146 + , 131, 147, 148, 62 + , 131, 147, 148, 61 + , 147, 81 + , 147, 72 + , 148, 149 + , 148, 148, 8, 149 + , 150, 151 + , 150, 150, 8, 151 + , 149, 29, 152 + , 151, 29, 153 + , 154, 17, 91 + , 152 + , 152, 154 + , 155, 17, 124 + , 153 + , 153, 155 + , 132, 61 + , 133, 90, 62 + , 133, 90, 61 + , 134, 30, 36, 90, 60, 129, 16, 129 + , 134, 30, 36, 90, 60, 129 + , 135, 14, 129, 74, 36, 90, 60, 62 + , 135, 14, 129, 74, 36, 90, 60, 61 + , 135, 74, 36, 90, 60, 129 + , 135, 21, 36, 128, 61, 126, 61, 126, 60, 129 + , 135, 21, 36, 72, 150, 61, 126, 61, 126, 60, 129 + , 135, 21, 36, 102, 31, 90, 60, 129 + , 135, 21, 36, 72, 151, 31, 90, 60, 129 + , 136, 9, 62 + , 136, 9, 61 + , 136, 9, 29, 62 + , 136, 9, 29, 61 + , 137, 4, 62 + , 137, 4, 61 + , 137, 4, 29, 62 + , 137, 4, 29, 61 + , 138, 59, 126, 62 + , 138, 59, 126, 61 + , 139, 75, 36, 90, 60, 129 + , 141, 66, 36, 90, 60, 156 + , 156, 33, 157, 55 + , 156, 33, 157, 158, 157, 55 + , 159, 160 + , 159, 159, 160 + , 157 + , 157, 159 + , 160, 5, 90, 7, 145 + , 158, 10, 7, 145 + , 140, 29, 7, 129 + , 142, 68, 90, 62 + , 142, 68, 90, 61 + , 143, 70, 130, 161 + , 143, 70, 130, 162 + , 143, 70, 130, 161, 162 + , 161, 6, 36, 29, 60, 130 + , 162, 20, 130 + , 144, 82, 62 + , 144, 82, 61 + , 163, 22, 29, 36, 164, 60, 33, 165, 55 + , 97, 22, 166, 36, 164, 60, 33, 165, 55 + , 167, 29 + , 167, 167, 8, 29 + , 164 + , 164, 167 + , 165 + , 165, 168 + , 168, 169 + , 84, 169 + , 169, 170 + , 169, 169, 170 + , 170, 129 + , 170, 163 + , 166 + , 166, 29 + , 88 + , 88, 89 + , 171, 84, 0}; + +const int QScriptGrammar::rule_index [] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, + 22, 26, 32, 36, 41, 45, 48, 53, 55, 58, + 59, 61, 65, 71, 73, 75, 77, 79, 81, 83, + 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, + 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, + 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 154, 158, 162, 164, 167, 170, 173, + 178, 182, 185, 189, 191, 195, 197, 199, 201, 204, + 207, 209, 212, 215, 218, 221, 224, 227, 230, 233, + 236, 238, 242, 246, 250, 252, 256, 260, 262, 266, + 270, 274, 276, 280, 284, 288, 292, 296, 300, 302, + 306, 310, 314, 318, 322, 324, 328, 332, 336, 340, + 342, 346, 350, 354, 358, 360, 364, 366, 370, 372, + 376, 378, 382, 384, 388, 390, 394, 396, 400, 402, + 406, 408, 412, 414, 418, 420, 426, 428, 434, 436, + 440, 442, 446, 448, 450, 452, 454, 456, 458, 460, + 462, 464, 466, 468, 470, 472, 476, 477, 479, 481, + 485, 486, 488, 490, 492, 494, 496, 498, 500, 502, + 504, 506, 508, 510, 512, 514, 516, 518, 522, 524, + 527, 528, 530, 534, 538, 540, 542, 544, 548, 550, + 554, 557, 560, 563, 564, 566, 569, 570, 572, 574, + 577, 580, 588, 594, 602, 610, 616, 626, 637, 645, + 654, 657, 660, 664, 668, 671, 674, 678, 682, 686, + 690, 696, 702, 706, 712, 714, 717, 718, 720, 725, + 729, 733, 737, 741, 745, 749, 754, 760, 763, 766, + 769, 778, 787, 789, 793, 794, 796, 797, 799, 801, + 803, 805, 808, 810, 812, 813, 815, 816, 818}; +#endif // QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO + +const int QScriptGrammar::action_default [] = { + 0, 98, 165, 129, 137, 133, 173, 180, 77, 149, + 179, 187, 175, 125, 0, 176, 264, 62, 177, 178, + 183, 78, 141, 145, 66, 95, 76, 81, 61, 0, + 115, 181, 102, 261, 260, 263, 184, 0, 195, 0, + 0, 0, 8, 9, 0, 5, 0, 265, 2, 0, + 267, 20, 0, 0, 0, 0, 0, 3, 6, 0, + 0, 167, 209, 7, 0, 1, 0, 0, 4, 0, + 0, 196, 0, 0, 0, 185, 186, 91, 0, 174, + 182, 0, 0, 78, 97, 265, 2, 267, 80, 79, + 0, 0, 0, 93, 94, 92, 0, 266, 255, 256, + 0, 253, 0, 254, 0, 257, 258, 0, 259, 252, + 262, 0, 268, 0, 27, 28, 29, 30, 55, 31, + 56, 32, 33, 34, 35, 36, 37, 38, 39, 24, + 40, 41, 42, 43, 44, 26, 57, 45, 25, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 58, 0, + 22, 0, 0, 14, 0, 23, 13, 96, 0, 126, + 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, + 0, 106, 0, 0, 0, 100, 101, 99, 104, 108, + 107, 105, 103, 118, 117, 119, 0, 134, 0, 130, + 69, 0, 0, 0, 71, 60, 59, 0, 0, 70, + 166, 0, 74, 72, 0, 73, 75, 210, 211, 0, + 162, 155, 153, 160, 161, 159, 158, 164, 157, 156, + 154, 163, 150, 0, 138, 0, 0, 142, 0, 0, + 146, 68, 0, 0, 64, 0, 63, 269, 225, 0, + 226, 227, 228, 221, 0, 222, 223, 224, 249, 250, + 82, 0, 0, 0, 0, 0, 214, 215, 171, 169, + 131, 139, 135, 151, 127, 172, 0, 78, 143, 147, + 120, 109, 0, 0, 128, 0, 0, 0, 0, 121, + 0, 0, 0, 0, 0, 113, 111, 114, 112, 110, + 123, 122, 124, 0, 136, 0, 132, 0, 170, 78, + 0, 152, 167, 168, 0, 167, 0, 0, 217, 0, + 0, 0, 219, 0, 140, 0, 0, 144, 0, 0, + 148, 207, 0, 199, 208, 202, 0, 206, 0, 167, + 200, 0, 167, 0, 0, 218, 0, 0, 0, 220, + 266, 255, 0, 0, 257, 0, 251, 0, 241, 0, + 0, 0, 213, 0, 212, 189, 192, 0, 28, 55, + 31, 56, 33, 34, 5, 38, 39, 2, 40, 43, + 3, 6, 167, 7, 46, 1, 48, 4, 50, 51, + 52, 53, 54, 58, 190, 188, 66, 67, 65, 0, + 229, 230, 0, 0, 0, 232, 237, 235, 238, 0, + 0, 236, 237, 0, 233, 0, 234, 191, 240, 0, + 191, 239, 0, 242, 243, 0, 191, 244, 245, 0, + 0, 246, 0, 0, 0, 247, 248, 84, 83, 0, + 0, 0, 216, 0, 0, 0, 231, 0, 21, 0, + 18, 20, 11, 0, 17, 12, 19, 16, 10, 0, + 15, 88, 86, 90, 87, 85, 89, 204, 197, 0, + 205, 201, 0, 203, 193, 0, 194, 198}; + +const int QScriptGrammar::goto_default [] = { + 29, 28, 439, 437, 113, 112, 14, 2, 438, 111, + 114, 194, 24, 17, 190, 26, 8, 201, 21, 27, + 77, 25, 1, 32, 30, 270, 13, 264, 3, 260, + 5, 262, 4, 261, 22, 268, 23, 269, 9, 263, + 259, 300, 389, 265, 266, 35, 6, 79, 12, 15, + 18, 19, 10, 7, 31, 80, 20, 36, 75, 76, + 11, 357, 356, 78, 459, 458, 322, 323, 461, 325, + 460, 324, 395, 399, 402, 398, 397, 417, 418, 16, + 100, 107, 96, 99, 106, 108, 33, 0}; + +const int QScriptGrammar::action_index [] = { + 1318, 79, -84, 56, 39, -17, -84, -84, 169, -84, + -84, -84, -84, 216, 149, -84, -84, -84, -84, -84, + -84, 475, 68, 100, 180, 184, -84, -84, -84, 99, + 303, -84, 193, -84, 1318, -84, -84, 160, -84, 194, + 85, 629, -84, -84, 1398, -84, -5, 32, 42, 26, + 1478, 37, 629, 629, 629, 366, 629, -84, -84, 629, + 629, 629, -84, -84, 55, -84, 629, 629, -84, 61, + 629, -84, 629, 52, 38, -84, -84, -84, 49, -84, + -84, 629, 629, 64, 182, 48, -84, 1158, -84, -84, + 629, 629, 629, -84, -84, -84, 36, -84, 44, 50, + 40, -84, 57, -84, -26, 1318, -84, -53, 1318, -84, + -84, 18, 7, 43, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, 629, + -84, 1238, 23, -84, 629, -84, -84, 189, 629, 214, + 629, 629, 629, 629, 293, 629, 629, 629, 629, 629, + 629, 143, 629, 629, 629, 65, 83, 69, 153, 152, + 144, 161, 175, 273, 283, 318, 629, 62, 629, 74, + -84, 1078, 629, 702, -84, -84, -84, 84, 629, -84, + -84, 88, -84, -84, 629, -84, -84, -84, -84, 629, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, 629, 45, 629, 629, 63, 53, 629, + -84, -84, 1078, 629, -84, 102, -84, -84, -84, 90, + -84, -84, -84, -84, 101, -84, -84, -84, -84, -84, + -84, 51, 59, 629, 89, 94, -84, -84, 775, -84, + 13, -36, -65, -84, 230, 2, -52, 556, 14, 133, + 248, 147, -12, 629, 224, 629, 629, 629, 629, 258, + 629, 629, 629, 629, 629, 199, 261, 261, 261, 181, + 242, 322, 322, 629, -55, 629, 5, 629, -84, 334, + 629, -84, 629, 15, -61, 629, -59, 1398, -84, 629, + 73, 1398, -84, 629, 20, 629, 629, 24, 41, 629, + -84, 54, 82, 19, -84, -84, 629, -84, 17, 629, + -84, -10, 629, -7, 1398, -84, 629, 77, 1398, -84, + 31, 27, -13, 10, 1318, -22, -84, 1398, -84, 629, + 76, 1398, 11, 1398, -84, -84, 1398, -15, 136, 9, + 131, 80, 629, 1398, 28, 6, 78, 47, 8, 394, + 34, 30, 925, 29, 3, 21, 629, 25, 1, 629, + 35, 629, 33, 16, -84, -84, 202, -84, -84, 67, + -84, -84, 629, 72, -4, -84, -2, -84, -1, 66, + 629, -84, 0, 12, -84, -37, -84, 1398, -84, 95, + 1398, -84, 105, -84, -84, 98, 1398, 4, -84, -14, + -25, -84, -16, -40, 22, -84, -84, -84, -84, 629, + 93, 1398, -84, 629, 104, 1398, -84, 103, 71, 848, + -84, 58, -84, 998, -84, -84, -84, -84, -84, 75, + -84, -84, -84, -84, -84, -84, -84, 46, -84, 114, + -84, -84, 629, -84, -84, 60, -84, -84, + + -50, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -28, -88, -88, -10, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -64, -88, -88, -88, -88, -88, + -88, 131, -88, -88, -22, -88, -88, -88, -88, -88, + -27, -88, 13, 94, 88, 98, 89, -88, -88, 106, + 107, -4, -88, -88, -88, -88, 68, 111, -88, -31, + 85, -88, 110, -88, -88, -88, -88, -88, -88, -88, + -88, 127, 122, -88, -88, -88, -88, -88, -88, -88, + 97, 100, 101, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -48, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, 32, + -88, 33, -88, -88, 34, -88, -88, -88, 46, -88, + 60, 74, 76, 77, -88, 73, 67, 70, 81, 58, + 79, -88, 37, 51, 65, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, 59, -88, 43, -88, + -88, 42, 48, 20, -88, -88, -88, -88, 41, -88, + -88, -88, -88, -88, 40, -88, -88, -88, -88, 49, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, 50, -88, 45, 26, -88, -88, 24, + -88, -88, 56, 22, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, 31, -88, -88, -88, -88, 57, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, 158, -88, 146, 142, 150, 154, -88, + 47, 138, 115, 135, 132, -88, -88, -88, -88, -88, + -88, -88, -88, 168, -88, 172, -88, 160, -88, -88, + 180, -88, 220, -88, -88, 117, -88, -2, -88, 38, + -88, -5, -88, 174, -88, 170, 166, -88, -88, 164, + -88, -88, -88, -88, -88, -88, 190, -88, -37, 80, + -88, -88, 105, -88, -13, -88, 28, -88, 0, -88, + -88, -44, -88, -88, -52, -88, -88, 12, -88, 52, + -88, 1, -88, 4, -88, -88, 6, -88, -88, -88, + -88, -88, 119, 8, -88, -88, -88, -88, -88, 120, + -88, -88, 44, -88, -88, -88, 68, -88, -45, 116, + -88, 124, -88, -88, -88, -88, -14, -88, -88, -88, + -88, -88, -1, -88, -88, -88, -88, -88, -55, -88, + 11, -88, -53, -88, -88, -88, -88, 109, -88, -88, + 96, -88, -88, -88, -88, -88, -19, -54, -88, -88, + -21, -88, -88, -88, -43, -88, -88, -88, -88, 10, + -88, -38, -88, 2, -88, -39, -88, -88, -88, 3, + -88, 9, -88, 7, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, 5, -88, -88, -56, -88, -88}; + +const int QScriptGrammar::action_info [] = { + 305, 307, 109, 400, 400, 400, 273, 105, 416, 302, + 297, 295, 293, 423, 273, 151, 313, 321, 406, 407, + 424, 295, 422, 198, 420, 149, 313, 353, -47, 396, + 154, 258, -49, 346, 416, -36, -25, -26, -195, 392, + 385, -44, 258, 344, 349, 440, 321, 343, 319, 347, + 336, 332, 433, 334, 347, 416, 101, 158, 102, 188, + 229, 340, 349, 462, -196, 223, 440, 341, 293, 429, + 223, 326, 98, 101, 433, 158, 403, 97, 457, 446, + 198, 198, 0, 198, 198, 198, 103, 186, 429, 457, + 328, 392, 198, 186, 416, 253, 204, 198, 156, 237, + 104, 198, 410, 198, 419, 81, 88, 97, 0, 81, + 198, 441, 198, 198, -265, 0, 82, 89, 420, 81, + 82, 404, 465, 81, 0, 252, 0, 0, 391, 390, + 82, 0, 394, 311, 82, 450, 351, 338, 188, 0, + 199, 249, 248, 329, 0, 0, 249, 248, 205, 255, + 225, 242, 241, 431, 226, 257, 256, 198, 236, 442, + 244, 0, 247, 246, 435, 239, 414, 413, 172, 172, + 173, 173, 172, 0, 173, 466, 464, 172, 172, 173, + 173, 174, 174, 315, 191, 174, 172, 316, 173, 239, + 174, 174, 245, 243, 90, 232, 90, 240, 238, 174, + 172, 90, 173, 192, 0, 193, 172, 0, 173, 0, + 208, 207, 0, 174, 233, 0, 193, 232, 172, 174, + 173, 240, 238, 244, 172, 0, 173, 0, 0, 0, + 0, 174, 160, 161, 160, 161, 233, 174, 193, 91, + 0, 91, 275, 276, 0, 92, 91, 92, 275, 276, + 0, 0, 92, 0, 0, 245, 243, 0, 0, 162, + 163, 162, 163, 0, 0, 280, 281, 0, 0, 277, + 278, 280, 281, 0, 282, 277, 278, 283, 0, 284, + 282, 280, 281, 283, 0, 284, 172, 0, 173, 0, + 282, 0, 0, 283, 0, 284, 165, 166, 0, 174, + 0, 0, 0, 0, 167, 168, 165, 166, 169, 0, + 170, 0, 0, 0, 167, 168, 165, 166, 169, 0, + 170, 0, 0, 0, 167, 168, 165, 166, 169, 0, + 170, 0, 0, 0, 167, 168, 0, 210, 169, 0, + 170, 165, 166, 0, 0, 280, 281, 211, 0, 167, + 168, 212, 0, 169, 282, 170, 0, 283, 0, 284, + 213, 0, 214, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 215, 0, 216, 88, 0, 42, 43, + 0, 0, 0, 217, 0, 0, 218, 89, 85, 0, + 0, 0, 219, 0, 0, 86, 0, 0, 220, 87, + 51, 0, 52, 0, 0, 0, 42, 43, 0, 55, + 0, 221, 0, 58, 0, 0, 85, 0, 0, 0, + 0, 0, 0, 86, 0, 0, 0, 87, 51, 0, + 52, 63, 0, 65, 0, 0, 0, 55, 0, 0, + 0, 58, 0, 0, 57, 68, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, + 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 57, 68, 45, 0, 0, 0, 210, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 211, 0, + 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, + 0, 213, 0, 214, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 215, 0, 216, 88, 0, 0, + 0, 0, 0, 0, 217, 0, 0, 218, 89, 0, + 0, 0, 0, 219, 0, 0, 0, 0, 0, 220, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 221, 0, 0, 0, 0, 0, 0, 210, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 211, + 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, + 0, 0, 213, 0, 214, 0, 0, 309, 0, 0, + 0, 0, 0, 0, 0, 215, 0, 216, 88, 0, + 0, 0, 0, 0, 0, 217, 0, 0, 218, 89, + 0, 0, 0, 0, 219, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 221, 0, 0, 0, 0, 0, 0, + 41, 42, 43, 0, 0, 0, 0, 0, 0, 0, + 0, 85, 0, 0, 0, 0, 0, 0, 86, 0, + 0, 0, 87, 51, 0, 52, 0, 0, 0, 53, + 0, 54, 55, 56, 0, 0, 58, 0, 0, 0, + 59, 0, 60, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 63, 0, 65, 0, 67, 0, + 70, 0, 72, 0, 0, 0, 0, 57, 68, 45, + 0, 0, 0, 41, 42, 43, 0, 0, 0, 0, + 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, + 0, 86, 0, 0, 0, 87, 51, 0, 52, 0, + 0, 0, 53, 0, 54, 55, 56, 0, 0, 58, + 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, + 0, 0, 203, 0, 0, 0, 0, 63, 0, 65, + 0, 67, 0, 70, 0, 72, 0, 0, 0, 0, + 57, 68, 45, 0, 0, 0, 41, 42, 43, 0, + 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, + 0, 0, 0, 0, 86, 0, 0, 0, 87, 51, + 0, 52, 0, 0, 0, 53, 0, 54, 55, 56, + 0, 0, 58, 0, 0, 0, 59, 0, 60, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 63, 0, 65, 0, 67, 0, 70, 272, 72, 0, + 0, 0, 0, 57, 68, 45, 0, 0, 0, 41, + 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 0, 0, 0, 0, 0, 86, 0, 0, + 0, 87, 51, 0, 52, 0, 0, 0, 53, 0, + 54, 55, 56, 0, 0, 58, 0, 0, 0, 59, + 0, 60, 0, 0, 448, 0, 0, 0, 0, 0, + 0, 0, 0, 63, 0, 65, 0, 67, 0, 70, + 0, 72, 0, 0, 0, 0, 57, 68, 45, 0, + 0, 0, -45, 0, 0, 0, 41, 42, 43, 0, + 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, + 0, 0, 0, 0, 86, 0, 0, 0, 87, 51, + 0, 52, 0, 0, 0, 53, 0, 54, 55, 56, + 0, 0, 58, 0, 0, 0, 59, 0, 60, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 63, 0, 65, 0, 67, 0, 70, 0, 72, 0, + 0, 0, 0, 57, 68, 45, 0, 0, 0, 41, + 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 0, 0, 0, 0, 0, 86, 0, 0, + 0, 87, 51, 0, 52, 0, 0, 0, 53, 0, + 54, 55, 56, 0, 0, 58, 0, 0, 0, 59, + 0, 60, 0, 0, 445, 0, 0, 0, 0, 0, + 0, 0, 0, 63, 0, 65, 0, 67, 0, 70, + 0, 72, 0, 0, 0, 0, 57, 68, 45, 0, + 0, 0, 115, 116, 117, 0, 0, 119, 121, 122, + 0, 0, 123, 0, 124, 0, 0, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 196, 130, 131, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 137, 0, 0, + 0, 0, 0, 0, 139, 140, 141, 0, 143, 144, + 145, 146, 147, 148, 0, 0, 134, 142, 125, 118, + 120, 136, 115, 116, 117, 0, 0, 119, 121, 122, + 0, 0, 123, 0, 124, 0, 0, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 129, 130, 131, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 133, 0, 0, 0, 135, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 137, 0, 0, + 0, 0, 0, 138, 139, 140, 141, 0, 143, 144, + 145, 146, 147, 148, 0, 0, 134, 142, 125, 118, + 120, 136, 115, 116, 117, 0, 0, 119, 121, 122, + 0, 0, 123, 0, 124, 0, 0, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 129, 130, 131, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 133, 0, 0, 0, 135, 0, 0, 0, 0, + 0, 0, 0, 153, 0, 0, 0, 137, 0, 0, + 0, 0, 0, 138, 139, 140, 141, 0, 143, 144, + 145, 146, 147, 148, 0, 0, 134, 142, 125, 118, + 120, 136, 37, 0, 0, 0, 0, 39, 0, 41, + 42, 43, 44, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 0, 50, 51, 0, 52, 0, 0, 0, 53, 0, + 54, 55, 56, 0, 0, 58, 0, 0, 0, 59, + 0, 60, 0, 0, 0, 0, 0, 61, 0, 62, + 0, 0, 0, 63, 64, 65, 66, 67, 69, 70, + 71, 72, 73, 74, 0, 0, 57, 68, 45, 38, + 40, 0, 37, 0, 0, 0, 0, 39, 0, 41, + 42, 43, 44, 0, 0, 0, 0, 0, 0, 46, + 85, 0, 0, 0, 0, 0, 0, 48, 49, 0, + 0, 50, 51, 0, 52, 0, 0, 0, 53, 0, + 54, 55, 56, 0, 0, 58, 0, 0, 0, 59, + 0, 60, 0, 0, 0, 0, 0, 61, 0, 62, + 0, 0, 0, 63, 64, 65, 66, 67, 69, 70, + 71, 72, 73, 74, 0, 0, 57, 68, 45, 38, + 40, 0, 358, 116, 117, 0, 0, 360, 121, 362, + 42, 43, 363, 0, 124, 0, 0, 0, 126, 365, + 366, 0, 0, 0, 0, 0, 0, 367, 368, 131, + 132, 50, 51, 0, 52, 0, 0, 0, 53, 0, + 54, 369, 56, 0, 0, 371, 0, 0, 0, 59, + 0, 60, 0, -191, 0, 0, 0, 372, 0, 62, + 0, 0, 0, 373, 374, 375, 376, 67, 378, 379, + 380, 381, 382, 383, 0, 0, 370, 377, 364, 359, + 361, 136, + + 388, 415, 303, 425, 231, 393, 436, 432, 434, 467, + 447, 443, 463, 209, 444, 415, 430, 409, 355, 449, + 405, 401, 110, 251, 421, 426, 355, 202, 235, 345, + 330, 230, 335, 228, 337, 34, 342, 254, 110, 150, + 312, 155, 152, 308, 310, 339, 352, 206, 200, 354, + 303, 384, 195, 251, 197, 83, 222, 348, 350, 175, + 0, 83, 0, 83, 83, 83, 195, 234, 83, 83, + 285, 189, 159, 176, 412, 267, 83, 83, 83, 227, + 271, 181, 224, 83, 164, 83, 303, 177, 83, 187, + 178, 83, 83, 179, 83, 83, 171, 83, 183, 83, + 184, 185, 182, 83, 180, 427, 83, 83, 452, 453, + 386, 303, 83, 387, 451, 83, 0, 93, 83, 83, + 94, 95, 331, 303, 83, 83, 454, 455, 83, 83, + 428, 456, 386, 83, 83, 387, 427, 83, 287, 250, + 83, 355, 83, 157, 428, 83, 0, 333, 84, 83, + 83, 250, 0, 83, 355, 289, 83, 411, 288, 306, + 83, 286, 0, 0, 83, 271, 0, 290, 83, 271, + 408, 279, 83, 271, 0, 291, 83, 271, 299, 292, + 0, 271, 299, 271, 299, 274, 83, 271, 83, 271, + 83, 271, 83, 271, 0, 271, 0, 271, 299, 294, + 298, 296, 0, 271, 320, 317, 318, 314, 299, 0, + 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, + 301, 0, 0, 0, 0, 0, 303, 0, 0, 0, + 327, 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, 304, 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 QScriptGrammar::action_check [] = { + 61, 60, 55, 5, 5, 5, 1, 33, 33, 61, + 8, 76, 48, 29, 1, 8, 2, 29, 55, 7, + 60, 76, 36, 8, 20, 7, 2, 16, 7, 33, + 7, 36, 7, 55, 33, 7, 7, 7, 29, 36, + 55, 7, 36, 33, 36, 8, 29, 60, 7, 7, + 31, 61, 36, 60, 7, 33, 29, 1, 8, 76, + 7, 29, 36, 17, 29, 2, 8, 36, 48, 36, + 2, 17, 36, 29, 36, 1, 10, 29, 29, 8, + 8, 8, -1, 8, 8, 8, 29, 48, 36, 29, + 8, 36, 8, 48, 33, 36, 8, 8, 55, 0, + 60, 8, 7, 8, 6, 40, 42, 29, -1, 40, + 8, 8, 8, 8, 36, -1, 51, 53, 20, 40, + 51, 55, 8, 40, -1, 74, -1, -1, 61, 62, + 51, -1, 60, 60, 51, 60, 60, 60, 76, -1, + 56, 61, 62, 61, -1, -1, 61, 62, 60, 60, + 50, 61, 62, 60, 54, 61, 62, 8, 56, 56, + 29, -1, 61, 62, 60, 29, 61, 62, 25, 25, + 27, 27, 25, -1, 27, 61, 62, 25, 25, 27, + 27, 38, 38, 50, 15, 38, 25, 54, 27, 29, + 38, 38, 61, 62, 12, 15, 12, 61, 62, 38, + 25, 12, 27, 34, -1, 36, 25, -1, 27, -1, + 61, 62, -1, 38, 34, -1, 36, 15, 25, 38, + 27, 61, 62, 29, 25, -1, 27, -1, -1, -1, + -1, 38, 18, 19, 18, 19, 34, 38, 36, 57, + -1, 57, 18, 19, -1, 63, 57, 63, 18, 19, + -1, -1, 63, -1, -1, 61, 62, -1, -1, 45, + 46, 45, 46, -1, -1, 23, 24, -1, -1, 45, + 46, 23, 24, -1, 32, 45, 46, 35, -1, 37, + 32, 23, 24, 35, -1, 37, 25, -1, 27, -1, + 32, -1, -1, 35, -1, 37, 23, 24, -1, 38, + -1, -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, -1, + 37, -1, -1, -1, 31, 32, -1, 3, 35, -1, + 37, 23, 24, -1, -1, 23, 24, 13, -1, 31, + 32, 17, -1, 35, 32, 37, -1, 35, -1, 37, + 26, -1, 28, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 39, -1, 41, 42, -1, 12, 13, + -1, -1, -1, 49, -1, -1, 52, 53, 22, -1, + -1, -1, 58, -1, -1, 29, -1, -1, 64, 33, + 34, -1, 36, -1, -1, -1, 12, 13, -1, 43, + -1, 77, -1, 47, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, 65, -1, 67, -1, -1, -1, 43, -1, -1, + -1, 47, -1, -1, 78, 79, 80, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, + -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 78, 79, 80, -1, -1, -1, 3, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 13, -1, + -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, + -1, 26, -1, 28, -1, -1, -1, -1, -1, -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, -1, -1, -1, -1, -1, 64, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 77, -1, -1, -1, -1, -1, -1, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, + -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, + -1, -1, 26, -1, 28, -1, -1, 31, -1, -1, + -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, -1, -1, -1, -1, -1, + 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 77, -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, -1, 67, -1, 69, -1, + 71, -1, 73, -1, -1, -1, -1, 78, 79, 80, + -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, 60, -1, -1, -1, -1, 65, -1, 67, + -1, 69, -1, 71, -1, 73, -1, -1, -1, -1, + 78, 79, 80, -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, -1, 67, -1, 69, -1, 71, 72, 73, -1, + -1, -1, -1, 78, 79, 80, -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, 56, -1, -1, -1, -1, -1, + -1, -1, -1, 65, -1, 67, -1, 69, -1, 71, + -1, 73, -1, -1, -1, -1, 78, 79, 80, -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, -1, 67, -1, 69, -1, 71, -1, 73, -1, + -1, -1, -1, 78, 79, 80, -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, 56, -1, -1, -1, -1, -1, + -1, -1, -1, 65, -1, 67, -1, 69, -1, 71, + -1, 73, -1, -1, -1, -1, 78, 79, 80, -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, -1, 70, 71, + 72, 73, 74, 75, -1, -1, 78, 79, 80, 81, + 82, 83, 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, 68, -1, 70, 71, + 72, 73, 74, 75, -1, -1, 78, 79, 80, 81, + 82, 83, 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, 68, -1, 70, 71, + 72, 73, 74, 75, -1, -1, 78, 79, 80, 81, + 82, 83, 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, -1, -1, 78, 79, 80, 81, + 82, -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, -1, -1, 78, 79, 80, 81, + 82, -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, -1, -1, 78, 79, 80, 81, + 82, 83, + + 14, 46, 6, 46, 14, 6, 45, 45, 6, 65, + 7, 2, 7, 41, 7, 46, 6, 6, 45, 6, + 73, 76, 86, 45, 78, 46, 45, 7, 6, 81, + 67, 7, 45, 7, 6, 85, 80, 6, 86, 7, + 45, 7, 9, 45, 6, 45, 45, 7, 7, 45, + 6, 45, 10, 45, 6, 18, 7, 45, 6, 22, + -1, 18, -1, 18, 18, 18, 10, 11, 18, 18, + 23, 28, 26, 22, 6, 18, 18, 18, 18, 34, + 23, 23, 32, 18, 24, 18, 6, 22, 18, 30, + 23, 18, 18, 23, 18, 18, 23, 18, 24, 18, + 24, 24, 23, 18, 23, 20, 18, 18, 20, 20, + 12, 6, 18, 15, 20, 18, -1, 20, 18, 18, + 20, 20, 42, 6, 18, 18, 20, 20, 18, 18, + 20, 20, 12, 18, 18, 15, 20, 18, 23, 20, + 18, 45, 18, 21, 20, 18, -1, 42, 21, 18, + 18, 20, -1, 18, 45, 23, 18, 61, 23, 42, + 18, 23, -1, -1, 18, 23, -1, 25, 18, 23, + 61, 25, 18, 23, -1, 25, 18, 23, 18, 25, + -1, 23, 18, 23, 18, 27, 18, 23, 18, 23, + 18, 23, 18, 23, -1, 23, -1, 23, 18, 31, + 40, 29, -1, 23, 40, 35, 40, 33, 18, -1, + -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, + 40, -1, -1, -1, -1, -1, 6, -1, -1, -1, + 40, -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, 42, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptgrammar_p.h b/src/script/qscriptgrammar_p.h new file mode 100644 index 0000000..90c11fd --- /dev/null +++ b/src/script/qscriptgrammar_p.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! + +#ifndef QSCRIPTGRAMMAR_P_H +#define QSCRIPTGRAMMAR_P_H + +// +// 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. +// + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +class QScriptGrammar +{ +public: + enum { + EOF_SYMBOL = 0, + T_AND = 1, + T_AND_AND = 2, + T_AND_EQ = 3, + T_AUTOMATIC_SEMICOLON = 62, + T_BREAK = 4, + T_CASE = 5, + T_CATCH = 6, + T_COLON = 7, + T_COMMA = 8, + T_CONST = 81, + T_CONTINUE = 9, + T_DEBUGGER = 82, + 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 = 80, + 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_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_NEW = 43, + T_NOT = 44, + T_NOT_EQ = 45, + T_NOT_EQ_EQ = 46, + T_NULL = 78, + 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_QUESTION = 54, + T_RBRACE = 55, + T_RBRACKET = 56, + T_REMAINDER = 57, + T_REMAINDER_EQ = 58, + T_RESERVED_WORD = 83, + T_RETURN = 59, + T_RPAREN = 60, + T_SEMICOLON = 61, + T_STAR = 63, + T_STAR_EQ = 64, + T_STRING_LITERAL = 65, + T_SWITCH = 66, + T_THIS = 67, + T_THROW = 68, + T_TILDE = 69, + T_TRUE = 79, + T_TRY = 70, + T_TYPEOF = 71, + T_VAR = 72, + T_VOID = 73, + T_WHILE = 74, + T_WITH = 75, + T_XOR = 76, + T_XOR_EQ = 77, + + ACCEPT_STATE = 237, + RULE_COUNT = 269, + STATE_COUNT = 468, + TERMINAL_COUNT = 84, + NON_TERMINAL_COUNT = 88, + + GOTO_INDEX_OFFSET = 468, + GOTO_INFO_OFFSET = 1562, + GOTO_CHECK_OFFSET = 1562 + }; + + static const char *const spell []; + static const int lhs []; + static const int rhs []; + +#ifndef QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO + static const int rule_index []; + static const int rule_info []; +#endif // QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO + + 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]; + } +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTGRAMMAR_P_H diff --git a/src/script/qscriptlexer.cpp b/src/script/qscriptlexer.cpp new file mode 100644 index 0000000..f93b905 --- /dev/null +++ b/src/script/qscriptlexer.cpp @@ -0,0 +1,1122 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "qscriptengine_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptlexer_p.h" +#include "qscriptgrammar_p.h" + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +QT_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 QScript { +extern qsreal integerFromString(const char *buf, int size, int radix); +} + +QScript::Lexer::Lexer(QScriptEnginePrivate *eng) + : 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), + 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) +{ + // allocate space for read buffers + buffer8 = new char[size8]; + buffer16 = new QChar[size16]; + pattern = 0; + flags = 0; + +} + +QScript::Lexer::~Lexer() +{ + delete [] buffer8; + delete [] buffer16; +} + +void QScript::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 QScript::Lexer::shift(uint p) +{ + while (p--) { + ++pos; + ++yycolumn; + current = next1; + next1 = next2; + next2 = next3; + next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; + } +} + +void QScript::Lexer::setDone(State s) +{ + state = s; + done = true; +} + +int QScript::Lexer::findReservedWord(const QChar *c, int size) const +{ + switch (size) { + case 2: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) + return QScriptGrammar::T_DO; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) + return QScriptGrammar::T_IF; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) + return QScriptGrammar::T_IN; + } break; + + case 3: { + if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) + return QScriptGrammar::T_FOR; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) + return QScriptGrammar::T_NEW; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) + return QScriptGrammar::T_TRY; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) + return QScriptGrammar::T_VAR; + else if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) + return QScriptGrammar::T_RESERVED_WORD; + } + } break; + + case 4: { + if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QScriptGrammar::T_CASE; + else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QScriptGrammar::T_ELSE; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) + return QScriptGrammar::T_THIS; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) + return QScriptGrammar::T_VOID; + else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) + return QScriptGrammar::T_WITH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) + return QScriptGrammar::T_TRUE; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) + return QScriptGrammar::T_NULL; + else if (check_reserved) { + if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) + return QScriptGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) + return QScriptGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) + return QScriptGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) + return QScriptGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) + return QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::T_TYPEOF; + 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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::T_RESERVED_WORD; + 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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::T_DEBUGGER; + 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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::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 QScriptGrammar::T_RESERVED_WORD; + } + } break; + + } // switch + + return -1; +} + +int QScript::Lexer::lex() +{ + int token = 0; + state = Start; + ushort stringType = 0; // either single or double quotes + 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 = QScriptGrammar::T_SEMICOLON; + stackToken = 0; + setDone(Other); + } else { + setDone(Eof); + } + } else if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + bol = true; + terminator = true; + syncProhibitAutomaticSemicolon(); + if (restrKeyword) { + token = QScriptGrammar::T_SEMICOLON; + setDone(Other); + } + } else if (current == '"' || current == '\'') { + recordStartPos(); + state = InString; + 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 == QScriptGrammar::T_PLUS_PLUS + || token == QScriptGrammar::T_MINUS_MINUS)) { + // automatic semicolon insertion + stackToken = token; + token = QScriptGrammar::T_SEMICOLON; + } + setDone(Other); + } + else { + setDone(Bad); + err = IllegalCharacter; + errmsg = QLatin1String("Illegal character"); + } + } + break; + case InString: + if (current == stringType) { + shift(1); + setDone(String); + } else if (current == 0 || isLineTerminator()) { + setDone(Bad); + err = UnclosedStringLiteral; + errmsg = QLatin1String("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 = QLatin1String("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 = QLatin1String("Illegal unicode escape sequence"); + } + break; + case InSingleLineComment: + if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + terminator = true; + bol = true; + if (restrKeyword) { + token = QScriptGrammar::T_SEMICOLON; + setDone(Other); + } else + state = Start; + } else if (current == 0) { + setDone(Eof); + } + break; + case InMultiLineComment: + if (current == 0) { + setDone(Bad); + err = UnclosedComment; + errmsg = QLatin1String("Unclosed comment at end of file"); + } else if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + } else if (current == '*' && next1 == '/') { + state = Start; + shift(1); + } + 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 = QLatin1String("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 = QLatin1String("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 = QScript::integerFromString(buffer8, pos8, 16); + state = Number; + } else if (state == Octal) { // scan octal number + dval = QScript::integerFromString(buffer8, pos8, 8); + state = Number; + } + + restrKeyword = false; + delimited = false; + + switch (parenthesesState) { + case IgnoreParentheses: + break; + case CountParentheses: + if (token == QScriptGrammar::T_RPAREN) { + --parenthesesCount; + if (parenthesesCount == 0) + parenthesesState = BalancedParentheses; + } else if (token == QScriptGrammar::T_LPAREN) { + ++parenthesesCount; + } + break; + case BalancedParentheses: + parenthesesState = IgnoreParentheses; + break; + } + + switch (state) { + case Eof: + return 0; + case Other: + if(token == QScriptGrammar::T_RBRACE || token == QScriptGrammar::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 QScriptGrammar::T_IDENTIFIER; + } + if (token == QScriptGrammar::T_CONTINUE || token == QScriptGrammar::T_BREAK + || token == QScriptGrammar::T_RETURN || token == QScriptGrammar::T_THROW) { + restrKeyword = true; + } else if (token == QScriptGrammar::T_IF || token == QScriptGrammar::T_FOR + || token == QScriptGrammar::T_WHILE || token == QScriptGrammar::T_WITH) { + parenthesesState = CountParentheses; + parenthesesCount = 0; + } else if (token == QScriptGrammar::T_DO) { + parenthesesState = BalancedParentheses; + } + return token; + case String: + if (driver) + qsyylval.ustr = driver->intern(buffer16, pos16); + else + qsyylval.ustr = 0; + return QScriptGrammar::T_STRING_LITERAL; + case Number: + qsyylval.dval = dval; + return QScriptGrammar::T_NUMERIC_LITERAL; + case Bad: + return -1; + default: + Q_ASSERT(!"unhandled numeration value in switch"); + return -1; + } +} + +bool QScript::Lexer::isWhiteSpace() const +{ + return (current == ' ' || current == '\t' || + current == 0x0b || current == 0x0c); +} + +bool QScript::Lexer::isLineTerminator() const +{ + return (current == '\n' || current == '\r'); +} + +bool QScript::Lexer::isIdentLetter(ushort c) +{ + /* TODO: allow other legitimate unicode chars */ + return ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || c == '$' + || c == '_'); +} + +bool QScript::Lexer::isDecimalDigit(ushort c) +{ + return (c >= '0' && c <= '9'); +} + +bool QScript::Lexer::isHexDigit(ushort c) const +{ + return ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')); +} + +bool QScript::Lexer::isOctalDigit(ushort c) const +{ + return (c >= '0' && c <= '7'); +} + +int QScript::Lexer::matchPunctuator(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { + shift(4); + return QScriptGrammar::T_GT_GT_GT_EQ; + } else if (c1 == '=' && c2 == '=' && c3 == '=') { + shift(3); + return QScriptGrammar::T_EQ_EQ_EQ; + } else if (c1 == '!' && c2 == '=' && c3 == '=') { + shift(3); + return QScriptGrammar::T_NOT_EQ_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '>') { + shift(3); + return QScriptGrammar::T_GT_GT_GT; + } else if (c1 == '<' && c2 == '<' && c3 == '=') { + shift(3); + return QScriptGrammar::T_LT_LT_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '=') { + shift(3); + return QScriptGrammar::T_GT_GT_EQ; + } else if (c1 == '<' && c2 == '=') { + shift(2); + return QScriptGrammar::T_LE; + } else if (c1 == '>' && c2 == '=') { + shift(2); + return QScriptGrammar::T_GE; + } else if (c1 == '!' && c2 == '=') { + shift(2); + return QScriptGrammar::T_NOT_EQ; + } else if (c1 == '+' && c2 == '+') { + shift(2); + return QScriptGrammar::T_PLUS_PLUS; + } else if (c1 == '-' && c2 == '-') { + shift(2); + return QScriptGrammar::T_MINUS_MINUS; + } else if (c1 == '=' && c2 == '=') { + shift(2); + return QScriptGrammar::T_EQ_EQ; + } else if (c1 == '+' && c2 == '=') { + shift(2); + return QScriptGrammar::T_PLUS_EQ; + } else if (c1 == '-' && c2 == '=') { + shift(2); + return QScriptGrammar::T_MINUS_EQ; + } else if (c1 == '*' && c2 == '=') { + shift(2); + return QScriptGrammar::T_STAR_EQ; + } else if (c1 == '/' && c2 == '=') { + shift(2); + return QScriptGrammar::T_DIVIDE_EQ; + } else if (c1 == '&' && c2 == '=') { + shift(2); + return QScriptGrammar::T_AND_EQ; + } else if (c1 == '^' && c2 == '=') { + shift(2); + return QScriptGrammar::T_XOR_EQ; + } else if (c1 == '%' && c2 == '=') { + shift(2); + return QScriptGrammar::T_REMAINDER_EQ; + } else if (c1 == '|' && c2 == '=') { + shift(2); + return QScriptGrammar::T_OR_EQ; + } else if (c1 == '<' && c2 == '<') { + shift(2); + return QScriptGrammar::T_LT_LT; + } else if (c1 == '>' && c2 == '>') { + shift(2); + return QScriptGrammar::T_GT_GT; + } else if (c1 == '&' && c2 == '&') { + shift(2); + return QScriptGrammar::T_AND_AND; + } else if (c1 == '|' && c2 == '|') { + shift(2); + return QScriptGrammar::T_OR_OR; + } + + switch(c1) { + case '=': shift(1); return QScriptGrammar::T_EQ; + case '>': shift(1); return QScriptGrammar::T_GT; + case '<': shift(1); return QScriptGrammar::T_LT; + case ',': shift(1); return QScriptGrammar::T_COMMA; + case '!': shift(1); return QScriptGrammar::T_NOT; + case '~': shift(1); return QScriptGrammar::T_TILDE; + case '?': shift(1); return QScriptGrammar::T_QUESTION; + case ':': shift(1); return QScriptGrammar::T_COLON; + case '.': shift(1); return QScriptGrammar::T_DOT; + case '+': shift(1); return QScriptGrammar::T_PLUS; + case '-': shift(1); return QScriptGrammar::T_MINUS; + case '*': shift(1); return QScriptGrammar::T_STAR; + case '/': shift(1); return QScriptGrammar::T_DIVIDE_; + case '&': shift(1); return QScriptGrammar::T_AND; + case '|': shift(1); return QScriptGrammar::T_OR; + case '^': shift(1); return QScriptGrammar::T_XOR; + case '%': shift(1); return QScriptGrammar::T_REMAINDER; + case '(': shift(1); return QScriptGrammar::T_LPAREN; + case ')': shift(1); return QScriptGrammar::T_RPAREN; + case '{': shift(1); return QScriptGrammar::T_LBRACE; + case '}': shift(1); return QScriptGrammar::T_RBRACE; + case '[': shift(1); return QScriptGrammar::T_LBRACKET; + case ']': shift(1); return QScriptGrammar::T_RBRACKET; + case ';': shift(1); return QScriptGrammar::T_SEMICOLON; + + default: return -1; + } +} + +ushort QScript::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 QScript::Lexer::convertOctal(ushort c1, ushort c2, + ushort c3) const +{ + return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); +} + +unsigned char QScript::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 QScript::Lexer::convertHex(ushort c1, ushort c2) +{ + return ((convertHex(c1) << 4) + convertHex(c2)); +} + +QChar QScript::Lexer::convertUnicode(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + return QChar((convertHex(c3) << 4) + convertHex(c4), + (convertHex(c1) << 4) + convertHex(c2)); +} + +void QScript::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 QScript::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 QScript::Lexer::recordStartPos() +{ + startlineno = yylineno; + startcolumn = yycolumn; +} + +bool QScript::Lexer::scanRegExp(RegExpBodyPrefix prefix) +{ + pos16 = 0; + bool lastWasEscape = false; + + if (prefix == EqualPrefix) + record16(QLatin1Char('=')); + + while (1) { + if (isLineTerminator() || current == 0) { + errmsg = QLatin1String("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 = QScript::Ecma::RegExp::flagFromChar(current); + if (flag == 0) { + errmsg = QString::fromLatin1("Invalid regular expression flag '%0'") + .arg(QChar(current)); + return false; + } + flags |= flag; + record16(current); + shift(1); + } + + return true; +} + +void QScript::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_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptlexer_p.h b/src/script/qscriptlexer_p.h new file mode 100644 index 0000000..acf242c --- /dev/null +++ b/src/script/qscriptlexer_p.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** 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 QSCRIPTLEXER_P_H +#define QSCRIPTLEXER_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> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; +class QScriptNameIdImpl; + +namespace QScript { + +class Lexer +{ +public: + Lexer(QScriptEnginePrivate *eng); + ~Lexer(); + + void setCode(const QString &c, int lineno); + int lex(); + + int currentLineNo() const { return yylineno; } + int currentColumnNo() const { return yycolumn; } + + 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); + + QScriptNameIdImpl *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: + QScriptEnginePrivate *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 QScriptNameIdImpl *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 startlineno; + int startcolumn; + int bol; // begin of line + + union { + int ival; + double dval; + QScriptNameIdImpl *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; +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptmember_p.h b/src/script/qscriptmember_p.h new file mode 100644 index 0000000..ac98432 --- /dev/null +++ b/src/script/qscriptmember_p.h @@ -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 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 QSCRIPTMEMBER_P_H +#define QSCRIPTMEMBER_P_H + +#include "qscriptmemberfwd_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +inline void QScript::Member::resetFlags(uint flags) +{ + m_flags = flags; +} + +inline void QScript::Member::setFlags(uint flags) +{ + m_flags |= flags; +} + +inline void QScript::Member::unsetFlags(uint flags) +{ + m_flags &= ~flags; +} + +inline uint QScript::Member::flags() const +{ + return m_flags; +} + +inline bool QScript::Member::testFlags(uint mask) const +{ + return m_flags & mask; +} + +inline bool QScript::Member::isValid() const +{ + return m_flags & 0x00000300; +} + +inline bool QScript::Member::isWritable() const +{ + return !(m_flags & QScriptValue::ReadOnly); +} + +inline bool QScript::Member::isDeletable() const +{ + return !(m_flags & QScriptValue::Undeletable); +} + +inline bool QScript::Member::dontEnum() const +{ + return m_flags & QScriptValue::SkipInEnumeration; +} + +inline bool QScript::Member::isObjectProperty() const +{ + return m_flags & ObjectProperty; +} + +inline bool QScript::Member::isNativeProperty() const +{ + return m_flags & NativeProperty; +} + +inline bool QScript::Member::isUninitializedConst() const +{ + return m_flags & UninitializedConst; +} + +inline bool QScript::Member::isGetter() const +{ + return m_flags & QScriptValue::PropertyGetter; +} + +inline bool QScript::Member::isSetter() const +{ + return m_flags & QScriptValue::PropertySetter; +} + +inline bool QScript::Member::isGetterOrSetter() const +{ + return m_flags & (QScriptValue::PropertyGetter | QScriptValue::PropertySetter); +} + +inline int QScript::Member::id() const +{ + return m_id; +} + +inline QScriptNameIdImpl *QScript::Member::nameId() const +{ + return m_nameId; +} + +inline QScript::Member QScript::Member::invalid() +{ + Member m; + m.m_flags = 0; + return m; +} + +inline void QScript::Member::invalidate() +{ + m_flags = 0; +} + +inline void QScript::Member::native(QScriptNameIdImpl *nameId, int id, uint flags) +{ + Q_ASSERT(! (flags & ObjectProperty)); + + m_nameId = nameId; + m_id = id; + m_flags = flags | NativeProperty; +} + +inline void QScript::Member::object(QScriptNameIdImpl *nameId, int id, uint flags) +{ + Q_ASSERT(! (flags & NativeProperty)); + + m_nameId = nameId; + m_id = id; + m_flags = flags | ObjectProperty; +} + +inline bool QScript::Member::operator==(const QScript::Member &other) const +{ + return m_nameId == other.m_nameId; +} + +inline bool QScript::Member::operator!=(const QScript::Member &other) const +{ + return m_nameId != other.m_nameId; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptmemberfwd_p.h b/src/script/qscriptmemberfwd_p.h new file mode 100644 index 0000000..023815a --- /dev/null +++ b/src/script/qscriptmemberfwd_p.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 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 QSCRIPTMEMBERFWD_P_H +#define QSCRIPTMEMBERFWD_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 + +#ifndef QT_NO_SCRIPT + +class QScriptNameIdImpl; + +namespace QScript { + + class Member + { + public: + enum PropertyFlag { + ObjectProperty = 0x00000100, // Stored in the member table + NativeProperty = 0x00000200, + + UninitializedConst = 0x00000800, // NB: shared with QScriptValue::KeepExistingFlags + + InternalRange = 0x0000ff00 // Not user-accessible (read as 0, don't change on write) + }; + + inline Member() : m_nameId(0), m_id(0), m_flags(0) {} + + inline void resetFlags(uint flags); + inline void setFlags(uint flags); + inline void unsetFlags(uint flags); + inline uint flags() const; + inline bool testFlags(uint mask) const; + + inline bool isValid() const; + + inline bool isWritable() const; + inline bool isDeletable() const; + + inline bool dontEnum() const; + + inline bool isObjectProperty() const; + inline bool isNativeProperty() const; + + inline bool isUninitializedConst() const; + + inline bool isGetter() const; + inline bool isSetter() const; + inline bool isGetterOrSetter() const; + + inline int id() const; + inline QScriptNameIdImpl *nameId() const; + + inline bool operator==(const Member &other) const; + inline bool operator!=(const Member &other) const; + + inline static Member invalid(); + inline void invalidate(); + + inline void native(QScriptNameIdImpl *nameId, int id, uint flags); + inline void object(QScriptNameIdImpl *nameId, int id, uint flags); + + private: + QScriptNameIdImpl *m_nameId; + int m_id; + uint m_flags; + }; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptmemorypool_p.h b/src/script/qscriptmemorypool_p.h new file mode 100644 index 0000000..2f069ec --- /dev/null +++ b/src/script/qscriptmemorypool_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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 QSCRIPTMEMORYPOOL_P_H +#define QSCRIPTMEMORYPOOL_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> + +QT_BEGIN_NAMESPACE + +namespace QScript { + +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 QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptnameid_p.h b/src/script/qscriptnameid_p.h new file mode 100644 index 0000000..c0d8f6b --- /dev/null +++ b/src/script/qscriptnameid_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 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 QSCRIPTNAMEID_P_H +#define QSCRIPTNAMEID_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 QScriptNameIdImpl +{ +public: + QString s; + uint h; + QScriptNameIdImpl *next; + uint used: 1; + uint persistent: 1; + uint unique: 1; + uint pad: 29; + + inline QScriptNameIdImpl(const QString &_s): + s(_s), h(0), next(0), used(0), persistent(0), unique(0), pad(0) { } +}; + +QT_END_NAMESPACE + +#endif // QSCRIPTNAMEID_P_H diff --git a/src/script/qscriptnodepool_p.h b/src/script/qscriptnodepool_p.h new file mode 100644 index 0000000..5e1876c --- /dev/null +++ b/src/script/qscriptnodepool_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 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 QSCRIPTNODEPOOL_P_H +#define QSCRIPTNODEPOOL_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 "qscriptmemorypool_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; + +namespace QScript { + +namespace AST { +class Node; +} // namespace AST + +class Code; +class CompilationUnit; + +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, QScriptEnginePrivate *engine); + virtual ~NodePool(); + + Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation); + + inline QString fileName() const { return m_fileName; } + inline QScriptEnginePrivate *engine() const { return m_engine; } +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + inline qint64 id() const { return m_id; } +#endif + +private: + QHash<AST::Node*, Code*> m_codeCache; + QString m_fileName; + QScriptEnginePrivate *m_engine; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + qint64 m_id; +#endif + +private: + Q_DISABLE_COPY(NodePool) +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptobject_p.h b/src/script/qscriptobject_p.h new file mode 100644 index 0000000..1ac3c65 --- /dev/null +++ b/src/script/qscriptobject_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 QSCRIPTOBJECT_P_H +#define QSCRIPTOBJECT_P_H + +#include "qscriptobjectfwd_p.h" + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +inline bool QScriptObject::findMember(QScriptNameIdImpl *nameId, + QScript::Member *m) const +{ + const QScript::Member *members = m_members.constData(); + const int size = m_members.size(); + + const QScript::Member *first = &members[-1]; + const QScript::Member *last = &members[size - 1]; + + for (const QScript::Member *it = last; it != first; --it) { + if (it->nameId() == nameId && it->isValid()) { + *m = *it; + return true; + } + } + + return false; +} + +// assumes that m already points to the setter +inline bool QScriptObject::findGetter(QScript::Member *m) const +{ + const QScript::Member *members = m_members.constData(); + const QScript::Member *first = &members[-1]; + const QScript::Member *last = &members[m->id() - 1]; + + for (const QScript::Member *it = last; it != first; --it) { + if (it->nameId() == m->nameId() && it->isValid() && it->isGetter()) { + *m = *it; + return true; + } + } + + return false; +} + +// assumes that m already points to the getter +inline bool QScriptObject::findSetter(QScript::Member *m) const +{ + const QScript::Member *members = m_members.constData(); + const QScript::Member *first = &members[-1]; + const QScript::Member *last = &members[m->id() - 1]; + + for (const QScript::Member *it = last; it != first; --it) { + if (it->nameId() == m->nameId() && it->isValid() && it->isSetter()) { + *m = *it; + return true; + } + } + + return false; +} + +inline int QScriptObject::memberCount() const +{ + return m_members.size(); +} + +inline void QScriptObject::createMember(QScriptNameIdImpl *nameId, + QScript::Member *member, uint flags) +{ + member->object(nameId, m_values.size(), flags); + m_members.append(*member); + m_values.append(QScriptValueImpl()); +} + +inline void QScriptObject::member(int index, QScript::Member *member) +{ + *member = m_members[index]; +} + +inline void QScriptObject::put(const QScript::Member &m, const QScriptValueImpl &v) +{ + m_values[m.id()] = v; +} + +inline QScriptValueImpl &QScriptObject::reference(const QScript::Member &m) +{ + return m_values[m.id()]; +} + +inline void QScriptObject::get(const QScript::Member &m, QScriptValueImpl *v) +{ + Q_ASSERT(m.isObjectProperty()); + *v = m_values[m.id()]; +} + +inline void QScriptObject::removeMember(const QScript::Member &member) +{ + m_members[member.id()].invalidate(); + m_values[member.id()].invalidate(); +} + +inline QScriptObject::~QScriptObject() +{ + finalize(); +} + +inline void QScriptObject::finalize() +{ + finalizeData(); +} + +inline void QScriptObject::finalizeData() +{ + if (m_data) { + m_data->finalize(m_class->engine()); + delete m_data; + m_data = 0; + } +} + +inline void QScriptObject::reset() +{ + m_prototype.invalidate(); + m_scope.invalidate(); + m_internalValue.invalidate(); + m_members.resize(0); + m_values.resize(0); + m_data = 0; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptobjectdata_p.h b/src/script/qscriptobjectdata_p.h new file mode 100644 index 0000000..ed4e5fd --- /dev/null +++ b/src/script/qscriptobjectdata_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 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 QSCRIPTOBJECTDATA_P_H +#define QSCRIPTOBJECTDATA_P_H + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptEnginePrivate; + +class QScriptObjectData +{ +protected: + inline QScriptObjectData() {} + +public: + virtual void finalize(QScriptEnginePrivate *) {} + virtual ~QScriptObjectData() {} + +private: + Q_DISABLE_COPY(QScriptObjectData) +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptobjectfwd_p.h b/src/script/qscriptobjectfwd_p.h new file mode 100644 index 0000000..0cbec1f --- /dev/null +++ b/src/script/qscriptobjectfwd_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 QSCRIPTOBJECTFWD_P_H +#define QSCRIPTOBJECTFWD_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> + +#ifndef QT_NO_SCRIPT + +#include "qscriptbuffer_p.h" +#include "qscriptmemberfwd_p.h" +#include "qscriptvalueimplfwd_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptObjectData; + +class QScriptObject +{ +public: + inline void reset(); + inline ~QScriptObject(); + inline void finalize(); + inline void finalizeData(); + + inline bool findMember(QScriptNameIdImpl *nameId, + QScript::Member *m) const; + + inline bool findGetter(QScript::Member *m) const; + + inline bool findSetter(QScript::Member *m) const; + + inline int memberCount() const; + + inline void createMember(QScriptNameIdImpl *nameId, + QScript::Member *member, uint flags); + + inline void member(int index, QScript::Member *member); + + inline void put(const QScript::Member &m, const QScriptValueImpl &v); + + inline QScriptValueImpl &reference(const QScript::Member &m); + + inline void get(const QScript::Member &m, QScriptValueImpl *v); + + inline void removeMember(const QScript::Member &member); + + QScriptValueImpl m_prototype; + QScriptValueImpl m_scope; + QScriptValueImpl m_internalValue; // [[value]] + QScriptObjectData *m_data; + QScript::Buffer<QScript::Member> m_members; + QScript::Buffer<QScriptValueImpl> m_values; + qint64 m_id; + QScriptClassInfo *m_class; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptparser.cpp b/src/script/qscriptparser.cpp new file mode 100644 index 0000000..0b04df1 --- /dev/null +++ b/src/script/qscriptparser.cpp @@ -0,0 +1,1172 @@ +// 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> + +#ifndef QT_NO_SCRIPT + +#include <string.h> + +#include "qscriptengine.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptlexer_p.h" +#include "qscriptast_p.h" +#include "qscriptnodepool_p.h" + +#define Q_SCRIPT_UPDATE_POSITION(node, startloc, endloc) do { \ + node->startLine = startloc.startLine; \ + node->startColumn = startloc.startColumn; \ + node->endLine = endloc.endLine; \ + node->endColumn = endloc.endColumn; \ +} while (0) + + + +#include "qscriptparser_p.h" + +// +// This file is automatically generated from qscript.g. +// Changes will be lost. +// + +QT_BEGIN_NAMESPACE + +inline static bool automatic(QScriptEnginePrivate *driver, int token) +{ + return token == QScriptGrammar::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +QScriptParser::QScriptParser(): + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + error_lineno(0), + error_column(0) +{ +} + +QScriptParser::~QScriptParser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline QScriptParser::Location location(QScript::Lexer *lexer) +{ + QScriptParser::Location loc; + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + loc.endLine = lexer->endLineNo(); + loc.endColumn = lexer->endColumnNo(); + return loc; +} + +bool QScriptParser::parse(QScriptEnginePrivate *driver) +{ + const int INITIAL_STATE = 0; + QScript::Lexer *lexer = driver->lexer(); + + int yytoken = -1; + int saved_yytoken = -1; + + reallocateStack(); + + tos = 0; + state_stack[++tos] = INITIAL_STATE; + + while (true) + { + const int state = state_stack [tos]; + if (yytoken == -1 && - TERMINAL_COUNT != action_index [state]) + { + if (saved_yytoken == -1) + { + yytoken = lexer->lex(); + location_stack [tos] = location(lexer); + } + else + { + yytoken = saved_yytoken; + saved_yytoken = -1; + } + } + + int act = t_action (state, yytoken); + + if (act == ACCEPT_STATE) + return true; + + else if (act > 0) + { + if (++tos == stack_size) + reallocateStack(); + + sym_stack [tos].dval = lexer->dval (); + state_stack [tos] = act; + location_stack [tos] = location(lexer); + yytoken = -1; + } + + else if (act < 0) + { + int r = - act - 1; + + tos -= rhs [r]; + act = state_stack [tos++]; + + switch (r) { + +case 0: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ThisExpression> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 1: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 2: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NullExpression> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 3: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TrueLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 4: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FalseLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 5: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 6: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StringLiteral> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 7: { + bool rx = lexer->scanRegExp(QScript::Lexer::NoPrefix); + if (!rx) { + error_message = lexer->errorMessage(); + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + return false; + } + sym(1).Node = QScript::makeAstNode<QScript::AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 8: { + bool rx = lexer->scanRegExp(QScript::Lexer::EqualPrefix); + if (!rx) { + error_message = lexer->errorMessage(); + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + return false; + } + sym(1).Node = QScript::makeAstNode<QScript::AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 9: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 10: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 11: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 12: { + if (sym(2).Node) + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); + else + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 13: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 14: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 15: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ElementList> (driver->nodePool(), sym(1).Elision, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 16: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision, sym(4).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 17: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Elision> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 18: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Elision> (driver->nodePool(), sym(1).Elision); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 19: { + sym(1).Node = 0; +} break; + +case 20: { + sym(1).Elision = sym(1).Elision->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 21: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyName, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 22: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 23: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 24: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 25: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 26: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 27: + +case 28: + +case 29: + +case 30: + +case 31: + +case 32: + +case 33: + +case 34: + +case 35: + +case 36: + +case 37: + +case 38: + +case 39: + +case 40: + +case 41: + +case 42: + +case 43: + +case 44: + +case 45: + +case 46: + +case 47: + +case 48: + +case 49: + +case 50: + +case 51: + +case 52: + +case 53: + +case 54: + +case 55: + +case 56: + +case 57: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; + +case 62: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 63: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 64: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(3).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 66: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NewExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 67: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(2).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 68: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(2).ArgumentList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 69: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 70: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 71: { + sym(1).Node = 0; +} break; + +case 72: { + sym(1).Node = sym(2).ArgumentList->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 73: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArgumentList> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 74: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 78: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 79: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 81: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 82: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 83: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 84: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 85: { + sym(1).Node = QScript::makeAstNode<QScript::AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 86: { + sym(1).Node = QScript::makeAstNode<QScript::AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 87: { + sym(1).Node = QScript::makeAstNode<QScript::AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 88: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 89: { + sym(1).Node = QScript::makeAstNode<QScript::AST::NotExpression> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 91: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mul, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 92: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Div, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 93: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mod, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 95: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Add, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 96: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Sub, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 98: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::LShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 99: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::RShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 100: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::URShift, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 102: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 103: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 104: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 105: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 106: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 107: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::In, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 109: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 110: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 111: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 112: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 113: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 115: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 116: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 117: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 118: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 120: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 121: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 122: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 123: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 125: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 127: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 129: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 131: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 133: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 135: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 137: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 139: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 141: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 143: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 145: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 147: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 149: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 151: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 152: { + sym(1).ival = QSOperator::Assign; +} break; + +case 153: { + sym(1).ival = QSOperator::InplaceMul; +} break; + +case 154: { + sym(1).ival = QSOperator::InplaceDiv; +} break; + +case 155: { + sym(1).ival = QSOperator::InplaceMod; +} break; + +case 156: { + sym(1).ival = QSOperator::InplaceAdd; +} break; + +case 157: { + sym(1).ival = QSOperator::InplaceSub; +} break; + +case 158: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; + +case 159: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; + +case 160: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; + +case 161: { + sym(1).ival = QSOperator::InplaceAnd; +} break; + +case 162: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 163: { + sym(1).ival = QSOperator::InplaceOr; +} break; + +case 165: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 166: { + sym(1).Node = 0; +} break; + +case 169: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 170: { + sym(1).Node = 0; +} break; + +case 187: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Block> (driver->nodePool(), sym(2).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 188: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementList> (driver->nodePool(), sym(1).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 189: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 190: { + sym(1).Node = 0; +} break; + +case 191: { + sym(1).Node = sym(1).StatementList->finish (); +} break; + +case 193: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableStatement> (driver->nodePool(), sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 194: { + sym(1).ival = T_CONST; +} break; + +case 195: { + sym(1).ival = T_VAR; +} break; + +case 196: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 197: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 198: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 199: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 200: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 201: { + sym(1).Node = QScript::makeAstNode<QScript::AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 202: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 203: { + sym(1).Node = 0; +} break; + +case 205: { + sym(1) = sym(2); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 206: { + sym(1).Node = 0; +} break; + +case 208: { + sym(1).Node = QScript::makeAstNode<QScript::AST::EmptyStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 210: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 211: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; + +case 212: { + sym(1).Node = QScript::makeAstNode<QScript::AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 214: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; + +case 215: { + sym(1).Node = QScript::makeAstNode<QScript::AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 216: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ForStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(9)); +} break; + +case 217: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LocalForStatement> (driver->nodePool(), sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(10)); +} break; + +case 218: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(7)); +} break; + +case 219: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LocalForEachStatement> (driver->nodePool(), sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; + +case 221: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ContinueStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 223: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 225: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BreakStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 227: { + sym(1).Node = QScript::makeAstNode<QScript::AST::BreakStatement> (driver->nodePool(), sym(2).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 229: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 230: { + sym(1).Node = QScript::makeAstNode<QScript::AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 231: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 232: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 233: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 234: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 235: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 236: { + sym(1).Node = 0; +} break; + +case 237: { + sym(1).Node = sym(1).CaseClauses->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 238: { + sym(1).Node = QScript::makeAstNode<QScript::AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 239: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 240: { + sym(1).Node = QScript::makeAstNode<QScript::AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 242: { + sym(1).Node = QScript::makeAstNode<QScript::AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 243: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 244: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 245: { + sym(1).Node = QScript::makeAstNode<QScript::AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(4)); +} break; + +case 246: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(5)); +} break; + +case 247: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Finally> (driver->nodePool(), sym(2).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 249: { + sym(1).Node = QScript::makeAstNode<QScript::AST::DebuggerStatement> (driver->nodePool()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 250: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; + +case 251: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(8)); +} break; + +case 252: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 253: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(3)); +} break; + +case 254: { + sym(1).Node = 0; +} break; + +case 255: { + sym(1).Node = sym(1).FormalParameterList->finish (); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 256: { + sym(1).Node = 0; +} break; + +case 258: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 259: { + sym(1).Node = QScript::makeAstNode<QScript::AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); + driver->changeAbstractSyntaxTree(sym(1).Node); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 260: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 261: { + sym(1).Node = QScript::makeAstNode<QScript::AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(2)); +} break; + +case 262: { + sym(1).Node = QScript::makeAstNode<QScript::AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 263: { + sym(1).Node = QScript::makeAstNode<QScript::AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); + Q_SCRIPT_UPDATE_POSITION(sym(1).Node, loc(1), loc(1)); +} break; + +case 264: { + sym(1).sval = 0; +} break; + +case 266: { + sym(1).Node = 0; +} break; + + } // switch + + state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); + + if (rhs[r] > 1) { + location_stack[tos - 1].endLine = location_stack[tos + rhs[r] - 2].endLine; + location_stack[tos - 1].endColumn = location_stack[tos + rhs[r] - 2].endColumn; + location_stack[tos] = location_stack[tos + rhs[r] - 1]; + } + } + + else + { + if (saved_yytoken == -1 && automatic (driver, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0) + { + saved_yytoken = yytoken; + yytoken = T_SEMICOLON; + continue; + } + + else if ((state == INITIAL_STATE) && (yytoken == 0)) { + // accept empty input + yytoken = T_SEMICOLON; + continue; + } + + int ers = state; + int shifts = 0; + int reduces = 0; + int expected_tokens [3]; + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) + { + int k = t_action (ers, tk); + + if (! k) + continue; + else if (k < 0) + ++reduces; + else if (spell [tk]) + { + if (shifts < 3) + expected_tokens [shifts] = tk; + ++shifts; + } + } + + error_message.clear (); + if (shifts && shifts < 3) + { + bool first = true; + + for (int s = 0; s < shifts; ++s) + { + if (first) + error_message += QLatin1String ("Expected "); + else + error_message += QLatin1String (", "); + + first = false; + error_message += QLatin1String("`"); + error_message += QLatin1String (spell [expected_tokens [s]]); + error_message += QLatin1String("'"); + } + } + + if (error_message.isEmpty()) + error_message = lexer->errorMessage(); + + error_lineno = lexer->startLineNo(); + error_column = lexer->startColumnNo(); + + return false; + } + } + + return false; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptparser_p.h b/src/script/qscriptparser_p.h new file mode 100644 index 0000000..98317c7 --- /dev/null +++ b/src/script/qscriptparser_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! + +// +// 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 qscript.g. +// Changes will be lost. +// + +#ifndef QSCRIPTPARSER_P_H +#define QSCRIPTPARSER_P_H + +#include "qscriptgrammar_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptastfwd_p.h" + +QT_BEGIN_NAMESPACE + +class QString; +class QScriptEnginePrivate; +class QScriptNameIdImpl; + +class QScriptParser: protected QScriptGrammar +{ +public: + union Value { + int ival; + double dval; + QScriptNameIdImpl *sval; + QScript::AST::ArgumentList *ArgumentList; + QScript::AST::CaseBlock *CaseBlock; + QScript::AST::CaseClause *CaseClause; + QScript::AST::CaseClauses *CaseClauses; + QScript::AST::Catch *Catch; + QScript::AST::DefaultClause *DefaultClause; + QScript::AST::ElementList *ElementList; + QScript::AST::Elision *Elision; + QScript::AST::ExpressionNode *Expression; + QScript::AST::Finally *Finally; + QScript::AST::FormalParameterList *FormalParameterList; + QScript::AST::FunctionBody *FunctionBody; + QScript::AST::FunctionDeclaration *FunctionDeclaration; + QScript::AST::Node *Node; + QScript::AST::PropertyName *PropertyName; + QScript::AST::PropertyNameAndValueList *PropertyNameAndValueList; + QScript::AST::SourceElement *SourceElement; + QScript::AST::SourceElements *SourceElements; + QScript::AST::Statement *Statement; + QScript::AST::StatementList *StatementList; + QScript::AST::VariableDeclaration *VariableDeclaration; + QScript::AST::VariableDeclarationList *VariableDeclarationList; + }; + + struct Location { + int startLine; + int startColumn; + int endLine; + int endColumn; + }; + +public: + QScriptParser(); + ~QScriptParser(); + + bool parse(QScriptEnginePrivate *driver); + + inline QString errorMessage() const + { return error_message; } + inline int errorLineNumber() const + { return error_lineno; } + inline int errorColumnNumber() const + { return error_column; } + +protected: + inline void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline Location &loc(int index) + { return location_stack [tos + index - 2]; } + +protected: + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + Location *location_stack; + QString error_message; + int error_lineno; + int error_column; +}; + +inline void QScriptParser::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<Location*> (qRealloc(location_stack, stack_size * sizeof(Location))); +} + + +#define Q_SCRIPT_REGEXPLITERAL_RULE1 7 + +#define Q_SCRIPT_REGEXPLITERAL_RULE2 8 + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTPARSER_P_H diff --git a/src/script/qscriptprettypretty.cpp b/src/script/qscriptprettypretty.cpp new file mode 100644 index 0000000..6ee1e55 --- /dev/null +++ b/src/script/qscriptprettypretty.cpp @@ -0,0 +1,1334 @@ +/**************************************************************************** +** +** 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 "qscriptprettypretty_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptast_p.h" + +#include <QtCore/QString> +#include <QtCore/QTextStream> +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +namespace QScript { +QString numberToString(qsreal value); +} + +using namespace QScript; + +PrettyPretty::PrettyPretty(QTextStream &o): + out(o), m_indentLevel(0) +{ +} + +PrettyPretty::~PrettyPretty() +{ +} + +void PrettyPretty::acceptAsBlock(AST::Node *node) +{ + out << "{"; + pushIndentLevel(); + newlineAndIndent(); + accept(node); + popIndentLevel(); + newlineAndIndent(); + out << "}"; +} + +int PrettyPretty::operatorPrecedenceLevel(int op) +{ + switch (op) { + case QSOperator::Div: + case QSOperator::Mod: + case QSOperator::Mul: + return 5; + case QSOperator::Add: + case QSOperator::Sub: + return 6; + case QSOperator::LShift: + case QSOperator::RShift: + case QSOperator::URShift: + return 7; + case QSOperator::Ge: + case QSOperator::Gt: + case QSOperator::In: + case QSOperator::InstanceOf: + case QSOperator::Le: + case QSOperator::Lt: + return 8; + case QSOperator::Equal: + case QSOperator::NotEqual: + case QSOperator::StrictEqual: + case QSOperator::StrictNotEqual: + return 9; + case QSOperator::BitAnd: + return 10; + case QSOperator::BitXor: + return 11; + case QSOperator::BitOr: + return 12; + case QSOperator::And: + return 13; + case QSOperator::Or: + return 14; + case QSOperator::InplaceAnd: + case QSOperator::InplaceSub: + case QSOperator::InplaceDiv: + case QSOperator::InplaceAdd: + case QSOperator::InplaceLeftShift: + case QSOperator::InplaceMod: + case QSOperator::InplaceMul: + case QSOperator::InplaceOr: + case QSOperator::InplaceRightShift: + case QSOperator::InplaceURightShift: + case QSOperator::InplaceXor: + case QSOperator::Assign: + return 16; + default: + Q_ASSERT_X(false, "PrettyPretty::operatorPrecedenceLevel()", "bad operator"); + } + return 0; +} + +int PrettyPretty::compareOperatorPrecedence(int op1, int op2) +{ + int prec1 = operatorPrecedenceLevel(op1); + int prec2 = operatorPrecedenceLevel(op2); + if (prec1 == prec2) + return 0; + if (prec1 > prec2) + return -1; + return 1; +} + +QTextStream &PrettyPretty::operator () (AST::Node *node, int level) +{ + int was = indentLevel(level); + accept(node); + indentLevel(was); + return out; +} + +QTextStream &PrettyPretty::newlineAndIndent() +{ + enum { IND = 4 }; + out << endl << QString().fill(QLatin1Char(' '), m_indentLevel * IND); + return out; +} + +void PrettyPretty::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +bool PrettyPretty::visit(AST::ThisExpression *node) +{ + Q_UNUSED(node); + out << "this"; + return true; +} + +void PrettyPretty::endVisit(AST::ThisExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::IdentifierExpression *node) +{ + out << QScriptEnginePrivate::toString(node->name); + return true; +} + +void PrettyPretty::endVisit(AST::IdentifierExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NullExpression *node) +{ + Q_UNUSED(node); + out << "null"; + return false; +} + +void PrettyPretty::endVisit(AST::NullExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::TrueLiteral *node) +{ + Q_UNUSED(node); + out << "true"; + return false; +} + +void PrettyPretty::endVisit(AST::TrueLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FalseLiteral *node) +{ + Q_UNUSED(node); + out << "false"; + return false; +} + +void PrettyPretty::endVisit(AST::FalseLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::StringLiteral *node) +{ + QString lit = QScriptEnginePrivate::toString(node->value); + lit.replace(QLatin1String("\\"), QLatin1String("\\\\")); + out << "\"" << lit << "\""; + return false; +} + +void PrettyPretty::endVisit(AST::StringLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NumericLiteral *node) +{ + out << QScript::numberToString(node->value); + return true; +} + +void PrettyPretty::endVisit(AST::NumericLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::RegExpLiteral *node) +{ + out << "/" << QScriptEnginePrivate::toString(node->pattern) << "/"; + if (node->flags) + out << QScript::Ecma::RegExp::flagsToString(node->flags); + + return true; +} + +void PrettyPretty::endVisit(AST::RegExpLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ArrayLiteral *node) +{ + out << "["; + accept(node->elements); + accept(node->elision); + out << "]"; + return false; +} + +void PrettyPretty::endVisit(AST::ArrayLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ObjectLiteral *node) +{ + out << "{"; + if (node->properties) { + pushIndentLevel(); + AST::PropertyNameAndValueList *prop; + for (prop = node->properties; prop != 0; prop = prop->next) { + newlineAndIndent(); + accept(prop); + if (prop->next) + out << ","; + } + popIndentLevel(); + newlineAndIndent(); + } + out << "}"; + return false; +} + +void PrettyPretty::endVisit(AST::ObjectLiteral *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ElementList *node) +{ + accept(node->elision); + accept(node->expression); + for (node = node->next; node != 0; node = node->next) { + out << ", "; + accept(node->elision); + accept(node->expression); + } + return false; +} + +void PrettyPretty::endVisit(AST::ElementList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Elision *node) +{ + out << ", "; + for (AST::Elision *eit = node->next; eit != 0; eit = eit->next) + out << ", "; + return false; +} + +void PrettyPretty::endVisit(AST::Elision *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::PropertyNameAndValueList *node) +{ + accept(node->name); + out << ": "; + accept(node->value); + return false; +} + +void PrettyPretty::endVisit(AST::PropertyNameAndValueList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::IdentifierPropertyName *node) +{ + out << QScriptEnginePrivate::toString(node->id); + return false; +} + +void PrettyPretty::endVisit(AST::IdentifierPropertyName *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::StringLiteralPropertyName *node) +{ + QString lit = QScriptEnginePrivate::toString(node->id); + lit.replace(QLatin1String("\\"), QLatin1String("\\\\")); + out << lit; + return false; +} + +void PrettyPretty::endVisit(AST::StringLiteralPropertyName *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NumericLiteralPropertyName *node) +{ + out << node->id; + return false; +} + +void PrettyPretty::endVisit(AST::NumericLiteralPropertyName *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ArrayMemberExpression *node) +{ + accept(node->base); + out << "["; + accept(node->expression); + out << "]"; + return false; +} + +void PrettyPretty::endVisit(AST::ArrayMemberExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FieldMemberExpression *node) +{ + accept(node->base); + out << "." << QScriptEnginePrivate::toString(node->name); + return false; +} + +void PrettyPretty::endVisit(AST::FieldMemberExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NewMemberExpression *node) +{ + out << "new "; + accept(node->base); + out << "("; + accept(node->arguments); + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::NewMemberExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NewExpression *node) +{ + Q_UNUSED(node); + out << "new "; + return true; +} + +void PrettyPretty::endVisit(AST::NewExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::CallExpression *node) +{ + accept(node->base); + out << "("; + accept(node->arguments); + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::CallExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ArgumentList *node) +{ + accept(node->expression); + for (node = node->next; node != 0; node = node->next) { + out << ", "; + accept(node->expression); + } + return false; +} + +void PrettyPretty::endVisit(AST::ArgumentList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::PostIncrementExpression *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::PostIncrementExpression *node) +{ + Q_UNUSED(node); + out << "++"; +} + +bool PrettyPretty::visit(AST::PostDecrementExpression *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::PostDecrementExpression *node) +{ + Q_UNUSED(node); + out << "--"; +} + +bool PrettyPretty::visit(AST::DeleteExpression *node) +{ + Q_UNUSED(node); + out << "delete "; + return true; +} + +void PrettyPretty::endVisit(AST::DeleteExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::VoidExpression *node) +{ + Q_UNUSED(node); + out << "void "; + return true; +} + +void PrettyPretty::endVisit(AST::VoidExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::TypeOfExpression *node) +{ + Q_UNUSED(node); + out << "typeof "; + return true; +} + +void PrettyPretty::endVisit(AST::TypeOfExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::PreIncrementExpression *node) +{ + Q_UNUSED(node); + out << "++"; + return true; +} + +void PrettyPretty::endVisit(AST::PreIncrementExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::PreDecrementExpression *node) +{ + Q_UNUSED(node); + out << "--"; + return true; +} + +void PrettyPretty::endVisit(AST::PreDecrementExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::UnaryPlusExpression *node) +{ + out << "+"; + bool needParens = (node->expression->binaryExpressionCast() != 0); + if (needParens) + out << "("; + accept(node->expression); + if (needParens) + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::UnaryPlusExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::UnaryMinusExpression *node) +{ + out << "-"; + bool needParens = (node->expression->binaryExpressionCast() != 0); + if (needParens) + out << "("; + accept(node->expression); + if (needParens) + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::UnaryMinusExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::TildeExpression *node) +{ + out << "~"; + bool needParens = (node->expression->binaryExpressionCast() != 0); + if (needParens) + out << "("; + accept(node->expression); + if (needParens) + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::TildeExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::NotExpression *node) +{ + out << "!"; + bool needParens = (node->expression->binaryExpressionCast() != 0); + if (needParens) + out << "("; + accept(node->expression); + if (needParens) + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::NotExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::BinaryExpression *node) +{ + bool needParens = node->left->binaryExpressionCast() + && (compareOperatorPrecedence(node->left->binaryExpressionCast()->op, node->op) < 0); + if (needParens) + out << "("; + accept(node->left); + if (needParens) + out << ")"; + QString s; + switch (node->op) { + case QSOperator::Add: + s = QLatin1String("+"); break; + case QSOperator::And: + s = QLatin1String("&&"); break; + case QSOperator::InplaceAnd: + s = QLatin1String("&="); break; + case QSOperator::Assign: + s = QLatin1String("="); break; + case QSOperator::BitAnd: + s = QLatin1String("&"); break; + case QSOperator::BitOr: + s = QLatin1String("|"); break; + case QSOperator::BitXor: + s = QLatin1String("^"); break; + case QSOperator::InplaceSub: + s = QLatin1String("-="); break; + case QSOperator::Div: + s = QLatin1String("/"); break; + case QSOperator::InplaceDiv: + s = QLatin1String("/="); break; + case QSOperator::Equal: + s = QLatin1String("=="); break; + case QSOperator::Ge: + s = QLatin1String(">="); break; + case QSOperator::Gt: + s = QLatin1String(">"); break; + case QSOperator::In: + s = QLatin1String("in"); break; + case QSOperator::InplaceAdd: + s = QLatin1String("+="); break; + case QSOperator::InstanceOf: + s = QLatin1String("instanceof"); break; + case QSOperator::Le: + s = QLatin1String("<="); break; + case QSOperator::LShift: + s = QLatin1String("<<"); break; + case QSOperator::InplaceLeftShift: + s = QLatin1String("<<="); break; + case QSOperator::Lt: + s = QLatin1String("<"); break; + case QSOperator::Mod: + s = QLatin1String("%"); break; + case QSOperator::InplaceMod: + s = QLatin1String("%="); break; + case QSOperator::Mul: + s = QLatin1String("*"); break; + case QSOperator::InplaceMul: + s = QLatin1String("*="); break; + case QSOperator::NotEqual: + s = QLatin1String("!="); break; + case QSOperator::Or: + s = QLatin1String("||"); break; + case QSOperator::InplaceOr: + s = QLatin1String("|="); break; + case QSOperator::RShift: + s = QLatin1String(">>"); break; + case QSOperator::InplaceRightShift: + s = QLatin1String(">>="); break; + case QSOperator::StrictEqual: + s = QLatin1String("==="); break; + case QSOperator::StrictNotEqual: + s = QLatin1String("!=="); break; + case QSOperator::Sub: + s = QLatin1String("-"); break; + case QSOperator::URShift: + s = QLatin1String(">>>"); break; + case QSOperator::InplaceURightShift: + s = QLatin1String(">>>="); break; + case QSOperator::InplaceXor: + s = QLatin1String("^="); break; + default: + Q_ASSERT (0); + } + out << " " << s << " "; + needParens = node->right->binaryExpressionCast() + && (compareOperatorPrecedence(node->right->binaryExpressionCast()->op, node->op) <= 0); + if (needParens) + out << "("; + accept(node->right); + if (needParens) + out << ")"; + return false; +} + +void PrettyPretty::endVisit(AST::BinaryExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ConditionalExpression *node) +{ + accept(node->expression); + out << " ? "; + accept(node->ok); + out << " : "; + accept(node->ko); + return false; +} + +void PrettyPretty::endVisit(AST::ConditionalExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Expression *node) +{ + accept(node->left); + out << ", "; + accept(node->right); + return false; +} + +void PrettyPretty::endVisit(AST::Expression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Block *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::Block *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::StatementList *node) +{ + accept(node->statement); + for (node = node->next; node != 0; node = node->next) { + newlineAndIndent(); + accept(node->statement); + } + return false; +} + +void PrettyPretty::endVisit(AST::StatementList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::VariableDeclarationList *node) +{ + AST::VariableDeclarationList *it = node; + + do { + it->declaration->accept(this); + it = it->next; + if (it) + out << ", "; + } while (it); + + return false; +} + +void PrettyPretty::endVisit(AST::VariableDeclarationList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::VariableStatement *node) +{ + out << "var "; + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::VariableStatement *node) +{ + Q_UNUSED(node); + out << ";"; +} + +bool PrettyPretty::visit(AST::VariableDeclaration *node) +{ + out << QScriptEnginePrivate::toString(node->name); + if (node->expression) { + out << " = "; + accept(node->expression); + } + return false; +} + +void PrettyPretty::endVisit(AST::VariableDeclaration *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::EmptyStatement *node) +{ + Q_UNUSED(node); + out << ";"; + return true; +} + +void PrettyPretty::endVisit(AST::EmptyStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ExpressionStatement *node) +{ + accept(node->expression); + out << ";"; + return false; +} + +void PrettyPretty::endVisit(AST::ExpressionStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::IfStatement *node) +{ + out << "if ("; + accept(node->expression); + out << ") "; + acceptAsBlock(node->ok); + if (node->ko) { + out << " else "; + acceptAsBlock(node->ko); + } + return false; +} + +void PrettyPretty::endVisit(AST::IfStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::DoWhileStatement *node) +{ + out << "do "; + acceptAsBlock(node->statement); + out << " while ("; + accept(node->expression); + out << ");"; + return false; +} + +void PrettyPretty::endVisit(AST::DoWhileStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::WhileStatement *node) +{ + out << "while ("; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::WhileStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ForStatement *node) +{ + out << "for ("; + accept(node->initialiser); + out << "; "; + accept(node->condition); + out << "; "; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::ForStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::LocalForStatement *node) +{ + out << "for (var "; + accept(node->declarations); + out << "; "; + accept(node->condition); + out << "; "; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::LocalForStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ForEachStatement *node) +{ + out << "for ("; + accept(node->initialiser); + out << " in "; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::ForEachStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::LocalForEachStatement *node) +{ + out << "for (var "; + accept(node->declaration); + out << " in "; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::LocalForEachStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ContinueStatement *node) +{ + out << "continue"; + if (node->label) { + out << " " << QScriptEnginePrivate::toString(node->label); + } + out << ";"; + return false; +} + +void PrettyPretty::endVisit(AST::ContinueStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::BreakStatement *node) +{ + out << "break"; + if (node->label) { + out << " " << QScriptEnginePrivate::toString(node->label); + } + out << ";"; + return false; +} + +void PrettyPretty::endVisit(AST::BreakStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ReturnStatement *node) +{ + out << "return"; + if (node->expression) { + out << " "; + accept(node->expression); + } + out << ";"; + return false; +} + +void PrettyPretty::endVisit(AST::ReturnStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::WithStatement *node) +{ + out << "with ("; + accept(node->expression); + out << ") "; + acceptAsBlock(node->statement); + return false; +} + +void PrettyPretty::endVisit(AST::WithStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::SwitchStatement *node) +{ + out << "switch ("; + accept(node->expression); + out << ") "; + acceptAsBlock(node->block); + return false; +} + +void PrettyPretty::endVisit(AST::SwitchStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::CaseBlock *node) +{ + accept(node->clauses); + if (node->defaultClause) { + newlineAndIndent(); + accept(node->defaultClause); + } + if (node->moreClauses) { + newlineAndIndent(); + accept(node->moreClauses); + } + return false; +} + +void PrettyPretty::endVisit(AST::CaseBlock *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::CaseClauses *node) +{ + accept(node->clause); + for (node = node->next; node != 0; node = node->next) { + newlineAndIndent(); + accept(node->clause); + } + return false; +} + +void PrettyPretty::endVisit(AST::CaseClauses *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::CaseClause *node) +{ + out << "case "; + accept(node->expression); + out << ":"; + if (node->statements) { + newlineAndIndent(); + accept(node->statements); + } + return false; +} + +void PrettyPretty::endVisit(AST::CaseClause *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::DefaultClause *node) +{ + Q_UNUSED(node); + out << "default:"; + newlineAndIndent(); + return true; +} + +void PrettyPretty::endVisit(AST::DefaultClause *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::LabelledStatement *node) +{ + out << QScriptEnginePrivate::toString(node->label) << ": "; + return true; +} + +void PrettyPretty::endVisit(AST::LabelledStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::ThrowStatement *node) +{ + Q_UNUSED(node); + out << "throw "; + accept(node->expression); + out << ";"; + return false; +} + +void PrettyPretty::endVisit(AST::ThrowStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::TryStatement *node) +{ + out << "try "; + acceptAsBlock(node->statement); + if (node->catchExpression) { + out << " catch (" << QScriptEnginePrivate::toString(node->catchExpression->name) << ") "; + acceptAsBlock(node->catchExpression->statement); + } + if (node->finallyExpression) { + out << " finally "; + acceptAsBlock(node->finallyExpression->statement); + } + return false; +} + +void PrettyPretty::endVisit(AST::TryStatement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Catch *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::Catch *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Finally *node) +{ + Q_UNUSED(node); + out << "finally "; + return true; +} + +void PrettyPretty::endVisit(AST::Finally *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FunctionDeclaration *node) +{ + out << "function"; + + if (node->name) + out << " " << QScriptEnginePrivate::toString(node->name); + + // the arguments + out << "("; + for (AST::FormalParameterList *it = node->formals; it; it = it->next) { + if (it->name) + out << QScriptEnginePrivate::toString(it->name); + + if (it->next) + out << ", "; + } + out << ")"; + + // the function body + out << " {"; + + if (node->body) { + pushIndentLevel(); + newlineAndIndent(); + accept(node->body); + popIndentLevel(); + newlineAndIndent(); + } + + out << "}"; + + return false; +} + +void PrettyPretty::endVisit(AST::FunctionDeclaration *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FunctionExpression *node) +{ + out << "function"; + + if (node->name) + out << " " << QScriptEnginePrivate::toString(node->name); + + // the arguments + out << "("; + for (AST::FormalParameterList *it = node->formals; it; it = it->next) { + if (it->name) + out << QScriptEnginePrivate::toString(it->name); + + if (it->next) + out << ", "; + } + out << ")"; + + // the function body + out << " {"; + + if (node->body) { + pushIndentLevel(); + newlineAndIndent(); + accept(node->body); + popIndentLevel(); + newlineAndIndent(); + } + + out << "}"; + + return false; +} + +void PrettyPretty::endVisit(AST::FunctionExpression *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FormalParameterList *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::FormalParameterList *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FunctionBody *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::FunctionBody *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::Program *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::Program *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::SourceElements *node) +{ + Q_UNUSED(node); + accept(node->element); + for (node = node->next; node != 0; node = node->next) { + newlineAndIndent(); + accept(node->element); + } + return false; +} + +void PrettyPretty::endVisit(AST::SourceElements *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::FunctionSourceElement *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::FunctionSourceElement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::StatementSourceElement *node) +{ + Q_UNUSED(node); + return true; +} + +void PrettyPretty::endVisit(AST::StatementSourceElement *node) +{ + Q_UNUSED(node); +} + +bool PrettyPretty::visit(AST::DebuggerStatement *node) +{ + Q_UNUSED(node); + out << "debugger"; + return true; +} + +void PrettyPretty::endVisit(AST::DebuggerStatement *node) +{ + Q_UNUSED(node); + out << ";"; +} + +bool PrettyPretty::preVisit(AST::Node *node) +{ + Q_UNUSED(node); + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptprettypretty_p.h b/src/script/qscriptprettypretty_p.h new file mode 100644 index 0000000..b757cc0 --- /dev/null +++ b/src/script/qscriptprettypretty_p.h @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** 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 QSCRIPTPRETTYPRETTY_P_H +#define QSCRIPTPRETTYPRETTY_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 "qscriptastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +class QTextStream; + +namespace QScript { + +class PrettyPretty: protected AST::Visitor +{ +public: + PrettyPretty(QTextStream &out); + virtual ~PrettyPretty(); + + QTextStream &operator () (AST::Node *node, int level = 0); + +protected: + void accept(AST::Node *node); + + virtual bool preVisit(AST::Node *node); + + virtual bool visit(AST::ThisExpression *node); + virtual void endVisit(AST::ThisExpression *node); + + virtual bool visit(AST::IdentifierExpression *node); + virtual void endVisit(AST::IdentifierExpression *node); + + virtual bool visit(AST::NullExpression *node); + virtual void endVisit(AST::NullExpression *node); + + virtual bool visit(AST::TrueLiteral *node); + virtual void endVisit(AST::TrueLiteral *node); + + virtual bool visit(AST::FalseLiteral *node); + virtual void endVisit(AST::FalseLiteral *node); + + virtual bool visit(AST::StringLiteral *node); + virtual void endVisit(AST::StringLiteral *node); + + virtual bool visit(AST::NumericLiteral *node); + virtual void endVisit(AST::NumericLiteral *node); + + virtual bool visit(AST::RegExpLiteral *node); + virtual void endVisit(AST::RegExpLiteral *node); + + virtual bool visit(AST::ArrayLiteral *node); + virtual void endVisit(AST::ArrayLiteral *node); + + virtual bool visit(AST::ObjectLiteral *node); + virtual void endVisit(AST::ObjectLiteral *node); + + virtual bool visit(AST::ElementList *node); + virtual void endVisit(AST::ElementList *node); + + virtual bool visit(AST::Elision *node); + virtual void endVisit(AST::Elision *node); + + virtual bool visit(AST::PropertyNameAndValueList *node); + virtual void endVisit(AST::PropertyNameAndValueList *node); + + virtual bool visit(AST::IdentifierPropertyName *node); + virtual void endVisit(AST::IdentifierPropertyName *node); + + virtual bool visit(AST::StringLiteralPropertyName *node); + virtual void endVisit(AST::StringLiteralPropertyName *node); + + virtual bool visit(AST::NumericLiteralPropertyName *node); + virtual void endVisit(AST::NumericLiteralPropertyName *node); + + virtual bool visit(AST::ArrayMemberExpression *node); + virtual void endVisit(AST::ArrayMemberExpression *node); + + virtual bool visit(AST::FieldMemberExpression *node); + virtual void endVisit(AST::FieldMemberExpression *node); + + virtual bool visit(AST::NewMemberExpression *node); + virtual void endVisit(AST::NewMemberExpression *node); + + virtual bool visit(AST::NewExpression *node); + virtual void endVisit(AST::NewExpression *node); + + virtual bool visit(AST::CallExpression *node); + virtual void endVisit(AST::CallExpression *node); + + virtual bool visit(AST::ArgumentList *node); + virtual void endVisit(AST::ArgumentList *node); + + virtual bool visit(AST::PostIncrementExpression *node); + virtual void endVisit(AST::PostIncrementExpression *node); + + virtual bool visit(AST::PostDecrementExpression *node); + virtual void endVisit(AST::PostDecrementExpression *node); + + virtual bool visit(AST::DeleteExpression *node); + virtual void endVisit(AST::DeleteExpression *node); + + virtual bool visit(AST::VoidExpression *node); + virtual void endVisit(AST::VoidExpression *node); + + virtual bool visit(AST::TypeOfExpression *node); + virtual void endVisit(AST::TypeOfExpression *node); + + virtual bool visit(AST::PreIncrementExpression *node); + virtual void endVisit(AST::PreIncrementExpression *node); + + virtual bool visit(AST::PreDecrementExpression *node); + virtual void endVisit(AST::PreDecrementExpression *node); + + virtual bool visit(AST::UnaryPlusExpression *node); + virtual void endVisit(AST::UnaryPlusExpression *node); + + virtual bool visit(AST::UnaryMinusExpression *node); + virtual void endVisit(AST::UnaryMinusExpression *node); + + virtual bool visit(AST::TildeExpression *node); + virtual void endVisit(AST::TildeExpression *node); + + virtual bool visit(AST::NotExpression *node); + virtual void endVisit(AST::NotExpression *node); + + virtual bool visit(AST::BinaryExpression *node); + virtual void endVisit(AST::BinaryExpression *node); + + virtual bool visit(AST::ConditionalExpression *node); + virtual void endVisit(AST::ConditionalExpression *node); + + virtual bool visit(AST::Expression *node); + virtual void endVisit(AST::Expression *node); + + virtual bool visit(AST::Block *node); + virtual void endVisit(AST::Block *node); + + virtual bool visit(AST::StatementList *node); + virtual void endVisit(AST::StatementList *node); + + virtual bool visit(AST::VariableStatement *node); + virtual void endVisit(AST::VariableStatement *node); + + virtual bool visit(AST::VariableDeclarationList *node); + virtual void endVisit(AST::VariableDeclarationList *node); + + virtual bool visit(AST::VariableDeclaration *node); + virtual void endVisit(AST::VariableDeclaration *node); + + virtual bool visit(AST::EmptyStatement *node); + virtual void endVisit(AST::EmptyStatement *node); + + virtual bool visit(AST::ExpressionStatement *node); + virtual void endVisit(AST::ExpressionStatement *node); + + virtual bool visit(AST::IfStatement *node); + virtual void endVisit(AST::IfStatement *node); + + virtual bool visit(AST::DoWhileStatement *node); + virtual void endVisit(AST::DoWhileStatement *node); + + virtual bool visit(AST::WhileStatement *node); + virtual void endVisit(AST::WhileStatement *node); + + virtual bool visit(AST::ForStatement *node); + virtual void endVisit(AST::ForStatement *node); + + virtual bool visit(AST::LocalForStatement *node); + virtual void endVisit(AST::LocalForStatement *node); + + virtual bool visit(AST::ForEachStatement *node); + virtual void endVisit(AST::ForEachStatement *node); + + virtual bool visit(AST::LocalForEachStatement *node); + virtual void endVisit(AST::LocalForEachStatement *node); + + virtual bool visit(AST::ContinueStatement *node); + virtual void endVisit(AST::ContinueStatement *node); + + virtual bool visit(AST::BreakStatement *node); + virtual void endVisit(AST::BreakStatement *node); + + virtual bool visit(AST::ReturnStatement *node); + virtual void endVisit(AST::ReturnStatement *node); + + virtual bool visit(AST::WithStatement *node); + virtual void endVisit(AST::WithStatement *node); + + virtual bool visit(AST::SwitchStatement *node); + virtual void endVisit(AST::SwitchStatement *node); + + virtual bool visit(AST::CaseBlock *node); + virtual void endVisit(AST::CaseBlock *node); + + virtual bool visit(AST::CaseClauses *node); + virtual void endVisit(AST::CaseClauses *node); + + virtual bool visit(AST::CaseClause *node); + virtual void endVisit(AST::CaseClause *node); + + virtual bool visit(AST::DefaultClause *node); + virtual void endVisit(AST::DefaultClause *node); + + virtual bool visit(AST::LabelledStatement *node); + virtual void endVisit(AST::LabelledStatement *node); + + virtual bool visit(AST::ThrowStatement *node); + virtual void endVisit(AST::ThrowStatement *node); + + virtual bool visit(AST::TryStatement *node); + virtual void endVisit(AST::TryStatement *node); + + virtual bool visit(AST::Catch *node); + virtual void endVisit(AST::Catch *node); + + virtual bool visit(AST::Finally *node); + virtual void endVisit(AST::Finally *node); + + virtual bool visit(AST::FunctionDeclaration *node); + virtual void endVisit(AST::FunctionDeclaration *node); + + virtual bool visit(AST::FunctionExpression *node); + virtual void endVisit(AST::FunctionExpression *node); + + virtual bool visit(AST::FormalParameterList *node); + virtual void endVisit(AST::FormalParameterList *node); + + virtual bool visit(AST::FunctionBody *node); + virtual void endVisit(AST::FunctionBody *node); + + virtual bool visit(AST::Program *node); + virtual void endVisit(AST::Program *node); + + virtual bool visit(AST::SourceElements *node); + virtual void endVisit(AST::SourceElements *node); + + virtual bool visit(AST::FunctionSourceElement *node); + virtual void endVisit(AST::FunctionSourceElement *node); + + virtual bool visit(AST::StatementSourceElement *node); + virtual void endVisit(AST::StatementSourceElement *node); + + virtual bool visit(AST::DebuggerStatement *node); + virtual void endVisit(AST::DebuggerStatement *node); + + int indentLevel(int level) + { + int was = m_indentLevel; + m_indentLevel = level; + return was; + } + + void pushIndentLevel() + { ++m_indentLevel; } + + void popIndentLevel() + { --m_indentLevel; } + + QTextStream &newlineAndIndent(); + + void acceptAsBlock(AST::Node *node); + + static int operatorPrecedenceLevel(int op); + static int compareOperatorPrecedence(int op1, int op2); + +private: + QTextStream &out; + int m_indentLevel; + + Q_DISABLE_COPY(PrettyPretty) +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptrepository_p.h b/src/script/qscriptrepository_p.h new file mode 100644 index 0000000..64dbac0 --- /dev/null +++ b/src/script/qscriptrepository_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 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 QSCRIPTREPOSITORY_P_H +#define QSCRIPTREPOSITORY_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 "qscriptbuffer_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + +template <typename Tp, typename Factory> +class Repository +{ +public: + inline Repository() { cache.reserve(32); } + inline ~Repository() { qDeleteAll(cache); } + + inline Tp *get() + { + if (cache.isEmpty()) + return Factory::create(); + + return cache.takeLast(); + } + + inline void release(Tp *item) + { cache.append(item); } + +private: + Buffer<Tp*> cache; + +private: + Q_DISABLE_COPY(Repository) +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/qscriptstring.cpp b/src/script/qscriptstring.cpp new file mode 100644 index 0000000..69b0796 --- /dev/null +++ b/src/script/qscriptstring.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 "qscriptstring.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptstring_p.h" +#include "qscriptnameid_p.h" +#include "qscriptvalue_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.4 + \class QScriptString + + \brief The QScriptString class acts as a handle to "interned" strings in a QScriptEngine. + + \ingroup script + \mainclass + + QScriptString can be used to achieve faster (repeated) + property getting/setting, and comparison of property names, of + script objects. + + To get a QScriptString representation of a string, pass the string + to QScriptEngine::toStringHandle(). The typical usage pattern is to + register one or more pre-defined strings when setting up your script + environment, then subsequently use the relevant QScriptString as + argument to e.g. QScriptValue::property(). + + Call the toString() function to obtain the string that a + QScriptString represents. +*/ + +/*! + \internal +*/ +QScriptStringPrivate::QScriptStringPrivate() + : nameId(0), engine(0), q_ptr(0) +{ + ref = 0; +} + +/*! + \internal +*/ +QScriptStringPrivate *QScriptStringPrivate::create() +{ + return new QScriptStringPrivate(); +} + +/*! + \internal +*/ +QScriptStringPrivate *QScriptStringPrivate::get(const QScriptString &q) +{ + return const_cast<QScriptStringPrivate*>(q.d_func()); +} + +/*! + \internal +*/ +void QScriptStringPrivate::init(QScriptString &q, QScriptStringPrivate *d) +{ + Q_ASSERT(q.d_ptr == 0); + q.d_ptr = d; + q.d_ptr->ref.ref(); +} + +/*! + Constructs an invalid QScriptString. +*/ +QScriptString::QScriptString() + : d_ptr(0) +{ +} + +/*! + Constructs a new QScriptString that is a copy of \a other. +*/ +QScriptString::QScriptString(const QScriptString &other) + : d_ptr(other.d_ptr) +{ + if (d_ptr) + d_ptr->ref.ref(); +} + +/*! + Destroys this QScriptString. +*/ +QScriptString::~QScriptString() +{ + if (d_ptr && !d_ptr->ref.deref()) { + if (isValid()) { + d_ptr->engine->uninternString(d_ptr); + } else { + // the engine has already been deleted + delete d_ptr; + } + d_ptr = 0; + } +} + +/*! + Assigns the \a other value to this QScriptString. +*/ +QScriptString &QScriptString::operator=(const QScriptString &other) +{ + if (d_ptr == other.d_ptr) + return *this; + if (d_ptr && !d_ptr->ref.deref()) { + if (isValid()) { + d_ptr->engine->uninternString(d_ptr); + } else { + // the engine has already been deleted + delete d_ptr; + } + } + d_ptr = other.d_ptr; + if (d_ptr) + d_ptr->ref.ref(); + return *this; +} + +/*! + Returns true if this QScriptString is valid; otherwise + returns false. +*/ +bool QScriptString::isValid() const +{ + Q_D(const QScriptString); + return (d && d->nameId); +} + +/*! + Returns true if this QScriptString is equal to \a other; + otherwise returns false. +*/ +bool QScriptString::operator==(const QScriptString &other) const +{ + Q_D(const QScriptString); + return (d == other.d_func()); +} + +/*! + Returns true if this QScriptString is not equal to \a other; + otherwise returns false. +*/ +bool QScriptString::operator!=(const QScriptString &other) const +{ + Q_D(const QScriptString); + return (d != other.d_func()); +} + +/*! + Returns the string that this QScriptString represents, or a + null string if this QScriptString is not valid. + + \sa isValid() +*/ +QString QScriptString::toString() const +{ + Q_D(const QScriptString); + if (!d || !d->nameId) + return QString(); + return d->nameId->s; +} + +/*! + Returns the string that this QScriptString represents, or a + null string if this QScriptString is not valid. + + \sa toString() +*/ +QScriptString::operator QString() const +{ + return toString(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptstring.h b/src/script/qscriptstring.h new file mode 100644 index 0000000..d2fecd8 --- /dev/null +++ b/src/script/qscriptstring.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 QSCRIPTSTRING_H +#define QSCRIPTSTRING_H + +#include <QtCore/qstring.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptEngine; +class QScriptStringPrivate; + +class Q_SCRIPT_EXPORT QScriptString +{ +public: + QScriptString(); + QScriptString(const QScriptString &other); + ~QScriptString(); + + QScriptString &operator=(const QScriptString &other); + + bool isValid() const; + + bool operator==(const QScriptString &other) const; + bool operator!=(const QScriptString &other) const; + + QString toString() const; + operator QString() const; + +private: + QScriptStringPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptString) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT +#endif // QSCRIPTSTRING_H diff --git a/src/script/qscriptstring_p.h b/src/script/qscriptstring_p.h new file mode 100644 index 0000000..34f9dec --- /dev/null +++ b/src/script/qscriptstring_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 QSCRIPTSTRING_P_H +#define QSCRIPTSTRING_P_H + +#include <QtCore/qatomic.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptNameIdImpl; +class QScriptEnginePrivate; +class QScriptString; + +class QScriptStringPrivate +{ + Q_DECLARE_PUBLIC(QScriptString) +public: + QScriptStringPrivate(); + + static QScriptStringPrivate *create(); + static QScriptStringPrivate *get(const QScriptString &q); + static void init(QScriptString &q, QScriptStringPrivate *d); + + QBasicAtomicInt ref; + QScriptNameIdImpl *nameId; + QScriptEnginePrivate *engine; + QScriptString *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptsyntaxchecker.cpp b/src/script/qscriptsyntaxchecker.cpp new file mode 100644 index 0000000..9653bc1 --- /dev/null +++ b/src/script/qscriptsyntaxchecker.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** 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 "qscriptsyntaxchecker_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptlexer_p.h" +#include "qscriptparser_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + + +SyntaxChecker::SyntaxChecker(): + tos(0), + stack_size(0), + state_stack(0) +{ +} + +SyntaxChecker::~SyntaxChecker() +{ + if (stack_size) { + qFree(state_stack); + } +} + +bool SyntaxChecker::automatic(QScript::Lexer *lexer, int token) const +{ + return token == T_RBRACE || token == 0 || lexer->prevTerminator(); +} + +SyntaxChecker::Result SyntaxChecker::checkSyntax(const QString &code) +{ + const int INITIAL_STATE = 0; + QScript::Lexer lexer (/*engine=*/ 0); + lexer.setCode(code, /*lineNo*/ 1); + + int yytoken = -1; + int saved_yytoken = -1; + QString error_message; + int error_lineno = -1; + int error_column = -1; + State checkerState = Valid; + + reallocateStack(); + + tos = 0; + state_stack[++tos] = INITIAL_STATE; + + while (true) + { + const int state = state_stack [tos]; + if (yytoken == -1 && - TERMINAL_COUNT != action_index [state]) + { + if (saved_yytoken == -1) + yytoken = lexer.lex(); + else + { + yytoken = saved_yytoken; + saved_yytoken = -1; + } + } + + int act = t_action (state, yytoken); + + if (act == ACCEPT_STATE) { + if (lexer.error() == QScript::Lexer::UnclosedComment) + checkerState = Intermediate; + else + checkerState = Valid; + break; + } else if (act > 0) { + if (++tos == stack_size) + reallocateStack(); + + state_stack [tos] = act; + yytoken = -1; + } + + else if (act < 0) + { + int r = - act - 1; + + tos -= rhs [r]; + act = state_stack [tos++]; + + if ((r == Q_SCRIPT_REGEXPLITERAL_RULE1) + || (r == Q_SCRIPT_REGEXPLITERAL_RULE2)) { + // Skip the rest of the RegExp literal + bool rx = lexer.scanRegExp(); + if (!rx) { + checkerState = Intermediate; + break; + } + } + + state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); + } + + else + { + if (saved_yytoken == -1 && automatic (&lexer, yytoken) && t_action (state, T_AUTOMATIC_SEMICOLON) > 0) + { + saved_yytoken = yytoken; + yytoken = T_SEMICOLON; + continue; + } + + else if ((state == INITIAL_STATE) && (yytoken == 0)) { + // accept empty input + yytoken = T_SEMICOLON; + continue; + } + + int ers = state; + int shifts = 0; + int reduces = 0; + int expected_tokens [3]; + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) + { + int k = t_action (ers, tk); + + if (! k) + continue; + else if (k < 0) + ++reduces; + else if (spell [tk]) + { + if (shifts < 3) + expected_tokens [shifts] = tk; + ++shifts; + } + } + + error_message.clear (); + if (shifts && shifts < 3) + { + bool first = true; + + for (int s = 0; s < shifts; ++s) + { + if (first) + error_message += QLatin1String ("Expected "); + else + error_message += QLatin1String (", "); + + first = false; + error_message += QLatin1String("`"); + error_message += QLatin1String (spell [expected_tokens [s]]); + error_message += QLatin1String("'"); + } + } + + if (error_message.isEmpty()) + error_message = lexer.errorMessage(); + + error_lineno = lexer.startLineNo(); + error_column = lexer.startColumnNo(); + checkerState = Error; + break; + } + } + + if (checkerState == Error) { + if (lexer.error() == QScript::Lexer::UnclosedComment) + checkerState = Intermediate; + else if (yytoken == 0) + checkerState = Intermediate; + } + return Result(checkerState, error_lineno, error_column, error_message); +} + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptsyntaxchecker_p.h b/src/script/qscriptsyntaxchecker_p.h new file mode 100644 index 0000000..0c02d24 --- /dev/null +++ b/src/script/qscriptsyntaxchecker_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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 QSCRIPTSYNTAXCHECKER_H +#define QSCRIPTSYNTAXCHECKER_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.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptgrammar_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + +class Lexer; + +class SyntaxChecker: protected QScriptGrammar +{ +public: + enum State { + Error, + Intermediate, + Valid, + }; + + struct Result { + Result(State s, int ln, int col, const QString &msg) + : state(s), errorLineNumber(ln), errorColumnNumber(col), + errorMessage(msg) {} + State state; + int errorLineNumber; + int errorColumnNumber; + QString errorMessage; + }; + + SyntaxChecker(); + ~SyntaxChecker(); + + Result checkSyntax(const QString &code); + +protected: + bool automatic(QScript::Lexer *lexer, int token) const; + inline void reallocateStack(); + +protected: + int tos; + int stack_size; + int *state_stack; +}; + +inline void SyntaxChecker::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); +} + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptsyntaxcheckresult_p.h b/src/script/qscriptsyntaxcheckresult_p.h new file mode 100644 index 0000000..fc5cb42 --- /dev/null +++ b/src/script/qscriptsyntaxcheckresult_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 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 QSCRIPTSYNTAXCHECKRESULT_P_H +#define QSCRIPTSYNTAXCHECKRESULT_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. +// + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qatomic.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +class QScriptSyntaxCheckResultPrivate +{ +public: + QScriptSyntaxCheckResultPrivate() { ref = 0; } + ~QScriptSyntaxCheckResultPrivate() {} + + QScriptSyntaxCheckResult::State state; + int errorColumnNumber; + int errorLineNumber; + QString errorMessage; + QBasicAtomicInt ref; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptvalue.cpp b/src/script/qscriptvalue.cpp new file mode 100644 index 0000000..a253985 --- /dev/null +++ b/src/script/qscriptvalue.cpp @@ -0,0 +1,1595 @@ +/**************************************************************************** +** +** 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 "qscriptvalue.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalue_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptclass.h" +#include "qscriptclass_p.h" + +#include <QtCore/QDateTime> +#include <QtCore/QRegExp> + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptValue + + \brief The QScriptValue class acts as a container for the Qt Script data types. + + \ingroup script + \mainclass + + QScriptValue supports the types defined in the \l{ECMA-262} + standard: The primitive types, which are Undefined, Null, Boolean, + Number, and String; and the Object type. Additionally, Qt Script + has built-in support for QVariant, QObject and QMetaObject. + + For the object-based types (including Date and RegExp), use the + newT() functions in QScriptEngine (e.g. QScriptEngine::newObject()) + to create a QScriptValue of the desired type. For the primitive types, + use one of the QScriptValue constructor overloads. + + The methods named isT() (e.g. isBool(), isUndefined()) can be + used to test if a value is of a certain type. The methods named + toT() (e.g. toBool(), toString()) can be used to convert a + QScriptValue to another type. You can also use the generic + qscriptvalue_cast() function. + + Object values have zero or more properties which are themselves + QScriptValues. Use setProperty() to set a property of an object, and + call property() to retrieve the value of a property. + + \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 0 + + Each property can have a set of attributes; these are specified as + the third (optional) argument to setProperty(). The attributes of a + property can be queried by calling the propertyFlags() function. The + following code snippet creates a property that cannot be modified by + script code: + + \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 1 + + If you want to iterate over the properties of a script object, use + the QScriptValueIterator class. + + Object values have an internal \c{prototype} property, which can be + accessed with prototype() and setPrototype(). Properties added to a + prototype are shared by all objects having that prototype; this is + referred to as prototype-based inheritance. In practice, it means + that (by default) the property() function will automatically attempt + to look up look the property in the prototype() (and in the + prototype of the prototype(), and so on), if the object itself does + not have the requested property. Note that this prototype-based + lookup is not performed by setProperty(); setProperty() will always + create the property in the script object itself. For more + information, see the \l{QtScript} documentation. + + Function objects (objects for which isFunction() returns true) can + be invoked by calling call(). Constructor functions can be used to + construct new objects by calling construct(). + + Use equals(), strictlyEquals() and lessThan() to compare a QScriptValue + to another. + + Object values can have custom data associated with them; see the + setData() and data() functions. By default, this data is not + accessible to scripts; it can be used to store any data you want to + associate with the script object. Typically this is used by custom + class objects (see QScriptClass) to store a C++ type that contains + the "native" object data. + + Note that a QScriptValue for which isObject() is true only carries a + reference to an actual object; copying the QScriptValue will only + copy the object reference, not the object itself. If you want to + clone an object (i.e. copy an object's properties to another + object), you can do so with the help of a \c{for-in} statement in + script code, or QScriptValueIterator in C++. + + \sa QScriptEngine, QScriptValueIterator +*/ + +/*! + \enum QScriptValue::SpecialValue + + This enum is used to specify a single-valued type. + + \value UndefinedValue An undefined value. + + \value NullValue A null value. +*/ + +/*! + \enum QScriptValue::PropertyFlag + + This enum describes the attributes of a property. + + \value ReadOnly The property is read-only. Attempts by Qt Script code to write to the property will be ignored. + + \value Undeletable Attempts by Qt Script code to \c{delete} the property will be ignored. + + \value SkipInEnumeration The property is not to be enumerated by a \c{for-in} enumeration. + + \value PropertyGetter The property is defined by a function which will be called to get the property value. + + \value PropertySetter The property is defined by a function which will be called to set the property value. + + \value QObjectMember This flag is used to indicate that an existing property is a QObject member (a property or method). + + \value KeepExistingFlags This value is used to indicate to setProperty() that the property's flags should be left unchanged. If the property doesn't exist, the default flags (0) will be used. + + \value UserRange Flags in this range are not used by Qt Script, and can be used for custom purposes. +*/ + +/*! + \enum QScriptValue::ResolveFlag + + This enum specifies how to look up a property of an object. + + \value ResolveLocal Only check the object's own properties. + + \value ResolvePrototype Check the object's own properties first, then search the prototype chain. This is the default. + + \value ResolveScope Check the object's own properties first, then search the scope chain. + + \value ResolveFull Check the object's own properties first, then search the prototype chain, and finally search the scope chain. +*/ + +/*! + Constructs an invalid QScriptValue. +*/ +QScriptValue::QScriptValue() + : d_ptr(0) +{ +} + +/*! + Destroys this QScriptValue. +*/ +QScriptValue::~QScriptValue() +{ + if (d_ptr && !d_ptr->ref.deref()) { + if (engine()) { + QScriptEnginePrivate::get(engine())->unregisterValue(d_ptr); + } else { + delete d_ptr; + } + d_ptr = 0; + } +} + +/*! + Constructs a new QScriptValue that is a copy of \a other. + + Note that if \a other is an object (i.e., isObject() would return + true), then only a reference to the underlying object is copied into + the new script value (i.e., the object itself is not copied). +*/ +QScriptValue::QScriptValue(const QScriptValue &other) + : d_ptr(other.d_ptr) +{ + if (d_ptr) + d_ptr->ref.ref(); +} + +/*! + \obsolete + + Constructs a new QScriptValue with the special \a value and + registers it with the script \a engine. +*/ +QScriptValue::QScriptValue(QScriptEngine *engine, QScriptValue::SpecialValue value) +{ + if (engine) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + d_ptr = eng_p->registerValue(QScriptValueImpl(value)); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \obsolete + + \fn QScriptValue::QScriptValue(QScriptEngine *engine, bool value) + + Constructs a new QScriptValue with the boolean \a value and + registers it with the script \a engine. +*/ +QScriptValue::QScriptValue(QScriptEngine *engine, bool val) +{ + if (engine) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + d_ptr = eng_p->registerValue(QScriptValueImpl(val)); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \fn QScriptValue::QScriptValue(QScriptEngine *engine, int value) + \obsolete + + Constructs a new QScriptValue with the integer \a value and + registers it with the script \a engine. +*/ +QScriptValue::QScriptValue(QScriptEngine *engine, int val) +{ + if (engine) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + d_ptr = eng_p->registerValue(QScriptValueImpl(val)); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \fn QScriptValue::QScriptValue(QScriptEngine *engine, uint value) + \obsolete + + Constructs a new QScriptValue with the unsigned integer \a value and + registers it with the script \a engine. + */ +QScriptValue::QScriptValue(QScriptEngine *engine, uint val) +{ + if (engine) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + d_ptr = eng_p->registerValue(QScriptValueImpl(val)); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \fn QScriptValue::QScriptValue(QScriptEngine *engine, qsreal value) + \obsolete + + Constructs a new QScriptValue with the qsreal \a value and + registers it with the script \a engine. +*/ +QScriptValue::QScriptValue(QScriptEngine *engine, qsreal val) +{ + if (engine) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + d_ptr = eng_p->registerValue(QScriptValueImpl(val)); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \fn QScriptValue::QScriptValue(QScriptEngine *engine, const QString &value) + \obsolete + + Constructs a new QScriptValue with the string \a value and + registers it with the script \a engine. +*/ +QScriptValue::QScriptValue(QScriptEngine *engine, const QString &val) +{ + if (engine) { + QScriptValueImpl v; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + eng_p->newString(&v, val); + d_ptr = eng_p->registerValue(v); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} + +/*! + \fn QScriptValue::QScriptValue(QScriptEngine *engine, const char *value) + \obsolete + + Constructs a new QScriptValue with the string \a value and + registers it with the script \a engine. +*/ + +#ifndef QT_NO_CAST_FROM_ASCII +QScriptValue::QScriptValue(QScriptEngine *engine, const char *val) +{ + if (engine) { + QScriptValueImpl v; + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine); + eng_p->newString(&v, QString::fromAscii(val)); + d_ptr = eng_p->registerValue(v); + d_ptr->ref.ref(); + } else { + d_ptr = 0; + } +} +#endif + +/*! + \since 4.5 + + Constructs a new QScriptValue with a special \a value. +*/ +QScriptValue::QScriptValue(SpecialValue value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value = QScriptValueImpl(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a boolean \a value. +*/ +QScriptValue::QScriptValue(bool value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value = QScriptValueImpl(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a number \a value. +*/ +QScriptValue::QScriptValue(int value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value = QScriptValueImpl(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a number \a value. +*/ +QScriptValue::QScriptValue(uint value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value = QScriptValueImpl(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a number \a value. +*/ +QScriptValue::QScriptValue(qsreal value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value = QScriptValueImpl(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a string \a value. +*/ +QScriptValue::QScriptValue(const QString &value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value.m_type = QScript::LazyStringType; + d_ptr->value.m_lazy_string_value = new QString(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a string \a value. +*/ +QScriptValue::QScriptValue(const QLatin1String &value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value.m_type = QScript::LazyStringType; + d_ptr->value.m_lazy_string_value = new QString(value); + d_ptr->ref.ref(); +} + +/*! + \since 4.5 + + Constructs a new QScriptValue with a string \a value. +*/ + +#ifndef QT_NO_CAST_FROM_ASCII +QScriptValue::QScriptValue(const char *value) + : d_ptr(new QScriptValuePrivate) +{ + d_ptr->value.m_type = QScript::LazyStringType; + d_ptr->value.m_lazy_string_value = new QString(QString::fromAscii(value)); + d_ptr->ref.ref(); +} +#endif + +/*! + Assigns the \a other value to this QScriptValue. + + Note that if \a other is an object (isObject() returns true), + only a reference to the underlying object will be assigned; + the object itself will not be copied. +*/ +QScriptValue &QScriptValue::operator=(const QScriptValue &other) +{ + if (d_ptr == other.d_ptr) + return *this; + if (d_ptr && !d_ptr->ref.deref()) { + if (engine()) { + QScriptEnginePrivate::get(engine())->unregisterValue(d_ptr); + } else { + delete d_ptr; + } + } + d_ptr = other.d_ptr; + if (d_ptr) + d_ptr->ref.ref(); + return *this; +} + +/*! + Returns true if this QScriptValue is an object of the Error class; + otherwise returns false. + + \sa QScriptContext::throwError() +*/ +bool QScriptValue::isError() const +{ + Q_D(const QScriptValue); + return d && d->value.isError(); +} + +/*! + Returns true if this QScriptValue is an object of the Array class; + otherwise returns false. + + \sa QScriptEngine::newArray() +*/ +bool QScriptValue::isArray() const +{ + Q_D(const QScriptValue); + return d && d->value.isArray(); +} + +/*! + Returns true if this QScriptValue is an object of the Date class; + otherwise returns false. + + \sa QScriptEngine::newDate() +*/ +bool QScriptValue::isDate() const +{ + Q_D(const QScriptValue); + return d && d->value.isDate(); +} + +/*! + Returns true if this QScriptValue is an object of the RegExp class; + otherwise returns false. + + \sa QScriptEngine::newRegExp() +*/ +bool QScriptValue::isRegExp() const +{ + Q_D(const QScriptValue); + return d && d->value.isRegExp(); +} + +/*! + If this QScriptValue is an object, returns the internal prototype + (\c{__proto__} property) of this object; otherwise returns an + invalid QScriptValue. + + \sa setPrototype(), isObject() +*/ +QScriptValue QScriptValue::prototype() const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.prototype()); +} + +/*! + If this QScriptValue is an object, sets the internal prototype + (\c{__proto__} property) of this object to be \a prototype; + otherwise does nothing. + + The internal prototype should not be confused with the public + property with name "prototype"; the public prototype is usually + only set on functions that act as constructors. + + \sa prototype(), isObject() +*/ +void QScriptValue::setPrototype(const QScriptValue &prototype) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + if (prototype.isValid() && prototype.engine() + && (prototype.engine() != engine())) { + qWarning("QScriptValue::setPrototype() failed: " + "cannot set a prototype created in " + "a different engine"); + return; + } + QScriptValueImpl was = d->value.prototype(); + d->value.setPrototype(d->value.engine()->toImpl(prototype)); + if (d->value.detectedCycle()) { + qWarning("QScriptValue::setPrototype() failed: " + "cyclic prototype value"); + d->value.setPrototype(was); + } +} + +/*! + Returns the scope object of this QScriptValue. This function is only + relevant for function objects. The scope determines how variables are + resolved when the function is invoked. +*/ +QScriptValue QScriptValue::scope() const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.scope()); +} + +/*! + Sets the \a scope object of this QScriptValue. This function is only + relevant for function objects. Changing the scope is useful when creating + closures; see \l{Nested Functions and the Scope Chain}. +*/ +void QScriptValue::setScope(const QScriptValue &scope) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + if (scope.isValid() && scope.engine() + && (scope.engine() != engine())) { + qWarning("QScriptValue::setScope() failed: " + "cannot set a scope object created in " + "a different engine"); + return; + } + d->value.setScope(d->value.engine()->toImpl(scope)); +} + +/*! + Returns true if this QScriptValue is an instance of + \a other; otherwise returns false. + + This QScriptValue is considered to be an instance of \a other if + \a other is a function and the value of the \c{prototype} + property of \a other is in the prototype chain of this + QScriptValue. +*/ +bool QScriptValue::instanceOf(const QScriptValue &other) const +{ + Q_D(const QScriptValue); + if (!isObject() || !other.isObject()) + return false; + if (other.engine() != engine()) { + qWarning("QScriptValue::instanceof: " + "cannot perform operation on a value created in " + "a different engine"); + return false; + } + return d->value.engine()->toImpl(*this) + .instanceOf(d->value.engine()->toImpl(other)); +} + +/*! + Returns true if this QScriptValue is less than \a other, otherwise + returns false. The comparison follows the behavior described in + \l{ECMA-262} section 11.8.5, "The Abstract Relational Comparison + Algorithm". + + Note that if this QScriptValue or the \a other value are objects, + calling this function has side effects on the script engine, since + the engine will call the object's valueOf() function (and possibly + toString()) in an attempt to convert the object to a primitive value + (possibly resulting in an uncaught script exception). + + \sa equals() +*/ +bool QScriptValue::lessThan(const QScriptValue &other) const +{ + if (!isValid() || !other.isValid()) + return false; + if (other.engine() && engine() && (other.engine() != engine())) { + qWarning("QScriptValue::lessThan: " + "cannot compare to a value created in " + "a different engine"); + return false; + } + return QScriptEnginePrivate::lessThan(QScriptValuePrivate::valueOf(*this), + QScriptValuePrivate::valueOf(other)); +} + +/*! + Returns true if this QScriptValue is equal to \a other, otherwise + returns false. The comparison follows the behavior described in + \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison + Algorithm". + + This function can return true even if the type of this QScriptValue + is different from the type of the \a other value; i.e. the + comparison is not strict. For example, comparing the number 9 to + the string "9" returns true; comparing an undefined value to a null + value returns true; comparing a \c{Number} object whose primitive + value is 6 to a \c{String} object whose primitive value is "6" + returns true; and comparing the number 1 to the boolean value + \c{true} returns true. If you want to perform a comparison + without such implicit value conversion, use strictlyEquals(). + + Note that if this QScriptValue or the \a other value are objects, + calling this function has side effects on the script engine, since + the engine will call the object's valueOf() function (and possibly + toString()) in an attempt to convert the object to a primitive value + (possibly resulting in an uncaught script exception). + + \sa strictlyEquals(), lessThan() +*/ +bool QScriptValue::equals(const QScriptValue &other) const +{ + if (!isValid() || !other.isValid()) + return isValid() == other.isValid(); + if (other.engine() && engine() && (other.engine() != engine())) { + qWarning("QScriptValue::equals: " + "cannot compare to a value created in " + "a different engine"); + return false; + } + return QScriptEnginePrivate::equals(QScriptValuePrivate::valueOf(*this), + QScriptValuePrivate::valueOf(other)); +} + +/*! + Returns true if this QScriptValue is equal to \a other using strict + comparison (no conversion), otherwise returns false. The comparison + follows the behavior described in \l{ECMA-262} section 11.9.6, "The + Strict Equality Comparison Algorithm". + + If the type of this QScriptValue is different from the type of the + \a other value, this function returns false. If the types are equal, + the result depends on the type, as shown in the following table: + + \table + \header \o Type \o Result + \row \o Undefined \o true + \row \o Null \o true + \row \o Boolean \o true if both values are true, false otherwise + \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise + \row \o String \o true if both values are exactly the same sequence of characters, false otherwise + \row \o Object \o true if both values refer to the same object, false otherwise + \endtable + + \sa equals() +*/ +bool QScriptValue::strictlyEquals(const QScriptValue &other) const +{ + if (!isValid() || !other.isValid()) + return isValid() == other.isValid(); + if (other.engine() && engine() && (other.engine() != engine())) { + qWarning("QScriptValue::strictlyEquals: " + "cannot compare to a value created in " + "a different engine"); + return false; + } + return QScriptEnginePrivate::strictlyEquals(QScriptValuePrivate::valueOf(*this), + QScriptValuePrivate::valueOf(other)); +} + +/*! + Returns the string value of this QScriptValue, as defined in + \l{ECMA-262} section 9.8, "ToString". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's toString() function (and possibly valueOf()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isString() +*/ +QString QScriptValue::toString() const +{ + Q_D(const QScriptValue); + if (!d) + return QString(); + return d->value.toString(); +} + +/*! + Returns the number value of this QScriptValue, as defined in + \l{ECMA-262} section 9.3, "ToNumber". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16() +*/ +qsreal QScriptValue::toNumber() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toNumber(); +} + +/*! + \obsolete + + Use toBool() instead. +*/ +bool QScriptValue::toBoolean() const +{ + Q_D(const QScriptValue); + if (!d) + return false; + return d->value.toBoolean(); +} + +/*! + \since 4.5 + + Returns the boolean value of this QScriptValue, using the conversion + rules described in \l{ECMA-262} section 9.2, "ToBoolean". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isBool() +*/ +bool QScriptValue::toBool() const +{ + Q_D(const QScriptValue); + if (!d) + return false; + return d->value.toBoolean(); +} + +/*! + Returns the signed 32-bit integer value of this QScriptValue, using + the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toUInt32() +*/ +qint32 QScriptValue::toInt32() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toInt32(); +} + +/*! + Returns the unsigned 32-bit integer value of this QScriptValue, using + the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toInt32() +*/ +quint32 QScriptValue::toUInt32() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toUInt32(); +} + +/*! + Returns the unsigned 16-bit integer value of this QScriptValue, using + the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber() +*/ +quint16 QScriptValue::toUInt16() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toUInt16(); +} + +/*! + Returns the integer value of this QScriptValue, using the conversion + rules described in \l{ECMA-262} section 9.4, "ToInteger". + + Note that if this QScriptValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber() +*/ +qsreal QScriptValue::toInteger() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toInteger(); +} + +/*! + Returns the QVariant value of this QScriptValue, if it can be + converted to a QVariant; otherwise returns an invalid QVariant. + The conversion is performed according to the following table: + + \table + \header \o Input Type \o Result + \row \o Undefined \o An invalid QVariant. + \row \o Null \o An invalid QVariant. + \row \o Boolean \o A QVariant containing the value of the boolean. + \row \o Number \o A QVariant containing the value of the number. + \row \o String \o A QVariant containing the value of the string. + \row \o QVariant Object \o The result is the QVariant value of the object (no conversion). + \row \o QObject Object \o A QVariant containing a pointer to the QObject. + \row \o Date Object \o A QVariant containing the date value (toDateTime()). + \row \o RegExp Object \o A QVariant containing the regular expression value (toRegExp()). + \row \o Object \o If the value is primitive, then the result is converted to a QVariant according to the above rules; otherwise, an invalid QVariant is returned. + \endtable + + \sa isVariant() +*/ +QVariant QScriptValue::toVariant() const +{ + Q_D(const QScriptValue); + if (!d) + return QVariant(); + return d->value.toVariant(); +} + +/*! + \obsolete + + This function is obsolete; use QScriptEngine::toObject() instead. +*/ +QScriptValue QScriptValue::toObject() const +{ + Q_D(const QScriptValue); + if (!d) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + if (!eng) + return QScriptValue(); + return eng->toPublic(eng->toObject(d->value)); +} + +/*! + Returns a QDateTime representation of this value, in local time. + If this QScriptValue is not a date, or the value of the date is NaN + (Not-a-Number), an invalid QDateTime is returned. + + \sa isDate() +*/ +QDateTime QScriptValue::toDateTime() const +{ + Q_D(const QScriptValue); + if (!d) + return QDateTime(); + return d->value.toDateTime(); +} + +#ifndef QT_NO_REGEXP +/*! + Returns the QRegExp representation of this value. + If this QScriptValue is not a regular expression, an empty + QRegExp is returned. + + \sa isRegExp() +*/ +QRegExp QScriptValue::toRegExp() const +{ + Q_D(const QScriptValue); + if (!d) + return QRegExp(); + return d->value.toRegExp(); +} +#endif // QT_NO_REGEXP + +/*! + If this QScriptValue is a QObject, returns the QObject pointer + that the QScriptValue represents; otherwise, returns 0. + + If the QObject that this QScriptValue wraps has been deleted, + this function returns 0 (i.e. it is possible for toQObject() + to return 0 even when isQObject() returns true). + + \sa isQObject() +*/ +QObject *QScriptValue::toQObject() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toQObject(); +} + +/*! + If this QScriptValue is a QMetaObject, returns the QMetaObject pointer + that the QScriptValue represents; otherwise, returns 0. + + \sa isQMetaObject() +*/ +const QMetaObject *QScriptValue::toQMetaObject() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.toQMetaObject(); +} + +/*! + Sets the value of this QScriptValue's property with the given \a name to + the given \a value. + + If this QScriptValue is not an object, this function does nothing. + + If this QScriptValue does not already have a property with name \a name, + a new property is created; the given \a flags then specify how this + property may be accessed by script code. + + If \a value is invalid, the property is removed. + + If the property is implemented using a setter function (i.e. has the + PropertySetter flag set), calling setProperty() has side-effects on + the script engine, since the setter function will be called with the + given \a value as argument (possibly resulting in an uncaught script + exception). + + Note that you cannot specify custom getter or setter functions for + built-in properties, such as the \c{length} property of Array objects + or meta properties of QObject objects. + + \sa property() +*/ +void QScriptValue::setProperty(const QString &name, const QScriptValue &value, + const PropertyFlags &flags) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + if (value.engine() && (value.engine() != engine())) { + qWarning("QScriptValue::setProperty(%s) failed: " + "cannot set value created in a different engine", + qPrintable(name)); + return; + } + d->value.setProperty(name, d->value.engine()->toImpl(value), flags); +} + +/*! + Returns the value of this QScriptValue's property with the given \a name, + using the given \a mode to resolve the property. + + If no such property exists, an invalid QScriptValue is returned. + + If the property is implemented using a getter function (i.e. has the + PropertyGetter flag set), calling property() has side-effects on the + script engine, since the getter function will be called (possibly + resulting in an uncaught script exception). If an exception + occurred, property() returns the value that was thrown (typically + an \c{Error} object). + + \sa setProperty(), propertyFlags(), QScriptValueIterator +*/ +QScriptValue QScriptValue::property(const QString &name, + const ResolveFlags &mode) const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.property(name, mode)); +} + +/*! + \overload + + Returns the property at the given \a arrayIndex, using the given \a + mode to resolve the property. + + This function is provided for convenience and performance when + working with array objects. + + If this QScriptValue is not an Array object, this function behaves + as if property() was called with the string representation of \a + arrayIndex. +*/ +QScriptValue QScriptValue::property(quint32 arrayIndex, + const ResolveFlags &mode) const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.property(arrayIndex, mode)); +} + +/*! + \overload + + Sets the property at the given \a arrayIndex to the given \a value. + + This function is provided for convenience and performance when + working with array objects. + + If this QScriptValue is not an Array object, this function behaves + as if setProperty() was called with the string representation of \a + arrayIndex. +*/ +void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue &value, + const PropertyFlags &flags) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + if (value.engine() && (value.engine() != engine())) { + qWarning("QScriptValue::setProperty() failed: " + "cannot set value created in a different engine"); + return; + } + d->value.setProperty(arrayIndex, d->value.engine()->toImpl(value), flags); +} + +/*! + \since 4.4 + + Returns the value of this QScriptValue's property with the given \a name, + using the given \a mode to resolve the property. + + This overload of property() is useful when you need to look up the + same property repeatedly, since the lookup can be performed faster + when the name is represented as an interned string. + + \sa QScriptEngine::toStringHandle(), setProperty() +*/ +QScriptValue QScriptValue::property(const QScriptString &name, + const ResolveFlags &mode) const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + if (!name.isValid()) + return QScriptValue(); + QScriptStringPrivate *s = QScriptStringPrivate::get(name); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.property(s->nameId, mode)); +} + +/*! + \since 4.4 + + Sets the value of this QScriptValue's property with the given \a + name to the given \a value. The given \a flags specify how this + property may be accessed by script code. + + This overload of setProperty() is useful when you need to set the + same property repeatedly, since the operation can be performed + faster when the name is represented as an interned string. + + \sa QScriptEngine::toStringHandle() +*/ +void QScriptValue::setProperty(const QScriptString &name, + const QScriptValue &value, + const PropertyFlags &flags) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject() || !name.isValid()) + return; + if (value.engine() && (value.engine() != engine())) { + qWarning("QScriptValue::setProperty() failed: " + "cannot set value created in a different engine"); + return; + } + QScriptStringPrivate *s = QScriptStringPrivate::get(name); + d->value.setProperty(s->nameId, d->value.engine()->toImpl(value), flags); +} + +/*! + Returns the flags of the property with the given \a name, using the + given \a mode to resolve the property. + + \sa property() +*/ +QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString &name, + const ResolveFlags &mode) const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->value.propertyFlags(name, mode); +} + +/*! + \since 4.4 + + Returns the flags of the property with the given \a name, using the + given \a mode to resolve the property. + + \sa property() +*/ +QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString &name, + const ResolveFlags &mode) const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + if (!name.isValid()) + return 0; + QScriptStringPrivate *s = QScriptStringPrivate::get(name); + return d->value.propertyFlags(s->nameId, mode); +} + +/*! + Calls this QScriptValue as a function, using \a thisObject as + the `this' object in the function call, and passing \a args + as arguments to the function. Returns the value returned from + the function. + + If this QScriptValue is not a function, call() does nothing + and returns an invalid QScriptValue. + + Note that if \a thisObject is not an object, the global object + (see \l{QScriptEngine::globalObject()}) will be used as the + `this' object. + + Calling call() can cause an exception to occur in the script engine; + in that case, call() returns the value that was thrown (typically an + \c{Error} object). You can call + QScriptEngine::hasUncaughtException() to determine if an exception + occurred. + + \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 2 + + \sa construct() +*/ +QScriptValue QScriptValue::call(const QScriptValue &thisObject, + const QScriptValueList &args) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + if (isFunction() && thisObject.isValid() && thisObject.engine() && + engine() && (thisObject.engine() != engine())) { + qWarning("QScriptValue::call() failed: " + "cannot call function with thisObject created in " + "a different engine"); + return QScriptValue(); + } + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.call(eng->toImpl(thisObject), + eng->toImplList(args))); +} + +/*! + Calls this QScriptValue as a function, using \a thisObject as + the `this' object in the function call, and passing \a arguments + as arguments to the function. Returns the value returned from + the function. + + If this QScriptValue is not a function, call() does nothing + and returns an invalid QScriptValue. + + \a arguments can be an arguments object, an array, null or + undefined; any other type will cause a TypeError to be thrown. + + Note that if \a thisObject is not an object, the global object + (see \l{QScriptEngine::globalObject()}) will be used as the + `this' object. + + One common usage of this function is to forward native function + calls to another function: + + \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 3 + + \sa construct(), QScriptContext::argumentsObject() +*/ +QScriptValue QScriptValue::call(const QScriptValue &thisObject, + const QScriptValue &arguments) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + if (isFunction() && thisObject.isValid() && thisObject.engine() + && (thisObject.engine() != engine())) { + qWarning("QScriptValue::call() failed: " + "cannot call function with thisObject created in " + "a different engine"); + return QScriptValue(); + } + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.call(eng->toImpl(thisObject), + eng->toImpl(arguments))); +} + +/*! + Creates a new \c{Object} and calls this QScriptValue as a + constructor, using the created object as the `this' object and + passing \a args as arguments. If the return value from the + constructor call is an object, then that object is returned; + otherwise the default constructed object is returned. + + If this QScriptValue is not a function, construct() does nothing + and returns an invalid QScriptValue. + + Calling construct() can cause an exception to occur in the script + engine; in that case, construct() returns the value that was thrown + (typically an \c{Error} object). You can call + QScriptEngine::hasUncaughtException() to determine if an exception + occurred. + + \sa call(), QScriptEngine::newObject() +*/ +QScriptValue QScriptValue::construct(const QScriptValueList &args) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.construct(eng->toImplList(args))); +} + +/*! + Creates a new \c{Object} and calls this QScriptValue as a + constructor, using the created object as the `this' object and + passing \a arguments as arguments. If the return value from the + constructor call is an object, then that object is returned; + otherwise the default constructed object is returned. + + If this QScriptValue is not a function, construct() does nothing + and returns an invalid QScriptValue. + + \a arguments can be an arguments object, an array, null or + undefined. Any other type will cause a TypeError to be thrown. + + \sa call(), QScriptEngine::newObject(), QScriptContext::argumentsObject() +*/ +QScriptValue QScriptValue::construct(const QScriptValue &arguments) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.construct(eng->toImpl(arguments))); +} + +/*! + Returns the QScriptEngine that created this QScriptValue, + or 0 if this QScriptValue is invalid or the value is not + associated with a particular engine. +*/ +QScriptEngine *QScriptValue::engine() const +{ + Q_D(const QScriptValue); + if (!d) + return 0; + return d->engine; +} + +/*! + \obsolete + + Use isBool() instead. +*/ +bool QScriptValue::isBoolean() const +{ + Q_D(const QScriptValue); + return d && d->value.isBoolean(); +} + +/*! + \since 4.5 + + Returns true if this QScriptValue is of the primitive type Boolean; + otherwise returns false. + + \sa toBool() +*/ +bool QScriptValue::isBool() const +{ + Q_D(const QScriptValue); + return d && d->value.isBoolean(); +} + +/*! + Returns true if this QScriptValue is of the primitive type Number; + otherwise returns false. + + \sa toNumber() +*/ +bool QScriptValue::isNumber() const +{ + Q_D(const QScriptValue); + return d && d->value.isNumber(); +} + +/*! + Returns true if this QScriptValue is of the primitive type String; + otherwise returns false. + + \sa toString() +*/ +bool QScriptValue::isString() const +{ + Q_D(const QScriptValue); + return d && d->value.isString(); +} + +/*! + Returns true if this QScriptValue is a function; otherwise returns + false. + + \sa call() +*/ +bool QScriptValue::isFunction() const +{ + Q_D(const QScriptValue); + return d && d->value.isFunction(); +} + +/*! + Returns true if this QScriptValue is of the primitive type Null; + otherwise returns false. + + \sa QScriptEngine::nullValue() +*/ +bool QScriptValue::isNull() const +{ + Q_D(const QScriptValue); + return d && d->value.isNull(); +} + +/*! + Returns true if this QScriptValue is of the primitive type Undefined; + otherwise returns false. + + \sa QScriptEngine::undefinedValue() +*/ +bool QScriptValue::isUndefined() const +{ + Q_D(const QScriptValue); + return d && d->value.isUndefined(); +} + +/*! + Returns true if this QScriptValue is of the Object type; otherwise + returns false. + + Note that function values, variant values, and QObject values are + objects, so this function returns true for such values. + + \sa toObject(), QScriptEngine::newObject() +*/ +bool QScriptValue::isObject() const +{ + Q_D(const QScriptValue); + return d && d->value.isObject(); +} + +/*! + Returns true if this QScriptValue is a variant value; + otherwise returns false. + + \sa toVariant(), QScriptEngine::newVariant() +*/ +bool QScriptValue::isVariant() const +{ + Q_D(const QScriptValue); + return d && d->value.isVariant(); +} + +/*! + Returns true if this QScriptValue is a QObject; otherwise returns + false. + + Note: This function returns true even if the QObject that this + QScriptValue wraps has been deleted. + + \sa toQObject(), QScriptEngine::newQObject() +*/ +bool QScriptValue::isQObject() const +{ + Q_D(const QScriptValue); + return d && d->value.isQObject(); +} + +/*! + Returns true if this QScriptValue is a QMetaObject; otherwise returns + false. + + \sa toQMetaObject(), QScriptEngine::newQMetaObject() +*/ +bool QScriptValue::isQMetaObject() const +{ + Q_D(const QScriptValue); + return d && d->value.isQMetaObject(); +} + +/*! + Returns true if this QScriptValue is valid; otherwise returns + false. +*/ +bool QScriptValue::isValid() const +{ + Q_D(const QScriptValue); + return d && d->value.isValid(); +} + +/*! + \since 4.4 + + Returns the internal data of this QScriptValue object. QtScript uses + this property to store the primitive value of Date, String, Number + and Boolean objects. For other types of object, custom data may be + stored using setData(). +*/ +QScriptValue QScriptValue::data() const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return QScriptValue(); + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + return eng->toPublic(d->value.internalValue()); +} + +/*! + \since 4.4 + + Sets the internal \a data of this QScriptValue object. You can use + this function to set object-specific data that won't be directly + accessible to scripts, but may be retrieved in C++ using the data() + function. +*/ +void QScriptValue::setData(const QScriptValue &data) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + QScriptEnginePrivate *eng = QScriptEnginePrivate::get(engine()); + d->value.setInternalValue(eng->toImpl(data)); +} + +/*! + \since 4.4 + + Returns the custom script class that this script object is an + instance of, or 0 if the object is not of a custom class. + + \sa setScriptClass() +*/ +QScriptClass *QScriptValue::scriptClass() const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return 0; + QScriptClassInfo *info = d->value.classInfo(); + if ((info->type() & QScriptClassInfo::TypeMask) < QScriptClassInfo::CustomType) + return 0; + return QScriptClassPrivate::classFromInfo(info); +} + +/*! + \since 4.4 + + Sets the custom script class of this script object to \a scriptClass. + This can be used to "promote" a plain script object (e.g. created + by the "new" operator in a script, or by QScriptEngine::newObject() in C++) + to an object of a custom type. + + If \a scriptClass is 0, the object will be demoted to a plain + script object. + + \sa scriptClass(), setData() +*/ +void QScriptValue::setScriptClass(QScriptClass *scriptClass) +{ + Q_D(QScriptValue); + if (!d || !d->value.isObject()) + return; + if (!scriptClass) { + QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine()); + d->value.setClassInfo(eng_p->m_class_object); + } else { + QScriptClassPrivate *cls_p = QScriptClassPrivate::get(scriptClass); + d->value.setClassInfo(cls_p->classInfo()); + } +} + +/*! + \internal + + Returns the ID of this object, or -1 if this QScriptValue is not an + object. + + \sa QScriptEngine::objectById() +*/ +qint64 QScriptValue::objectId() const +{ + Q_D(const QScriptValue); + if (!d || !d->value.isObject()) + return -1; + return d->value.m_object_value->m_id; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptvalue.h b/src/script/qscriptvalue.h new file mode 100644 index 0000000..306da53 --- /dev/null +++ b/src/script/qscriptvalue.h @@ -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 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 QSCRIPTVALUE_H +#define QSCRIPTVALUE_H + +#include <QtCore/qstring.h> + +#ifndef QT_NO_SCRIPT + +#include <QtCore/qlist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptClass; +class QScriptValue; +class QScriptEngine; +class QScriptString; +class QVariant; +class QObject; +struct QMetaObject; +class QDateTime; +#ifndef QT_NO_REGEXP +class QRegExp; +#endif + +typedef QList<QScriptValue> QScriptValueList; + +typedef double qsreal; + +class QScriptValuePrivate; +class Q_SCRIPT_EXPORT QScriptValue +{ +public: + enum ResolveFlag { + ResolveLocal = 0x00, + ResolvePrototype = 0x01, + ResolveScope = 0x02, + ResolveFull = ResolvePrototype | ResolveScope + }; + + Q_DECLARE_FLAGS(ResolveFlags, ResolveFlag) + + enum PropertyFlag { + ReadOnly = 0x00000001, + Undeletable = 0x00000002, + SkipInEnumeration = 0x00000004, + + PropertyGetter = 0x00000008, + PropertySetter = 0x00000010, + + QObjectMember = 0x00000020, + + KeepExistingFlags = 0x00000800, + + UserRange = 0xff000000 // Users may use these as they see fit. + }; + Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag) + + enum SpecialValue { + NullValue, + UndefinedValue + }; + +public: + QScriptValue(); + ~QScriptValue(); + QScriptValue(const QScriptValue &other); + QScriptValue(QScriptEngine *engine, SpecialValue val); + QScriptValue(QScriptEngine *engine, bool val); + QScriptValue(QScriptEngine *engine, int val); + QScriptValue(QScriptEngine *engine, uint val); + QScriptValue(QScriptEngine *engine, qsreal val); + QScriptValue(QScriptEngine *engine, const QString &val); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN_CONSTRUCTOR QScriptValue(QScriptEngine *engine, const char *val); +#endif + + QScriptValue(SpecialValue value); + QScriptValue(bool value); + QScriptValue(int value); + QScriptValue(uint value); + QScriptValue(qsreal value); + QScriptValue(const QString &value); + QScriptValue(const QLatin1String &value); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN_CONSTRUCTOR QScriptValue(const char *value); +#endif + + QScriptValue &operator=(const QScriptValue &other); + + QScriptEngine *engine() const; + + bool isValid() const; + bool isBool() const; + bool isBoolean() const; + bool isNumber() const; + bool isFunction() const; + bool isNull() const; + bool isString() const; + bool isUndefined() const; + bool isVariant() const; + bool isQObject() const; + bool isQMetaObject() const; + bool isObject() const; + bool isDate() const; + bool isRegExp() const; + bool isArray() const; + bool isError() const; + + QString toString() const; + qsreal toNumber() const; + bool toBool() const; + bool toBoolean() const; + qsreal toInteger() const; + qint32 toInt32() const; + quint32 toUInt32() const; + quint16 toUInt16() const; + QVariant toVariant() const; + QObject *toQObject() const; + const QMetaObject *toQMetaObject() const; + QScriptValue toObject() const; + QDateTime toDateTime() const; +#ifndef QT_NO_REGEXP + QRegExp toRegExp() const; +#endif + + bool instanceOf(const QScriptValue &other) const; + + bool lessThan(const QScriptValue &other) const; + bool equals(const QScriptValue &other) const; + bool strictlyEquals(const QScriptValue &other) const; + + QScriptValue prototype() const; + void setPrototype(const QScriptValue &prototype); + + QScriptValue scope() const; + void setScope(const QScriptValue &scope); + + QScriptValue property(const QString &name, + const ResolveFlags &mode = ResolvePrototype) const; + void setProperty(const QString &name, const QScriptValue &value, + const PropertyFlags &flags = KeepExistingFlags); + + QScriptValue property(quint32 arrayIndex, + const ResolveFlags &mode = ResolvePrototype) const; + void setProperty(quint32 arrayIndex, const QScriptValue &value, + const PropertyFlags &flags = KeepExistingFlags); + + QScriptValue property(const QScriptString &name, + const ResolveFlags &mode = ResolvePrototype) const; + void setProperty(const QScriptString &name, const QScriptValue &value, + const PropertyFlags &flags = KeepExistingFlags); + + QScriptValue::PropertyFlags propertyFlags( + const QString &name, const ResolveFlags &mode = ResolvePrototype) const; + QScriptValue::PropertyFlags propertyFlags( + const QScriptString &name, const ResolveFlags &mode = ResolvePrototype) const; + + QScriptValue call(const QScriptValue &thisObject = QScriptValue(), + const QScriptValueList &args = QScriptValueList()); + QScriptValue call(const QScriptValue &thisObject, + const QScriptValue &arguments); + QScriptValue construct(const QScriptValueList &args = QScriptValueList()); + QScriptValue construct(const QScriptValue &arguments); + + QScriptValue data() const; + void setData(const QScriptValue &data); + + QScriptClass *scriptClass() const; + void setScriptClass(QScriptClass *scriptClass); + + qint64 objectId() const; + +private: + // force compile error, prevent QScriptValue(bool) to be called + inline QScriptValue(void *) { Q_ASSERT(false); } + // force compile error, prevent QScriptValue(QScriptEngine*, bool) to be called + inline QScriptValue(QScriptEngine *, void *) { Q_ASSERT(false); } + +private: + QScriptValuePrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptValue) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QScriptValue::ResolveFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QScriptValue::PropertyFlags) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptvalue_p.h b/src/script/qscriptvalue_p.h new file mode 100644 index 0000000..8463ed2 --- /dev/null +++ b/src/script/qscriptvalue_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 QSCRIPTVALUE_P_H +#define QSCRIPTVALUE_P_H + +#include "qscriptvaluefwd_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SCRIPT + +// +// 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. +// + +inline QScriptValuePrivate::QScriptValuePrivate() +{ + engine = 0; + ref = 0; +} + +inline QScriptValuePrivate::~QScriptValuePrivate() +{ + if (value.type() == QScript::LazyStringType) + delete value.m_lazy_string_value; +} + +inline QScriptValuePrivate *QScriptValuePrivate::create() +{ + return new QScriptValuePrivate(); +} + +inline QScriptValuePrivate *QScriptValuePrivate::get(const QScriptValue &value) +{ + return const_cast<QScriptValuePrivate*>(value.d_func()); +} + +inline QScriptValueImpl QScriptValuePrivate::valueOf(const QScriptValue &value) +{ + QScriptValuePrivate *p = const_cast<QScriptValuePrivate*>(value.d_func()); + if (!p) + return QScriptValueImpl(); + return p->value; +} + +inline void QScriptValuePrivate::init(QScriptValue &value, QScriptValuePrivate *p) +{ + value.d_ptr = p; + value.d_ptr->ref.ref(); +} + +inline void QScriptValuePrivate::invalidate() +{ + engine = 0; + value.invalidate(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptvaluefwd_p.h b/src/script/qscriptvaluefwd_p.h new file mode 100644 index 0000000..d57786d --- /dev/null +++ b/src/script/qscriptvaluefwd_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 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 QSCRIPTVALUEFWD_P_H +#define QSCRIPTVALUEFWD_P_H + +#include <QtCore/qatomic.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalueimplfwd_p.h" + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptValuePrivate +{ +public: + inline QScriptValuePrivate(); + inline ~QScriptValuePrivate(); + + static inline QScriptValuePrivate *create(); + + static inline QScriptValuePrivate *get(const QScriptValue &value); + + static inline QScriptValueImpl valueOf(const QScriptValue &value); + + static inline void init(QScriptValue &value, QScriptValuePrivate *p); + + inline void invalidate(); + + QScriptEngine *engine; + QScriptValueImpl value; + QBasicAtomicInt ref; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptvalueimpl.cpp b/src/script/qscriptvalueimpl.cpp new file mode 100644 index 0000000..15d1b8a --- /dev/null +++ b/src/script/qscriptvalueimpl.cpp @@ -0,0 +1,448 @@ +/**************************************************************************** +** +** 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 "qscriptvalueimpl_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +static void dfs(QScriptObject *instance, QHash<QScriptObject*, int> &dfn, int n) +{ + bool found = dfn.contains(instance); + dfn[instance] = n; + + if (found) + return; + + if (instance->m_prototype.isObject()) + dfs (instance->m_prototype.m_object_value, dfn, n + 1); + + if (instance->m_scope.isObject()) + dfs (instance->m_scope.m_object_value, dfn, n + 1); +} + + +static bool checkCycle(QScriptObject *instance, const QHash<QScriptObject*, int> &dfn) +{ + int n = dfn.value(instance); + + if (instance->m_prototype.isObject()) { + if (n >= dfn.value(instance->m_prototype.m_object_value)) + return true; + } + + if (instance->m_scope.isObject()) { + if (n >= dfn.value(instance->m_scope.m_object_value)) + return true; + } + + return false; +} + +bool QScriptValueImpl::detectedCycle() const +{ + QHash<QScriptObject*, int> dfn; + dfs(m_object_value, dfn, 0); + return checkCycle(m_object_value, dfn); +} + +bool QScriptValueImpl::instanceOf(const QScriptValueImpl &value) const +{ + if (! isObject() || ! value.isObject() || !value.implementsHasInstance()) + return false; + return value.hasInstance(*this); +} + +bool QScriptValueImpl::implementsHasInstance() const +{ + Q_ASSERT(isObject()); + if (isFunction()) + return true; + if (QScriptClassData *odata = classInfo()->data()) { + return odata->implementsHasInstance(*this); + } + return false; +} + +bool QScriptValueImpl::hasInstance(const QScriptValueImpl &value) const +{ + Q_ASSERT(isObject()); + + if (QScriptClassData *odata = classInfo()->data()) { + if (odata->implementsHasInstance(*this)) + return odata->hasInstance(*this, value); + } + if (!isFunction()) + return false; + + // [[HasInstance] for function objects + + if (!value.isObject()) + return false; + + QScriptEnginePrivate *eng = engine(); + QScriptValueImpl proto = property(eng->idTable()->id_prototype); + if (!proto.isObject()) { + QScriptContextPrivate *ctx = eng->currentContext(); + ctx->throwTypeError(QLatin1String("instanceof: 'prototype' property is not an object")); + return false; + } + + QScriptObject *target = proto.m_object_value; + QScriptValueImpl v = value; + while (true) { + v = v.prototype(); + if (!v.isObject()) + break; + if (target == v.m_object_value) + return true; + } + return false; +} + +bool QScriptValueImpl::resolve_helper(QScriptNameIdImpl *nameId, QScript::Member *member, + QScriptValueImpl *object, QScriptValue::ResolveFlags mode, + QScript::AccessMode access) const +{ + QScriptObject *object_data = m_object_value; + + QScriptEnginePrivate *eng_p = engine(); + + if (nameId == eng_p->idTable()->id___proto__) { + member->native(nameId, /*id=*/0, QScriptValue::Undeletable); + *object = *this; + return true; + } + + // If not found anywhere else, search in the extra members. + if (QScriptClassData *odata = classInfo()->data()) { + *object = *this; + + if (odata->resolve(*this, nameId, member, object, access)) + return true; + } + + if (mode & QScriptValue::ResolvePrototype) { + // For values and other non object based types, search in class's prototype + const QScriptValueImpl &proto = object_data->m_prototype; + + if (proto.isObject() + && proto.resolve(nameId, member, object, mode, access)) { + return true; + } + } + + if ((mode & QScriptValue::ResolveScope) && object_data->m_scope.isValid()) + return object_data->m_scope.resolve(nameId, member, object, mode, access); + + return false; +} + +void QScriptValueImpl::setProperty(QScriptNameIdImpl *nameId, + const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags) +{ + if (!isObject()) + return; + + QScriptValueImpl base; + QScript::Member member; + + QScriptValue::ResolveFlags mode = QScriptValue::ResolveLocal; + // if we are not setting a setter or getter, look in prototype too + if (!(flags & (QScriptValue::PropertyGetter | QScriptValue::PropertySetter))) + mode |= QScriptValue::ResolvePrototype; + + if (resolve(nameId, &member, &base, mode, QScript::ReadWrite)) { + // we resolved an existing property with that name + if (flags & (QScriptValue::PropertyGetter | QScriptValue::PropertySetter)) { + // setting the getter or setter of a property in this object + if (member.isNativeProperty()) { + if (value.isValid()) { + qWarning("QScriptValue::setProperty() failed: " + "cannot set getter or setter of native property `%s'", + qPrintable(nameId->s)); + } + return; + } + if (member.isSetter()) { + // the property we resolved is a setter + if (!(flags & QScriptValue::PropertySetter) && !member.isGetter()) { + // find the getter, if not, create one + if (!m_object_value->findGetter(&member)) { + if (!value.isValid()) + return; // don't create property for invalid value + createMember(nameId, &member, flags); + } + } + } else if (member.isGetter()) { + // the property we resolved is a getter + if (!(flags & QScriptValue::PropertyGetter)) { + // find the setter, if not, create one + if (!m_object_value->findSetter(&member)) { + if (!value.isValid()) + return; // don't create property for invalid value + createMember(nameId, &member, flags); + } + } + } else { + // the property is a normal property -- change the flags + uint newFlags = flags & ~QScript::Member::InternalRange; + newFlags |= QScript::Member::ObjectProperty; + member.resetFlags(newFlags); + base.m_object_value->m_members[member.id()].resetFlags(newFlags); + } + Q_ASSERT(member.isValid()); + if (!value.isValid()) { + // remove the property + removeMember(member); + return; + } + } else { + // setting the value + if (member.isGetterOrSetter()) { + // call the setter + QScriptValueImpl setter; + if (member.isObjectProperty() && !member.isSetter()) { + if (!base.m_object_value->findSetter(&member)) { + qWarning("QScriptValue::setProperty() failed: " + "property '%s' has a getter but no setter", + qPrintable(nameId->s)); + return; + } + } + base.get(member, &setter); + setter.call(*this, QScriptValueImplList() << value); + return; + } else { + if (base.m_object_value != m_object_value) { + if (!value.isValid()) + return; // don't create property for invalid value + createMember(nameId, &member, flags); + base = *this; + } else { + if (!value.isValid()) { + // remove the property + removeMember(member); + return; + } + } + if (flags != QScriptValue::KeepExistingFlags) { + // change flags + if (member.isNativeProperty()) { + qWarning("QScriptValue::setProperty(%s): " + "cannot change flags of a native property", + qPrintable(nameId->s)); + } else { + uint newFlags = member.flags() & QScript::Member::InternalRange; + newFlags |= flags & ~QScript::Member::InternalRange; + base.m_object_value->m_members[member.id()].resetFlags(newFlags); + } + } + } + } + } else { + // property does not exist + if (!value.isValid()) + return; // don't create property for invalid value + createMember(nameId, &member, flags & ~QScript::Member::InternalRange); + base = *this; + } + + base.put(member, value); +} + +QVariant QScriptValueImpl::toVariant() const +{ + switch (m_type) { + case QScript::InvalidType: + return QVariant(); + + case QScript::UndefinedType: + case QScript::NullType: + case QScript::PointerType: + case QScript::ReferenceType: + break; + + case QScript::BooleanType: + return QVariant(m_bool_value); + + case QScript::IntegerType: + return QVariant(m_int_value); + + case QScript::NumberType: + return QVariant(m_number_value); + + case QScript::StringType: + return QVariant(m_string_value->s); + + case QScript::LazyStringType: + return QVariant(*m_lazy_string_value); + + case QScript::ObjectType: + if (isDate()) + return QVariant(toDateTime()); + +#ifndef QT_NO_REGEXP + if (isRegExp()) + return QVariant(toRegExp()); +#endif + if (isVariant()) + return variantValue(); + +#ifndef QT_NO_QOBJECT + if (isQObject()) + return qVariantFromValue(toQObject()); +#endif + + QScriptValueImpl v = engine()->toPrimitive(*this); + if (!v.isObject()) + return v.toVariant(); + break; + } // switch + return QVariant(); +} + +QDebug &operator<<(QDebug &d, const QScriptValueImpl &object) +{ + d.nospace() << "QScriptValue("; + + switch (object.type()) { + case QScript::InvalidType: + d.nospace() << "Invalid)"; + return d; + + case QScript::BooleanType: + d.nospace() << "bool=" << object.toBoolean(); + break; + + case QScript::IntegerType: + d.nospace() << "int=" << object.toInt32(); + break; + + case QScript::NumberType: + d.nospace() << "qsreal=" << object.toNumber(); + break; + + case QScript::LazyStringType: + case QScript::StringType: + d.nospace() << "string=" << object.toString(); + break; + + case QScript::ReferenceType: + d.nospace() << "reference"; + break; + + case QScript::NullType: + d.nospace() << "null"; + break; + + case QScript::UndefinedType: + d.nospace() << "undefined"; + break; + + case QScript::PointerType: + d.nospace() << "pointer"; + break; + + case QScript::ObjectType: + d.nospace() << object.classInfo()->name() << ",{"; + QScriptObject *od = object.objectValue(); + for (int i=0; i<od->memberCount(); ++i) { + if (i != 0) + d << ","; + + QScript::Member m; + od->member(i, &m); + + if (m.isValid() && m.isObjectProperty()) { + d << object.engine()->toString(m.nameId()); + QScriptValueImpl o; + od->get(m, &o); + d.nospace() << QLatin1String(":") + << (o.classInfo() + ? o.classInfo()->name() + : QLatin1String("?")); + } + } + + d.nospace() << "} scope={"; + QScriptValueImpl scope = object.scope(); + while (scope.isValid()) { + Q_ASSERT(scope.isObject()); + d.nospace() << " " << scope.objectValue(); + scope = scope.scope(); + } + d.nospace() << "}"; + break; + } + + d << ")"; + return d; +} + +void QScriptValueImpl::destroyObjectData() +{ + Q_ASSERT(isObject()); + m_object_value->finalizeData(); +} + +bool QScriptValueImpl::isMarked(int generation) const +{ + if (isString()) + return (m_string_value->used != 0); + else if (isObject()) { + QScript::GCBlock *block = QScript::GCBlock::get(m_object_value); + return (block->generation == generation); + } + return false; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptvalueimpl_p.h b/src/script/qscriptvalueimpl_p.h new file mode 100644 index 0000000..09dd6cd --- /dev/null +++ b/src/script/qscriptvalueimpl_p.h @@ -0,0 +1,786 @@ +/**************************************************************************** +** +** 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 QSCRIPTVALUEIMPL_P_H +#define QSCRIPTVALUEIMPL_P_H + +#include "qscriptvalueimplfwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptclassinfo_p.h" +#include "qscriptecmaarray_p.h" +#include "qscriptecmadate_p.h" +#include "qscriptecmaerror_p.h" +#include "qscriptecmaregexp_p.h" +#include "qscriptextqobject_p.h" +#include "qscriptextvariant_p.h" +#include "qscriptvaluefwd_p.h" +#include "qscriptnameid_p.h" +#include "qscriptenginefwd_p.h" +#include "qscriptcontextfwd_p.h" + +#include <QtCore/QDateTime> + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +inline QScriptValueImpl::QScriptValueImpl() + : m_type(QScript::InvalidType) {} + +inline QScriptValueImpl::QScriptValueImpl(QScriptValue::SpecialValue val) +{ + if (val == QScriptValue::NullValue) + m_type = QScript::NullType; + else if (val == QScriptValue::UndefinedValue) + m_type = QScript::UndefinedType; + else + m_type = QScript::InvalidType; +} + +inline QScriptValueImpl::QScriptValueImpl(bool val) + : m_type(QScript::BooleanType), m_bool_value(val) +{ +} + +inline QScriptValueImpl::QScriptValueImpl(int val) + : m_type(QScript::NumberType), m_number_value(val) +{ +} + +inline QScriptValueImpl::QScriptValueImpl(uint val) + : m_type(QScript::NumberType), m_number_value(val) +{ +} + +inline QScriptValueImpl::QScriptValueImpl(qsreal val) + : m_type(QScript::NumberType), m_number_value(val) +{ +} + +inline QScriptValueImpl::QScriptValueImpl(QScriptEnginePrivate *engine, const QString &val) +{ + engine->newString(this, val); +} + +inline QScriptValueImpl::QScriptValueImpl(QScriptNameIdImpl *val) + : m_type(QScript::StringType), m_string_value(val) +{ +} + +inline QScript::Type QScriptValueImpl::type() const +{ + return m_type; +} + +inline QScriptEnginePrivate *QScriptValueImpl::engine() const +{ + if (!isObject()) + return 0; + return m_object_value->m_class->engine(); +} + +inline QScriptClassInfo *QScriptValueImpl::classInfo() const +{ + if (!isObject()) + return 0; + return m_object_value->m_class; +} + +inline void QScriptValueImpl::setClassInfo(QScriptClassInfo *cls) +{ + Q_ASSERT(isObject()); + m_object_value->m_class = cls; +} + +inline QScriptNameIdImpl *QScriptValueImpl::stringValue() const +{ + Q_ASSERT(isString()); + return m_string_value; +} + +inline QScriptObject *QScriptValueImpl::objectValue() const +{ + Q_ASSERT(isObject()); + return m_object_value; +} + +inline void QScriptValueImpl::incr() +{ + ++m_number_value; +} + +inline void QScriptValueImpl::decr() +{ + --m_number_value; +} + +inline void QScriptValueImpl::invalidate() +{ + m_type = QScript::InvalidType; +} + +inline bool QScriptValueImpl::isValid() const +{ + return m_type != QScript::InvalidType; +} + +inline bool QScriptValueImpl::isUndefined() const +{ + return (m_type == QScript::UndefinedType); +} + +inline bool QScriptValueImpl::isNull() const +{ + return (m_type == QScript::NullType); +} + +inline bool QScriptValueImpl::isBoolean() const +{ + return (m_type == QScript::BooleanType); +} + +inline bool QScriptValueImpl::isNumber() const +{ + return (m_type == QScript::NumberType); +} + +inline bool QScriptValueImpl::isString() const +{ + return (m_type == QScript::StringType) + || (m_type == QScript::LazyStringType); +} + +inline bool QScriptValueImpl::isReference() const +{ + return (m_type == QScript::ReferenceType); +} + +inline bool QScriptValueImpl::isObject() const +{ + return (m_type == QScript::ObjectType); +} + +inline bool QScriptValueImpl::isFunction() const +{ + return (m_type == QScript::ObjectType) + && (classInfo()->type() & QScriptClassInfo::FunctionBased); +} + +inline bool QScriptValueImpl::isVariant() const +{ + return (m_type == QScript::ObjectType) + && (classInfo()->type() == QScriptClassInfo::VariantType); +} + +inline bool QScriptValueImpl::isQObject() const +{ + return (m_type == QScript::ObjectType) + && (classInfo()->type() == QScriptClassInfo::QObjectType); +} + +inline bool QScriptValueImpl::isQMetaObject() const +{ + return (m_type == QScript::ObjectType) + && (classInfo()->type() == QScriptClassInfo::QMetaObjectType); +} + +inline bool QScriptValueImpl::isArray() const +{ + if (!isObject()) + return false; + return classInfo() == engine()->arrayConstructor->classInfo(); +} + +inline bool QScriptValueImpl::isDate() const +{ + if (!isObject()) + return false; + return classInfo() == engine()->dateConstructor->classInfo(); +} + +inline bool QScriptValueImpl::isError() const +{ + if (!isObject()) + return false; + return classInfo() == engine()->errorConstructor->classInfo(); +} + +inline bool QScriptValueImpl::isRegExp() const +{ + if (!isObject()) + return false; + return classInfo() == engine()->regexpConstructor->classInfo(); +} + +inline qsreal QScriptValueImpl::toNumber() const +{ + if (!isValid()) + return 0; + return QScriptEnginePrivate::convertToNativeDouble(*this); +} + +inline bool QScriptValueImpl::toBoolean() const +{ + if (!isValid()) + return false; + return QScriptEnginePrivate::convertToNativeBoolean(*this); +} + +inline QString QScriptValueImpl::toString() const +{ + if (!isValid()) + return QString(); + return QScriptEnginePrivate::convertToNativeString(*this); +} + +inline qint32 QScriptValueImpl::toInt32() const +{ + if (!isValid()) + return 0; + double d = QScriptEnginePrivate::convertToNativeDouble(*this); + return QScriptEnginePrivate::toInt32(d); +} + +inline quint32 QScriptValueImpl::toUInt32() const +{ + if (!isValid()) + return 0; + double d = QScriptEnginePrivate::convertToNativeDouble(*this); + return QScriptEnginePrivate::toUint32(d); +} + +inline quint16 QScriptValueImpl::toUInt16() const +{ + if (!isValid()) + return 0; + double d = QScriptEnginePrivate::convertToNativeDouble(*this); + return QScriptEnginePrivate::toUint16(d); +} + +inline qsreal QScriptValueImpl::toInteger() const +{ + if (!isValid()) + return 0; + double d = QScriptEnginePrivate::convertToNativeDouble(*this); + return QScriptEnginePrivate::toInteger(d); +} + +inline QDateTime QScriptValueImpl::toDateTime() const +{ + if (!isDate()) + return QDateTime(); + return engine()->toDateTime(*this); +} + +#ifndef QT_NO_REGEXP +inline QRegExp QScriptValueImpl::toRegExp() const +{ + if (!isRegExp()) + return QRegExp(); + return engine()->regexpConstructor->toRegExp(*this); +} +#endif // QT_NO_REGEXP + +inline QObject *QScriptValueImpl::toQObject() const +{ +#ifndef QT_NO_QOBJECT + if (isQObject()) { + QScript::ExtQObject *ctor = engine()->qobjectConstructor; + Q_ASSERT(ctor != 0); + + QScript::ExtQObject::Instance *data = ctor->get(*this); + Q_ASSERT(data != 0); + + return data->value; + } else if (isVariant()) { + int type = variantValue().userType(); + if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar)) + return *reinterpret_cast<QObject* const *>(variantValue().constData()); + } +#endif + return 0; +} + +inline const QMetaObject *QScriptValueImpl::toQMetaObject() const +{ +#ifndef QT_NO_QOBJECT + if (isQMetaObject()) { + QScript::ExtQMetaObject *ctor = engine()->qmetaObjectConstructor; + Q_ASSERT(ctor != 0); + + QScript::ExtQMetaObject::Instance *data = ctor->get(*this); + Q_ASSERT(data != 0); + + return data->value; + } +#endif + return 0; +} + +inline QScriptValueImpl QScriptValueImpl::prototype() const +{ + if (!isObject()) + return QScriptValueImpl(); + return m_object_value->m_prototype; +} + +inline void QScriptValueImpl::setPrototype(const QScriptValueImpl &prototype) +{ + if (isObject()) + m_object_value->m_prototype = prototype; +} + +inline QScriptObjectData *QScriptValueImpl::objectData() const +{ + Q_ASSERT(isObject()); + return m_object_value->m_data; +} + +inline void QScriptValueImpl::setObjectData(QScriptObjectData *data) +{ + Q_ASSERT(isObject()); + m_object_value->m_data = data; +} + +inline bool QScriptValueImpl::resolve(QScriptNameIdImpl *nameId, QScript::Member *member, + QScriptValueImpl *object, QScriptValue::ResolveFlags mode, + QScript::AccessMode access) const +{ + Q_ASSERT(isValid()); + Q_ASSERT(isObject()); + Q_ASSERT(member); + Q_ASSERT(object); + + Q_ASSERT(nameId->unique); + + QScriptObject *object_data = m_object_value; + + // Search in properties... + if (object_data->findMember(nameId, member)) { + *object = *this; + return true; + } + + return resolve_helper(nameId, member, object, mode, access); +} + +inline void QScriptValueImpl::get(const QScript::Member &member, QScriptValueImpl *out) const +{ + Q_ASSERT(out); + Q_ASSERT(isObject()); + Q_ASSERT(member.isValid()); + + if (! member.isObjectProperty()) { + get_helper(member, out); + return; + } + + Q_ASSERT(member.id() >= 0); + Q_ASSERT(member.id() < m_object_value->memberCount()); + + m_object_value->get(member, out); +} + +inline void QScriptValueImpl::get(QScriptNameIdImpl *nameId, QScriptValueImpl *out) +{ + QScript::Member m; + QScriptValueImpl o; + if (resolve(nameId, &m, &o, QScriptValue::ResolvePrototype, QScript::Read)) + o.get(m, out); + else + *out = QScriptValueImpl(QScriptValue::UndefinedValue); +} + +inline void QScriptValueImpl::get_helper(const QScript::Member &member, QScriptValueImpl *out) const +{ + if (member.nameId() == engine()->idTable()->id___proto__) { + *out = prototype(); + + if (!out->isValid()) + *out = QScriptValueImpl(QScriptValue::UndefinedValue); + + return; + } + + if (QScriptClassData *data = classInfo()->data()) { + if (data->get(*this, member, out)) + return; + } + + out->invalidate(); +} + +inline void QScriptValueImpl::put(const QScript::Member &member, const QScriptValueImpl &value) +{ + Q_ASSERT(isObject()); + Q_ASSERT(member.isValid()); + // Q_ASSERT(member.isWritable()); + + QScriptEnginePrivate *eng_p = engine(); + + if (member.isObjectProperty()) { + Q_ASSERT(member.nameId()->unique); + Q_ASSERT(member.id() >= 0); + Q_ASSERT(member.id() < m_object_value->memberCount()); + m_object_value->put(member, value); + } + + else if (member.nameId() == eng_p->idTable()->id___proto__) { + if (value.isNull()) // only Object.prototype.__proto__ can be null + setPrototype(eng_p->undefinedValue()); + else { + QScriptValueImpl was = prototype(); + setPrototype(value); + if (detectedCycle()) { + eng_p->currentContext()->throwError(QLatin1String("cycle in prototype chain")); + setPrototype(was); + } + } + } + + else { + Q_ASSERT(classInfo()->data()); + classInfo()->data()->put(this, member, value); + } +} + +inline void QScriptValueImpl::setQObjectValue(QObject *object) +{ +#ifndef QT_NO_QOBJECT + Q_ASSERT(isQObject()); + + QScript::ExtQObject *ctor = engine()->qobjectConstructor; + Q_ASSERT(ctor != 0); + + QScript::ExtQObject::Instance *data = ctor->get(*this); + Q_ASSERT(data != 0); + + data->value = object; +#else + Q_UNUSED(object); +#endif +} + +inline QVariant &QScriptValueImpl::variantValue() const +{ + Q_ASSERT(isVariant()); + + QScript::Ext::Variant *ctor = engine()->variantConstructor; + Q_ASSERT(ctor != 0); + + QScript::Ext::Variant::Instance *data = ctor->get(*this); + Q_ASSERT(data != 0); + + return data->value; +} + +inline void QScriptValueImpl::setVariantValue(const QVariant &value) +{ + if (!isVariant()) + return; + + QScript::Ext::Variant *ctor = engine()->variantConstructor; + Q_ASSERT(ctor != 0); + + QScript::Ext::Variant::Instance *data = ctor->get(*this); + Q_ASSERT(data != 0); + + data->value = value; +} + +inline QScriptValueImpl QScriptValueImpl::internalValue() const +{ + Q_ASSERT(isObject()); + return m_object_value->m_internalValue; +} + +inline void QScriptValueImpl::setInternalValue(const QScriptValueImpl &internalValue) +{ + Q_ASSERT(isObject()); + m_object_value->m_internalValue = internalValue; +} + +inline void QScriptValueImpl::removeMember(const QScript::Member &member) +{ + if (member.isObjectProperty()) + m_object_value->removeMember(member); + + else if (QScriptClassData *data = classInfo()->data()) + data->removeMember(*this, member); +} + +inline void QScriptValueImpl::createMember(QScriptNameIdImpl *nameId, + QScript::Member *member, uint flags) +{ + Q_ASSERT(isObject()); + + QScriptObject *object_data = m_object_value; + object_data->createMember(nameId, member, flags); + Q_ASSERT(member->isObjectProperty()); +} + +inline QScriptValueImpl QScriptValueImpl::scope() const +{ + Q_ASSERT(isObject()); + return m_object_value->m_scope; +} + +inline void QScriptValueImpl::setScope(const QScriptValueImpl &scope) +{ + Q_ASSERT(isObject()); + m_object_value->m_scope = scope; +} + +inline int QScriptValueImpl::memberCount() const +{ + Q_ASSERT(isObject()); + return m_object_value->memberCount(); +} + +inline void QScriptValueImpl::member(int index, QScript::Member *member) const +{ + Q_ASSERT(isObject()); + Q_ASSERT(index >= 0); + Q_ASSERT(index < m_object_value->memberCount()); + m_object_value->member(index, member); +} + +inline QScriptFunction *QScriptValueImpl::toFunction() const +{ + if (!isFunction()) + return 0; + return engine()->convertToNativeFunction(*this); +} + +inline QScriptValueImpl QScriptValueImpl::property(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode) const +{ + if (!isObject()) + return QScriptValueImpl(); + + QScriptValueImpl base; + QScript::Member member; + + if (! resolve(nameId, &member, &base, mode, QScript::Read)) + return QScriptValueImpl(); + + QScriptValueImpl value; + base.get(member, &value); + if (member.isGetterOrSetter()) { + QScriptValueImpl getter; + if (member.isObjectProperty() && !member.isGetter()) { + if (!base.m_object_value->findGetter(&member)) + return QScriptValueImpl(); + } + base.get(member, &getter); + value = getter.call(*this); + } + return value; +} + +inline void QScriptValueImpl::setProperty(const QString &name, const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags) +{ + if (!isObject()) + return; + QScriptNameIdImpl *nameId = engine()->nameId(name); + setProperty(nameId, value, flags); +} + +inline QScriptValueImpl QScriptValueImpl::property(const QString &name, + const QScriptValue::ResolveFlags &mode) const +{ + if (!isObject()) + return QScriptValueImpl(); + QScriptNameIdImpl *nameId = engine()->nameId(name); + return property(nameId, mode); +} + +inline QScriptValueImpl QScriptValueImpl::property(quint32 arrayIndex, + const QScriptValue::ResolveFlags &mode) const +{ + if (!isObject()) + return QScriptValueImpl(); + + QScriptEnginePrivate *eng_p = engine(); + QScript::Ecma::Array::Instance *instance = eng_p->arrayConstructor->get(*this); + if (instance && (arrayIndex != 0xFFFFFFFF)) + return instance->value.at(arrayIndex); + + return property(QScriptValueImpl(arrayIndex).toString(), mode); +} + +inline void QScriptValueImpl::setProperty(quint32 arrayIndex, const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags) +{ + if (!isObject()) + return; + + QScriptEnginePrivate *eng_p = engine(); + QScript::Ecma::Array::Instance *instance = eng_p->arrayConstructor->get(*this); + if (instance && (arrayIndex != 0xFFFFFFFF)) { + instance->value.assign(arrayIndex, value); + return; + } + + setProperty(QScriptValueImpl(arrayIndex).toString(), value, flags); +} + +inline QScriptValue::PropertyFlags QScriptValueImpl::propertyFlags(const QString &name, + const QScriptValue::ResolveFlags &mode) const +{ + QScriptNameIdImpl *nameId = engine()->nameId(name); + return propertyFlags(nameId, mode); +} + +inline QScriptValue::PropertyFlags QScriptValueImpl::propertyFlags(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode) const +{ + if (!isObject()) + return 0; + + QScriptValueImpl base; + QScript::Member member; + if (! resolve(nameId, &member, &base, mode, QScript::ReadWrite)) + return 0; + + return QScriptValue::PropertyFlags(member.flags() & ~QScript::Member::InternalRange); +} + +inline bool QScriptValueImpl::deleteProperty(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode) +{ + if (!isObject()) + return true; + QScript::Member member; + QScriptValueImpl base; + if (resolve(nameId, &member, &base, mode, QScript::Write)) { + if (!member.isDeletable()) + return false; + base.removeMember(member); + if (member.isGetterOrSetter() && (member.isGetter() != member.isSetter())) { + // delete the "other half" of the property too (getter or setter) + return deleteProperty(nameId, mode); + } + } + return true; +} + +inline QScriptValueImpl QScriptValueImpl::call(const QScriptValueImpl &thisObject, + const QScriptValueImplList &args) +{ + if (!isFunction()) + return QScriptValueImpl(); + + return engine()->call(*this, thisObject, args, /*asConstructor=*/false); +} + +inline QScriptValueImpl QScriptValueImpl::call(const QScriptValueImpl &thisObject, + const QScriptValueImpl &args) +{ + if (!isFunction()) + return QScriptValueImpl(); + + return engine()->call(*this, thisObject, args, /*asConstructor=*/false); +} + +inline QScriptValueImpl QScriptValueImpl::construct(const QScriptValueImplList &args) +{ + if (!isFunction()) + return QScriptValueImpl(); + + QScriptEnginePrivate *eng_p = engine(); + + QScriptValueImpl proto = property(QLatin1String("prototype"), QScriptValue::ResolveLocal); + QScriptValueImpl object; + eng_p->newObject(&object, proto); + + QScriptValueImpl result = eng_p->call(*this, object, args, /*asConstructor=*/true); + if (result.isObject()) + return result; + return object; +} + +inline QScriptValueImpl QScriptValueImpl::construct(const QScriptValueImpl &args) +{ + if (!isFunction()) + return QScriptValueImpl(); + + QScriptEnginePrivate *eng_p = engine(); + + QScriptValueImpl proto = property(QLatin1String("prototype"), QScriptValue::ResolveLocal); + QScriptValueImpl object; + eng_p->newObject(&object, proto); + + QScriptValueImpl result = eng_p->call(*this, object, args, /*asConstructor=*/true); + if (result.isObject()) + return result; + return object; +} + +inline void QScriptValueImpl::mark(int generation) const +{ + if (! isValid()) + return; + + else if (isString()) + engine()->markString(m_string_value, generation); + + else if (isObject()) + engine()->markObject(*this, generation); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptvalueimplfwd_p.h b/src/script/qscriptvalueimplfwd_p.h new file mode 100644 index 0000000..059842e --- /dev/null +++ b/src/script/qscriptvalueimplfwd_p.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** 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 QSCRIPTVALUEIMPLFWD_P_H +#define QSCRIPTVALUEIMPLFWD_P_H + +#include "qscriptglobals_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalue.h" + +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptValueImpl; +typedef QList<QScriptValueImpl> QScriptValueImplList; + +class QScriptClassInfo; +class QScriptObject; +class QScriptObjectData; +class QScriptNameIdImpl; +class QScriptFunction; +class QScriptEnginePrivate; + +namespace QScript +{ + class Member; +}; + +class QScriptValueImpl +{ +public: + enum TypeHint { + NoTypeHint, + NumberTypeHint, + StringTypeHint + }; + + inline QScriptValueImpl(); + inline QScriptValueImpl(QScriptValue::SpecialValue val); + inline QScriptValueImpl(bool val); + inline QScriptValueImpl(int val); + inline QScriptValueImpl(uint val); + inline QScriptValueImpl(qsreal val); + inline QScriptValueImpl(QScriptEnginePrivate *engine, const QString &val); + inline QScriptValueImpl(QScriptNameIdImpl *val); + + inline QScript::Type type() const; + inline QScriptEnginePrivate *engine() const; + inline QScriptClassInfo *classInfo() const; + inline void setClassInfo(QScriptClassInfo *cls); + inline QScriptNameIdImpl *stringValue() const; + inline QScriptObject *objectValue() const; + inline void incr(); + inline void decr(); + + inline void invalidate(); + inline bool isValid() const; + inline bool isBoolean() const; + inline bool isNumber() const; + inline bool isString() const; + inline bool isFunction() const; + inline bool isObject() const; + inline bool isUndefined() const; + inline bool isNull() const; + inline bool isVariant() const; + inline bool isQObject() const; + inline bool isQMetaObject() const; + inline bool isReference() const; + + inline bool isError() const; + inline bool isArray() const; + inline bool isDate() const; + inline bool isRegExp() const; + + inline QString toString() const; + inline qsreal toNumber() const; + inline bool toBoolean() const; + inline qsreal toInteger() const; + inline qint32 toInt32() const; + inline quint32 toUInt32() const; + inline quint16 toUInt16() const; + QVariant toVariant() const; + inline QObject *toQObject() const; + inline const QMetaObject *toQMetaObject() const; + inline QDateTime toDateTime() const; +#ifndef QT_NO_REGEXP + inline QRegExp toRegExp() const; +#endif + + inline QVariant &variantValue() const; + inline void setVariantValue(const QVariant &v); + + bool instanceOf(const QScriptValueImpl &value) const; + bool instanceOf_helper(const QScriptValueImpl &value) const; + + bool implementsHasInstance() const; + bool hasInstance(const QScriptValueImpl &value) const; + + inline QScriptValueImpl prototype() const; + inline void setPrototype(const QScriptValueImpl &prototype); + + inline QScriptValueImpl property(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolvePrototype) const; + void setProperty(QScriptNameIdImpl *nameId, const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags); + + inline QScriptValueImpl property(const QString &name, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolvePrototype) const; + inline void setProperty(const QString &name, const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags); + + inline QScriptValueImpl property(quint32 arrayIndex, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolvePrototype) const; + inline void setProperty(quint32 arrayIndex, const QScriptValueImpl &value, + const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags); + + inline QScriptValue::PropertyFlags propertyFlags(const QString &name, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolvePrototype) const; + inline QScriptValue::PropertyFlags propertyFlags(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolvePrototype) const; + + inline bool deleteProperty(QScriptNameIdImpl *nameId, + const QScriptValue::ResolveFlags &mode = QScriptValue::ResolveLocal); + + inline QScriptValueImpl call(const QScriptValueImpl &thisObject = QScriptValueImpl(), + const QScriptValueImplList &args = QScriptValueImplList()); + inline QScriptValueImpl call(const QScriptValueImpl &thisObject, + const QScriptValueImpl &arguments); + inline QScriptValueImpl construct(const QScriptValueImplList &args = QScriptValueImplList()); + inline QScriptValueImpl construct(const QScriptValueImpl &arguments); + + inline void mark(int) const; + bool isMarked(int) const; + + inline QScriptValueImpl internalValue() const; + inline void setInternalValue(const QScriptValueImpl &internalValue); + + inline void setQObjectValue(QObject *object); + + inline QScriptObjectData *objectData() const; + inline void setObjectData(QScriptObjectData *data); + void destroyObjectData(); + + inline void createMember(QScriptNameIdImpl *nameId, + QScript::Member *member, uint flags); // ### remove me + inline int memberCount() const; + inline void member(int index, QScript::Member *member) const; + + inline bool resolve(QScriptNameIdImpl *nameId, QScript::Member *member, + QScriptValueImpl *object, QScriptValue::ResolveFlags mode, + QScript::AccessMode access) const; + bool resolve_helper(QScriptNameIdImpl *nameId, QScript::Member *member, + QScriptValueImpl *object, QScriptValue::ResolveFlags mode, + QScript::AccessMode access) const; + inline void get(const QScript::Member &member, QScriptValueImpl *out) const; + inline void get_helper(const QScript::Member &member, QScriptValueImpl *out) const; + inline void get(QScriptNameIdImpl *nameId, QScriptValueImpl *out); + inline void put(const QScript::Member &member, const QScriptValueImpl &value); + inline void removeMember(const QScript::Member &member); + + inline QScriptValueImpl scope() const; + inline void setScope(const QScriptValueImpl &scope); + + inline QScriptFunction *toFunction() const; + + bool detectedCycle() const; + + QScript::Type m_type; + union { + bool m_bool_value; + int m_int_value; + qsreal m_number_value; + void *m_ptr_value; + QScriptObject *m_object_value; + QScriptNameIdImpl *m_string_value; + QString *m_lazy_string_value; + }; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTVALUEIMPLFWD_P_H diff --git a/src/script/qscriptvalueiterator.cpp b/src/script/qscriptvalueiterator.cpp new file mode 100644 index 0000000..fe5ef9f --- /dev/null +++ b/src/script/qscriptvalueiterator.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** 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 "qscriptvalueiterator.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptvalueiterator_p.h" +#include "qscriptvalueiteratorimpl_p.h" +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.3 + \class QScriptValueIterator + + \brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue. + + \ingroup script + \mainclass + + The QScriptValueIterator constructor takes a QScriptValue as + argument. After construction, the iterator is located at the very + beginning of the sequence of properties. Here's how to iterate over + all the properties of a QScriptValue: + + \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0 + + The next() advances the iterator. The name(), value() and flags() + functions return the name, value and flags of the last item that was + jumped over. + + If you want to remove properties as you iterate over the + QScriptValue, use remove(). If you want to modify the value of a + property, use setValue(). + + Note that QScriptValueIterator only iterates over the QScriptValue's + own properties; i.e. it does not follow the prototype chain. You can + use a loop like this to follow the prototype chain: + + \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1 + + Note that QScriptValueIterator will not automatically skip over + properties that have the QScriptValue::SkipInEnumeration flag set; + that flag only affects iteration in script code. If you want, you + can skip over such properties with code like the following: + + \snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2 + + \sa QScriptValue::property() +*/ + +/*! + \internal +*/ +QScriptValueIteratorPrivate::QScriptValueIteratorPrivate() + : q_ptr(0), it(0) +{ +} + +/*! + \internal +*/ +QScriptValueIteratorPrivate::~QScriptValueIteratorPrivate() +{ +} + +/*! + Constructs an iterator for traversing \a object. The iterator is + set to be at the front of the sequence of properties (before the + first property). +*/ +QScriptValueIterator::QScriptValueIterator(const QScriptValue &object) +{ + QScriptValueImpl val = QScriptValuePrivate::valueOf(object); + if (!val.isObject()) { + d_ptr = 0; + } else { + d_ptr = new QScriptValueIteratorPrivate(); + d_ptr->it = new QScriptValueIteratorImpl(val); + } +} + +/*! + Destroys the iterator. +*/ +QScriptValueIterator::~QScriptValueIterator() +{ + if (d_ptr) { + delete d_ptr->it; + delete d_ptr; + d_ptr = 0; + } +} + +/*! + Returns true if there is at least one item ahead of the iterator + (i.e. the iterator is \e not at the back of the property sequence); + otherwise returns false. + + \sa next(), hasPrevious() +*/ +bool QScriptValueIterator::hasNext() const +{ + Q_D(const QScriptValueIterator); + return (d && d->it->hasNext()); +} + +/*! + Advances the iterator by one position. + + Calling this function on an iterator located at the back of the + container leads to undefined results. + + \sa hasNext(), previous(), name() +*/ +void QScriptValueIterator::next() +{ + Q_D(QScriptValueIterator); + if (d) + d->it->next(); +} + +/*! + Returns true if there is at least one item behind the iterator + (i.e. the iterator is \e not at the front of the property sequence); + otherwise returns false. + + \sa previous(), hasNext() +*/ +bool QScriptValueIterator::hasPrevious() const +{ + Q_D(const QScriptValueIterator); + return (d && d->it->hasPrevious()); +} + +/*! + Moves the iterator back by one position. + + Calling this function on an iterator located at the front of the + container leads to undefined results. + + \sa hasPrevious(), next(), name() +*/ +void QScriptValueIterator::previous() +{ + Q_D(QScriptValueIterator); + if (d) + d->it->previous(); +} + +/*! + Moves the iterator to the front of the QScriptValue (before the + first property). + + \sa toBack(), next() +*/ +void QScriptValueIterator::toFront() +{ + Q_D(QScriptValueIterator); + if (d) + d->it->toFront(); +} + +/*! + Moves the iterator to the back of the QScriptValue (after the + last property). + + \sa toFront(), previous() +*/ +void QScriptValueIterator::toBack() +{ + Q_D(QScriptValueIterator); + if (d) + d->it->toBack(); +} + +/*! + Returns the name of the last property that was jumped over using + next() or previous(). + + \sa value(), flags() +*/ +QString QScriptValueIterator::name() const +{ + Q_D(const QScriptValueIterator); + if (!d) + return QString(); + return d->it->name(); +} + +/*! + \since 4.4 + + Returns the name of the last property that was jumped over using + next() or previous(). +*/ +QScriptString QScriptValueIterator::scriptName() const +{ + Q_D(const QScriptValueIterator); + if (!d) + return QScriptString(); + QScriptEnginePrivate *eng = d->it->object().engine(); + return eng->internedString(d->it->nameId()); +} + +/*! + Returns the value of the last property that was jumped over using + next() or previous(). + + \sa setValue(), name() +*/ +QScriptValue QScriptValueIterator::value() const +{ + Q_D(const QScriptValueIterator); + if (!d) + return QScriptValue(); + QScriptEnginePrivate *eng = d->it->object().engine(); + return eng->toPublic(d->it->value()); +} + +/*! + Sets the \a value of the last property that was jumped over using + next() or previous(). + + \sa value(), name() +*/ +void QScriptValueIterator::setValue(const QScriptValue &value) +{ + Q_D(const QScriptValueIterator); + if (d) { + QScriptEnginePrivate *eng = d->it->object().engine(); + d->it->setValue(eng->toImpl(value)); + } +} + +/*! + Returns the flags of the last property that was jumped over using + next() or previous(). + + \sa value() +*/ +QScriptValue::PropertyFlags QScriptValueIterator::flags() const +{ + Q_D(const QScriptValueIterator); + if (!d) + return 0; + return QScriptValue::PropertyFlags(d->it->flags() & ~QScript::Member::InternalRange); +} + +/*! + Removes the last property that was jumped over using next() + or previous(). + + \sa setValue() +*/ +void QScriptValueIterator::remove() +{ + Q_D(const QScriptValueIterator); + if (d) + d->it->remove(); +} + +/*! + Makes the iterator operate on \a object. The iterator is set to be + at the front of the sequence of properties (before the first + property). +*/ +QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object) +{ + if (d_ptr) { + delete d_ptr->it; + d_ptr = 0; + } + QScriptValueImpl val = QScriptValuePrivate::valueOf(object); + if (val.isObject()) { + d_ptr = new QScriptValueIteratorPrivate(); + d_ptr->it = new QScriptValueIteratorImpl(val); + } + return *this; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptvalueiterator.h b/src/script/qscriptvalueiterator.h new file mode 100644 index 0000000..91561e8 --- /dev/null +++ b/src/script/qscriptvalueiterator.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 QSCRIPTVALUEITERATOR_H +#define QSCRIPTVALUEITERATOR_H + +#include <QtScript/qscriptvalue.h> + +#ifndef QT_NO_SCRIPT + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QString; +class QScriptString; + +class QScriptValueIteratorPrivate; +class Q_SCRIPT_EXPORT QScriptValueIterator +{ +public: + QScriptValueIterator(const QScriptValue &value); + ~QScriptValueIterator(); + + bool hasNext() const; + void next(); + + bool hasPrevious() const; + void previous(); + + QString name() const; + QScriptString scriptName() const; + + QScriptValue value() const; + void setValue(const QScriptValue &value); + + QScriptValue::PropertyFlags flags() const; + + void remove(); + + void toFront(); + void toBack(); + + QScriptValueIterator& operator=(QScriptValue &value); + +private: + QScriptValueIteratorPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QScriptValueIterator) + Q_DISABLE_COPY(QScriptValueIterator) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_SCRIPT + +#endif // QSCRIPTVALUEITERATOR_H diff --git a/src/script/qscriptvalueiterator_p.h b/src/script/qscriptvalueiterator_p.h new file mode 100644 index 0000000..e1f2815 --- /dev/null +++ b/src/script/qscriptvalueiterator_p.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 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 QSCRIPTVALUEITERATOR_P_H +#define QSCRIPTVALUEITERATOR_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_BEGIN_NAMESPACE + +class QScriptValueIteratorImpl; + +class QScriptValueIterator; +class QScriptValueIteratorPrivate +{ + Q_DECLARE_PUBLIC(QScriptValueIterator) +public: + QScriptValueIteratorPrivate(); + ~QScriptValueIteratorPrivate(); + + QScriptValueIterator *q_ptr; + + QScriptValueIteratorImpl *it; +}; + +QT_END_NAMESPACE + +#endif // QSCRIPTVALUEITERATOR_P_H diff --git a/src/script/qscriptvalueiteratorimpl.cpp b/src/script/qscriptvalueiteratorimpl.cpp new file mode 100644 index 0000000..bfe3946 --- /dev/null +++ b/src/script/qscriptvalueiteratorimpl.cpp @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** 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 "qscriptvalueiteratorimpl_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptengine_p.h" +#include "qscriptcontext_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QScript { + +extern QString numberToString(qsreal value); + +} // namespace + +QScriptValueIteratorImpl::QScriptValueIteratorImpl(const QScriptValueImpl &obj) +{ + Q_ASSERT(obj.isObject()); + m_frontObject = obj; + m_member.invalidate(); + m_foundMember.invalidate(); + m_foundForward = false; + m_object = obj; + m_searchIndex = 0; + m_searchClassDataIterator = false; + m_classDataIterator = 0; + m_ignoresDontEnum = true; + m_enumerateProto = false; +} + +QScriptValueIteratorImpl::~QScriptValueIteratorImpl() +{ + if (m_classDataIterator) { + delete m_classDataIterator; + m_classDataIterator = 0; + } +} + +bool QScriptValueIteratorImpl::ignoresDontEnum() const +{ + return m_ignoresDontEnum; +} + +void QScriptValueIteratorImpl::setIgnoresDontEnum(bool ignore) +{ + m_ignoresDontEnum = ignore; +} + +bool QScriptValueIteratorImpl::enumeratePrototype() const +{ + return m_enumerateProto; +} + +void QScriptValueIteratorImpl::setEnumeratePrototype(bool enable) +{ + m_enumerateProto = enable; +} + +bool QScriptValueIteratorImpl::acceptsMember(const QScriptValueImpl &o, + const QScript::Member &m) const +{ + if (!m.isValid() || (!m_ignoresDontEnum && m.dontEnum()) + || (m.isSetter() && !m.isGetter())) { + return false; + } + + if (!m_enumerateProto || QScriptEnginePrivate::strictlyEquals(o, m_frontObject)) + return true; + + // make sure it's not a shadowed property + QScript::Member dummy; + QScriptValueImpl base; + QScriptNameIdImpl *id; + if (m.nameId()) { + id = m.nameId(); + } else { + QScriptEnginePrivate *eng_p = m_frontObject.engine(); + id = eng_p->nameId(QScript::numberToString(m.id())); + } + m_frontObject.resolve(id, &dummy, &base, QScriptValue::ResolvePrototype, QScript::Read); + return QScriptEnginePrivate::strictlyEquals(base, o); +} + +bool QScriptValueIteratorImpl::hasNext() +{ + if (m_foundMember.isValid() && m_foundForward) { + // we have the information about the next element already + return true; + } + + int idx, count; + QScriptValueImpl obj = m_object; + + if (m_searchClassDataIterator) { + Q_ASSERT(m_classDataIterator != 0); + if (m_foundMember.isValid()) { + // undo effect of hasPrevious() + m_foundMember.invalidate(); + QScript::Member dummy; + m_classDataIterator->next(&dummy); + } + goto LSearchClassData; + } + + idx = m_searchIndex; + if (m_foundMember.isValid()) { + // undo effect of hasPrevious() + m_foundMember.invalidate(); + ++idx; + } + + LSearchObjectData: + count = obj.memberCount(); + for (int i = idx; i < count; ++i) { + QScript::Member m; + obj.member(i, &m); + if (acceptsMember(obj, m)) { + m_foundObject = obj; + m_foundMember = m; + m_foundForward = true; + m_searchIndex = i + 1; + return true; + } + } + + if (!m_classDataIterator) { + QScriptClassData *data = obj.classInfo()->data(); + if (!data) + goto LNext; + m_classDataIterator = data->newIterator(obj); + if (!m_classDataIterator) + goto LNext; + } + m_searchClassDataIterator = true; + + LSearchClassData: + Q_ASSERT(m_classDataIterator != 0); + while (m_classDataIterator->hasNext()) { + QScript::Member m; + m_classDataIterator->next(&m); + if (acceptsMember(obj, m)) { + m_foundObject = obj; + m_foundMember = m; + m_foundForward = true; + return true; + } + } + + LNext: + if (!m_enumerateProto || !obj.prototype().isObject()) + return false; + + // look in prototype + obj = obj.prototype(); + idx = 0; + if (m_classDataIterator) { + delete m_classDataIterator; + m_classDataIterator = 0; + m_searchClassDataIterator = false; + } + goto LSearchObjectData; +} + +void QScriptValueIteratorImpl::next() +{ + (void)hasNext(); // sync the next-element info + m_object = m_foundObject; + m_member = m_foundMember; + m_foundObject = QScriptValueImpl(); + m_foundMember.invalidate(); +} + +bool QScriptValueIteratorImpl::hasPrevious() +{ + if (m_foundMember.isValid() && !m_foundForward) { + // we have the information about the previous element already + return true; + } + + QScriptValueImpl obj = m_object; + + if (m_searchClassDataIterator) { + Q_ASSERT(m_classDataIterator != 0); + if (m_foundMember.isValid()) { + // undo effect of hasNext() + m_foundMember.invalidate(); + QScript::Member dummy; + m_classDataIterator->previous(&dummy); + } + while (m_classDataIterator->hasPrevious()) { + QScript::Member m; + m_classDataIterator->previous(&m); + if (acceptsMember(obj, m)) { + m_foundObject = obj; + m_foundMember = m; + m_foundForward = false; + return true; + } + } + m_searchClassDataIterator = false; + m_searchIndex = obj.memberCount(); + m_foundMember.invalidate(); + } + + // search object members + int i = m_searchIndex - 1; + if (m_foundMember.isValid()) { + // undo effect of hasPrevious() + m_foundMember.invalidate(); + --i; + } + for ( ; i >= 0; --i) { + QScript::Member m; + obj.member(i, &m); + if (acceptsMember(obj, m)) { + m_foundObject = obj; + m_foundMember = m; + m_foundForward = false; + m_searchIndex = i; + return true; + } + } + + return false; +} + +void QScriptValueIteratorImpl::previous() +{ + (void)hasPrevious(); // sync the previous-element info + m_object = m_foundObject; + m_member = m_foundMember; + m_foundObject = QScriptValueImpl(); + m_foundMember.invalidate(); +} + +QScript::Member *QScriptValueIteratorImpl::member() +{ + return &m_member; +} + +QScriptNameIdImpl *QScriptValueIteratorImpl::nameId() const +{ + return m_member.nameId(); +} + +QString QScriptValueIteratorImpl::name() const +{ + if (!m_member.isValid()) + return QString(); + if (m_member.nameId()) + return m_member.nameId()->s; + else + return QScript::numberToString(m_member.id()); +} + +QScriptValueImpl QScriptValueIteratorImpl::value() const +{ + if (!m_member.isValid()) + return QScriptValueImpl(); + QScriptValueImpl result; + m_object.get(m_member, &result); + if (m_member.isGetterOrSetter()) { + // find and call the getter + QScriptValueImpl getter; + if (m_member.isObjectProperty() && !m_member.isGetter()) { + QScript::Member mb; + QScriptObject *obj = m_object.m_object_value; + mb.object(m_member.nameId(), obj->memberCount(), 0); + if (!obj->findGetter(&mb)) + return QScriptValueImpl(); + m_object.get(mb, &getter); + } else { + getter = result; + } + result = getter.call(m_object); + } + return result; +} + +void QScriptValueIteratorImpl::setValue(const QScriptValueImpl &value) +{ + if (!m_member.isValid()) + return; + if (m_member.isGetterOrSetter()) { + // find and call the setter + QScriptValueImpl setter; + if (m_member.isObjectProperty() && !m_member.isSetter()) { + QScript::Member mb; + QScriptObject *obj = m_object.m_object_value; + mb.object(m_member.nameId(), obj->memberCount(), 0); + if (!obj->findSetter(&mb)) + return; + m_object.get(mb, &setter); + } else { + m_object.get(m_member, &setter); + } + setter.call(m_object, QScriptValueImplList() << value); + } else { + m_object.put(m_member, value); + } +} + +uint QScriptValueIteratorImpl::flags() const +{ + return m_member.flags(); +} + +QScriptValueImpl QScriptValueIteratorImpl::object() const +{ + return m_object; +} + +void QScriptValueIteratorImpl::setObject(const QScriptValueImpl &obj) +{ + Q_ASSERT(obj.isObject()); + m_object = obj; + if (m_classDataIterator) { + delete m_classDataIterator; + m_classDataIterator = 0; + } + toFront(); +} + +void QScriptValueIteratorImpl::remove() +{ + if (m_member.isValid()) + m_object.removeMember(m_member); +} + +void QScriptValueIteratorImpl::toFront() +{ + if (m_classDataIterator) { + if (!m_enumerateProto || QScriptEnginePrivate::strictlyEquals(m_object, m_frontObject)) { + m_classDataIterator->toFront(); + } else { + delete m_classDataIterator; + m_classDataIterator = 0; + } + } + + m_member.invalidate(); + m_object = m_frontObject; + + m_foundObject = QScriptValueImpl(); + m_foundMember.invalidate(); + m_searchIndex = 0; + m_searchClassDataIterator = false; +} + +void QScriptValueIteratorImpl::toBack() +{ + m_member.invalidate(); + + m_foundObject = QScriptValueImpl(); + m_foundMember.invalidate(); + + if (!m_classDataIterator) { + QScriptClassData *data = m_object.classInfo()->data(); + if (data) + m_classDataIterator = data->newIterator(m_object); + } + if (m_classDataIterator) + m_classDataIterator->toBack(); + else + m_searchIndex = m_object.memberCount(); + m_searchClassDataIterator = (m_classDataIterator != 0); +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptvalueiteratorimpl_p.h b/src/script/qscriptvalueiteratorimpl_p.h new file mode 100644 index 0000000..4ee7b11 --- /dev/null +++ b/src/script/qscriptvalueiteratorimpl_p.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 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 QSCRIPTVALUEITERATORIMPL_P_H +#define QSCRIPTVALUEITERATORIMPL_P_H + +#include "qscriptvalueimplfwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptmemberfwd_p.h" + +QT_BEGIN_NAMESPACE + +// +// 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 QScriptClassDataIterator; +class QScriptNameIdImpl; + +class QScriptValueIteratorImpl +{ +public: + QScriptValueIteratorImpl(const QScriptValueImpl &obj); + ~QScriptValueIteratorImpl(); + + bool ignoresDontEnum() const; + void setIgnoresDontEnum(bool ignore); + + bool enumeratePrototype() const; + void setEnumeratePrototype(bool enable); + + bool hasNext(); + void next(); + + bool hasPrevious(); + void previous(); + + QScript::Member *member(); + + QScriptNameIdImpl *nameId() const; + QString name() const; + + QScriptValueImpl value() const; + void setValue(const QScriptValueImpl &value); + + uint flags() const; + + void remove(); + + void toFront(); + void toBack(); + + QScriptValueImpl object() const; + void setObject(const QScriptValueImpl &obj); + +private: + bool acceptsMember(const QScriptValueImpl &o, const QScript::Member &m) const; + QScriptClassDataIterator *getClassDataIterator(); + + QScriptValueImpl m_frontObject; + + bool m_ignoresDontEnum; + bool m_enumerateProto; + + QScriptValueImpl m_object; + QScript::Member m_member; + + int m_searchIndex; + QScriptValueImpl m_foundObject; + QScript::Member m_foundMember; + bool m_foundForward; + QScriptClassDataIterator *m_classDataIterator; + bool m_searchClassDataIterator; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif diff --git a/src/script/qscriptxmlgenerator.cpp b/src/script/qscriptxmlgenerator.cpp new file mode 100644 index 0000000..131882b --- /dev/null +++ b/src/script/qscriptxmlgenerator.cpp @@ -0,0 +1,1118 @@ +/**************************************************************************** +** +** 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 "qscriptxmlgenerator_p.h" + +#ifndef QT_NO_SCRIPT + +#include "qscriptast_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptcontext_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptlexer_p.h" +#include "qscriptparser_p.h" + +#include <QtCore/qstring.h> +#include <QtCore/qtextstream.h> + +QT_BEGIN_NAMESPACE + +namespace QScript { + +extern QString numberToString(qsreal value); + +// copy of Qt::escape() (it's in QtGui :-( ) + +static QString escape(const QString& plain) +{ + QString rich; + rich.reserve(int(plain.length() * 1.1)); + for (int i = 0; i < plain.length(); ++i) { + if (plain.at(i) == QLatin1Char('<')) + rich += QLatin1String("<"); + else if (plain.at(i) == QLatin1Char('>')) + rich += QLatin1String(">"); + else if (plain.at(i) == QLatin1Char('&')) + rich += QLatin1String("&"); + else + rich += plain.at(i); + } + return rich; +} + +XmlGenerator::XmlGenerator(QTextStream &o): + out(o), m_indentLevel(-1), m_formatOutput(false) +{ +} + +XmlGenerator::~XmlGenerator() +{ +} + +QTextStream &XmlGenerator::operator()(const QString &program, int lineNumber) +{ + QScriptEnginePrivate priv; + NodePool *pool = new NodePool(/*fileName=*/QString(), &priv); + priv.setNodePool(pool); + + Lexer lex(&priv); + priv.setLexer(&lex); + lex.setCode(program, lineNumber); + + QScriptParser parser; + if (parser.parse(&priv)) { + accept(priv.abstractSyntaxTree()); + } + + delete pool; + + return out; +} + +QTextStream &XmlGenerator::newlineAndIndent() +{ + enum { IND = 2 }; + if (m_formatOutput) + out << endl << QString().fill(QLatin1Char(' '), m_indentLevel * IND); + return out; +} + +QTextStream &XmlGenerator::startTag(const QString &name, AST::Node *locationNode) +{ + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<") << name; + if (locationNode) + out << QLatin1String(" line=\"") << locationNode->startLine << QLatin1String("\""); + out << QLatin1String(">"); + return out; +} + +QTextStream &XmlGenerator::endTag(const QString &name) +{ + newlineAndIndent(); + popIndentLevel(); + out << QLatin1String("</") << escape(name) << QLatin1String(">"); + return out; +} + +void XmlGenerator::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +bool XmlGenerator::visit(AST::ThisExpression *) +{ + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<this/>"); + popIndentLevel(); + return true; +} + +void XmlGenerator::endVisit(AST::ThisExpression *) +{ +} + +bool XmlGenerator::visit(AST::IdentifierExpression *node) +{ + startTag(QLatin1String("identifier")); + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</identifier>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::IdentifierExpression *) +{ +} + +bool XmlGenerator::visit(AST::NullExpression *) +{ + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<null/>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::NullExpression *) +{ +} + +bool XmlGenerator::visit(AST::TrueLiteral *) +{ + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<true/>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::TrueLiteral *) +{ +} + +bool XmlGenerator::visit(AST::FalseLiteral *) +{ + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<false/>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::FalseLiteral *) +{ +} + +bool XmlGenerator::visit(AST::StringLiteral *node) +{ + startTag(QLatin1String("string")); + out << escape(QScriptEnginePrivate::toString(node->value)) << QLatin1String("</string>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::StringLiteral *) +{ +} + +bool XmlGenerator::visit(AST::NumericLiteral *node) +{ + startTag(QLatin1String("number")); + out << QString::number(node->value) << QLatin1String("</number>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::NumericLiteral *) +{ +} + +bool XmlGenerator::visit(AST::RegExpLiteral *node) +{ + startTag(QLatin1String("regexp")); + out << QLatin1String("/") << escape(QScriptEnginePrivate::toString(node->pattern)) << QLatin1String("/"); + if (node->flags) + out << QScript::Ecma::RegExp::flagsToString(node->flags); + out << QLatin1String("</regexp>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::RegExpLiteral *) +{ +} + +bool XmlGenerator::visit(AST::ArrayLiteral *) +{ + startTag(QLatin1String("array-literal")); + return true; +} + +void XmlGenerator::endVisit(AST::ArrayLiteral *) +{ + endTag(QLatin1String("array-literal")); +} + +bool XmlGenerator::visit(AST::ObjectLiteral *) +{ + startTag(QLatin1String("object-literal")); + return true; +} + +void XmlGenerator::endVisit(AST::ObjectLiteral *) +{ + endTag(QLatin1String("object-literal")); +} + +bool XmlGenerator::visit(AST::ElementList *) +{ + startTag(QLatin1String("element-list")); + return true; +} + +void XmlGenerator::endVisit(AST::ElementList *) +{ + endTag(QLatin1String("element-list")); +} + +bool XmlGenerator::visit(AST::Elision *) +{ + startTag(QLatin1String("elision")); // ### count + return true; +} + +void XmlGenerator::endVisit(AST::Elision *) +{ + endTag(QLatin1String("elision")); +} + +bool XmlGenerator::visit(AST::PropertyNameAndValueList *) +{ + startTag(QLatin1String("property-name-and-value-list")); + return true; +} + +void XmlGenerator::endVisit(AST::PropertyNameAndValueList *) +{ + endTag(QLatin1String("property-name-and-value-list")); +} + +bool XmlGenerator::visit(AST::IdentifierPropertyName *node) +{ + startTag(QLatin1String("identifier")); + out << escape(QScriptEnginePrivate::toString(node->id)) << QLatin1String("</identifier>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::IdentifierPropertyName *) +{ +} + +bool XmlGenerator::visit(AST::StringLiteralPropertyName *node) +{ + startTag(QLatin1String("string")); + out << escape(QScriptEnginePrivate::toString(node->id)) << QLatin1String("</string>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::StringLiteralPropertyName *) +{ +} + +bool XmlGenerator::visit(AST::NumericLiteralPropertyName *node) +{ + startTag(QLatin1String("number")); + out << escape(QScript::numberToString(node->id)) << QLatin1String("</number>"); + popIndentLevel(); + return false; +} + +void XmlGenerator::endVisit(AST::NumericLiteralPropertyName *) +{ +} + +bool XmlGenerator::visit(AST::ArrayMemberExpression *) +{ + startTag(QLatin1String("array-member-expression")); + return true; +} + +void XmlGenerator::endVisit(AST::ArrayMemberExpression *) +{ + endTag(QLatin1String("array-member-expression")); +} + +bool XmlGenerator::visit(AST::FieldMemberExpression *) +{ + startTag(QLatin1String("field-member-expression")); + return true; +} + +void XmlGenerator::endVisit(AST::FieldMemberExpression *node) +{ + startTag(QLatin1String("identifier")); + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</identifier>"); + popIndentLevel(); + endTag(QLatin1String("field-member-expression")); +} + +bool XmlGenerator::visit(AST::NewMemberExpression *) +{ + startTag(QLatin1String("new-member-expression")); + return true; +} + +void XmlGenerator::endVisit(AST::NewMemberExpression *) +{ + endTag(QLatin1String("new-member-expression")); +} + +bool XmlGenerator::visit(AST::NewExpression *) +{ + startTag(QLatin1String("new")); + return true; +} + +void XmlGenerator::endVisit(AST::NewExpression *) +{ + endTag(QLatin1String("new")); +} + +bool XmlGenerator::visit(AST::CallExpression *) +{ + startTag(QLatin1String("call")); + return true; +} + +void XmlGenerator::endVisit(AST::CallExpression *) +{ + endTag(QLatin1String("call")); +} + +bool XmlGenerator::visit(AST::ArgumentList *) +{ + startTag(QLatin1String("argument-list")); + return true; +} + +void XmlGenerator::endVisit(AST::ArgumentList *) +{ + endTag(QLatin1String("argument-list")); +} + +bool XmlGenerator::visit(AST::PostIncrementExpression *) +{ + startTag(QLatin1String("post-increment")); + return true; +} + +void XmlGenerator::endVisit(AST::PostIncrementExpression *) +{ + endTag(QLatin1String("post-increment")); +} + +bool XmlGenerator::visit(AST::PostDecrementExpression *) +{ + startTag(QLatin1String("post-decrement")); + return true; +} + +void XmlGenerator::endVisit(AST::PostDecrementExpression *) +{ + endTag(QLatin1String("post-decrement")); +} + +bool XmlGenerator::visit(AST::DeleteExpression *) +{ + startTag(QLatin1String("delete")); + return true; +} + +void XmlGenerator::endVisit(AST::DeleteExpression *) +{ + endTag(QLatin1String("delete")); +} + +bool XmlGenerator::visit(AST::VoidExpression *) +{ + startTag(QLatin1String("void")); + return true; +} + +void XmlGenerator::endVisit(AST::VoidExpression *) +{ + endTag(QLatin1String("void")); +} + +bool XmlGenerator::visit(AST::TypeOfExpression *) +{ + startTag(QLatin1String("typeof")); + return true; +} + +void XmlGenerator::endVisit(AST::TypeOfExpression *) +{ + endTag(QLatin1String("typeof")); +} + +bool XmlGenerator::visit(AST::PreIncrementExpression *) +{ + startTag(QLatin1String("pre-increment")); + return true; +} + +void XmlGenerator::endVisit(AST::PreIncrementExpression *) +{ + endTag(QLatin1String("pre-increment")); +} + +bool XmlGenerator::visit(AST::PreDecrementExpression *) +{ + startTag(QLatin1String("pre-decrement")); + return true; +} + +void XmlGenerator::endVisit(AST::PreDecrementExpression *) +{ + endTag(QLatin1String("pre-decrement")); +} + +bool XmlGenerator::visit(AST::UnaryPlusExpression *) +{ + startTag(QLatin1String("unary-plus")); + return true; +} + +void XmlGenerator::endVisit(AST::UnaryPlusExpression *) +{ + endTag(QLatin1String("unary-plus")); +} + +bool XmlGenerator::visit(AST::UnaryMinusExpression *) +{ + startTag(QLatin1String("unary-minus")); + return true; +} + +void XmlGenerator::endVisit(AST::UnaryMinusExpression *) +{ + endTag(QLatin1String("unary-minus")); +} + +bool XmlGenerator::visit(AST::TildeExpression *) +{ + startTag(QLatin1String("bitwise-not")); + return true; +} + +void XmlGenerator::endVisit(AST::TildeExpression *) +{ + endTag(QLatin1String("bitwise-not")); +} + +bool XmlGenerator::visit(AST::NotExpression *) +{ + startTag(QLatin1String("logical-not")); + return true; +} + +void XmlGenerator::endVisit(AST::NotExpression *) +{ + endTag(QLatin1String("logical-not")); +} + +bool XmlGenerator::visit(AST::BinaryExpression *node) +{ + QString s; + switch (node->op) { + case QSOperator::Add: + s = QLatin1String("+"); break; + case QSOperator::And: + s = QLatin1String("&&"); break; + case QSOperator::InplaceAnd: + s = QLatin1String("&="); break; + case QSOperator::Assign: + s = QLatin1String("="); break; + case QSOperator::BitAnd: + s = QLatin1String("&"); break; + case QSOperator::BitOr: + s = QLatin1String("|"); break; + case QSOperator::BitXor: + s = QLatin1String("^"); break; + case QSOperator::InplaceSub: + s = QLatin1String("-="); break; + case QSOperator::Div: + s = QLatin1String("/"); break; + case QSOperator::InplaceDiv: + s = QLatin1String("/="); break; + case QSOperator::Equal: + s = QLatin1String("=="); break; + case QSOperator::Ge: + s = QLatin1String(">="); break; + case QSOperator::Gt: + s = QLatin1String(">"); break; + case QSOperator::In: + s = QLatin1String("in"); break; + case QSOperator::InplaceAdd: + s = QLatin1String("+="); break; + case QSOperator::InstanceOf: + s = QLatin1String("instanceof"); break; + case QSOperator::Le: + s = QLatin1String("<="); break; + case QSOperator::LShift: + s = QLatin1String("<<"); break; + case QSOperator::InplaceLeftShift: + s = QLatin1String("<<="); break; + case QSOperator::Lt: + s = QLatin1String("<"); break; + case QSOperator::Mod: + s = QLatin1String("%"); break; + case QSOperator::InplaceMod: + s = QLatin1String("%="); break; + case QSOperator::Mul: + s = QLatin1String("*"); break; + case QSOperator::InplaceMul: + s = QLatin1String("*="); break; + case QSOperator::NotEqual: + s = QLatin1String("!="); break; + case QSOperator::Or: + s = QLatin1String("||"); break; + case QSOperator::InplaceOr: + s = QLatin1String("|="); break; + case QSOperator::RShift: + s = QLatin1String(">>"); break; + case QSOperator::InplaceRightShift: + s = QLatin1String(">>="); break; + case QSOperator::StrictEqual: + s = QLatin1String("==="); break; + case QSOperator::StrictNotEqual: + s = QLatin1String("!=="); break; + case QSOperator::Sub: + s = QLatin1String("-"); break; + case QSOperator::URShift: + s = QLatin1String(">>>"); break; + case QSOperator::InplaceURightShift: + s = QLatin1String(">>>="); break; + case QSOperator::InplaceXor: + s = QLatin1String("^="); break; + default: + Q_ASSERT (0); + } + pushIndentLevel(); + newlineAndIndent(); + out << QLatin1String("<binary-expression op=\"") << s << QLatin1String("\">"); + return true; +} + +void XmlGenerator::endVisit(AST::BinaryExpression *) +{ + endTag(QLatin1String("binary-expression")); +} + +bool XmlGenerator::visit(AST::ConditionalExpression *) +{ + startTag(QLatin1String("conditional")); + return true; +} + +void XmlGenerator::endVisit(AST::ConditionalExpression *) +{ + endTag(QLatin1String("conditional")); +} + +bool XmlGenerator::visit(AST::Expression *) +{ + startTag(QLatin1String("comma-expression")); + return true; +} + +void XmlGenerator::endVisit(AST::Expression *) +{ + endTag(QLatin1String("comma-expression")); +} + +bool XmlGenerator::visit(AST::Block *) +{ + startTag(QLatin1String("block")); + return true; +} + +void XmlGenerator::endVisit(AST::Block *) +{ + endTag(QLatin1String("block")); +} + +bool XmlGenerator::visit(AST::StatementList *) +{ + startTag(QLatin1String("statement-list")); + return true; +} + +void XmlGenerator::endVisit(AST::StatementList *) +{ + endTag(QLatin1String("statement-list")); +} + +bool XmlGenerator::visit(AST::VariableDeclarationList *) +{ + startTag(QLatin1String("variable-declaration-list")); + return true; +} + +void XmlGenerator::endVisit(AST::VariableDeclarationList *) +{ + endTag(QLatin1String("variable-declaration-list")); +} + +bool XmlGenerator::visit(AST::VariableStatement *node) +{ + startTag(QLatin1String("variable-statement"), node); + return true; +} + +void XmlGenerator::endVisit(AST::VariableStatement *) +{ + endTag(QLatin1String("variable-statement")); +} + +bool XmlGenerator::visit(AST::VariableDeclaration *node) +{ + startTag(QLatin1String("variable-declaration"), node); + startTag(QLatin1String("name")); + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</name>"); + popIndentLevel(); + return true; +} + +void XmlGenerator::endVisit(AST::VariableDeclaration *) +{ + endTag(QLatin1String("variable-declaration")); +} + +bool XmlGenerator::visit(AST::EmptyStatement *node) +{ + startTag(QLatin1String("empty-statement"), node); + return true; +} + +void XmlGenerator::endVisit(AST::EmptyStatement *) +{ + endTag(QLatin1String("empty-statement")); +} + +bool XmlGenerator::visit(AST::ExpressionStatement *node) +{ + startTag(QLatin1String("expression-statement"), node); + return true; +} + +void XmlGenerator::endVisit(AST::ExpressionStatement *) +{ + endTag(QLatin1String("expression-statement")); +} + +bool XmlGenerator::visit(AST::IfStatement *node) +{ + startTag(QLatin1String("if"), node); + return true; +} + +void XmlGenerator::endVisit(AST::IfStatement *) +{ + endTag(QLatin1String("if")); +} + +bool XmlGenerator::visit(AST::DoWhileStatement *node) +{ + startTag(QLatin1String("do-while"), node); + return true; +} + +void XmlGenerator::endVisit(AST::DoWhileStatement *) +{ + endTag(QLatin1String("do-while")); +} + +bool XmlGenerator::visit(AST::WhileStatement *node) +{ + startTag(QLatin1String("while"), node); + return true; +} + +void XmlGenerator::endVisit(AST::WhileStatement *) +{ + endTag(QLatin1String("while")); +} + +bool XmlGenerator::visit(AST::ForStatement *node) +{ + startTag(QLatin1String("for"), node); + return true; +} + +void XmlGenerator::endVisit(AST::ForStatement *) +{ + endTag(QLatin1String("for")); +} + +bool XmlGenerator::visit(AST::LocalForStatement *node) +{ + startTag(QLatin1String("for"), node); + return true; +} + +void XmlGenerator::endVisit(AST::LocalForStatement *) +{ + endTag(QLatin1String("for")); +} + +bool XmlGenerator::visit(AST::ForEachStatement *node) +{ + startTag(QLatin1String("for-in"), node); + return false; +} + +void XmlGenerator::endVisit(AST::ForEachStatement *) +{ + endTag(QLatin1String("for-in")); +} + +bool XmlGenerator::visit(AST::LocalForEachStatement *node) +{ + startTag(QLatin1String("for-in"), node); + return true; +} + +void XmlGenerator::endVisit(AST::LocalForEachStatement *) +{ + endTag(QLatin1String("for-in")); +} + +bool XmlGenerator::visit(AST::ContinueStatement *node) +{ + startTag(QLatin1String("continue"), node); + if (node->label) { + startTag(QLatin1String("label")); + out << escape(QScriptEnginePrivate::toString(node->label)); + out << QLatin1String("</label>"); + popIndentLevel(); + } + return true; +} + +void XmlGenerator::endVisit(AST::ContinueStatement *) +{ + endTag(QLatin1String("continue")); +} + +bool XmlGenerator::visit(AST::BreakStatement *node) +{ + startTag(QLatin1String("break"), node); + if (node->label) { + startTag(QLatin1String("label")); + out << escape(QScriptEnginePrivate::toString(node->label)); + out << QLatin1String("</label>"); + popIndentLevel(); + } + return true; +} + +void XmlGenerator::endVisit(AST::BreakStatement *) +{ + endTag(QLatin1String("break")); +} + +bool XmlGenerator::visit(AST::ReturnStatement *node) +{ + startTag(QLatin1String("return"), node); + return true; +} + +void XmlGenerator::endVisit(AST::ReturnStatement *) +{ + endTag(QLatin1String("return")); +} + +bool XmlGenerator::visit(AST::WithStatement *node) +{ + startTag(QLatin1String("with"), node); + return true; +} + +void XmlGenerator::endVisit(AST::WithStatement *) +{ + endTag(QLatin1String("with")); +} + +bool XmlGenerator::visit(AST::SwitchStatement *node) +{ + startTag(QLatin1String("switch"), node); + return true; +} + +void XmlGenerator::endVisit(AST::SwitchStatement *) +{ + endTag(QLatin1String("switch")); +} + +bool XmlGenerator::visit(AST::CaseBlock *) +{ + startTag(QLatin1String("case-block")); + return true; +} + +void XmlGenerator::endVisit(AST::CaseBlock *) +{ + endTag(QLatin1String("case-block")); +} + +bool XmlGenerator::visit(AST::CaseClauses *) +{ + startTag(QLatin1String("case-clauses")); + return true; +} + +void XmlGenerator::endVisit(AST::CaseClauses *) +{ + endTag(QLatin1String("case-clauses")); +} + +bool XmlGenerator::visit(AST::CaseClause *) +{ + startTag(QLatin1String("case-clause")); + return true; +} + +void XmlGenerator::endVisit(AST::CaseClause *) +{ + endTag(QLatin1String("case-clause")); +} + +bool XmlGenerator::visit(AST::DefaultClause *) +{ + startTag(QLatin1String("default-clause")); + return true; +} + +void XmlGenerator::endVisit(AST::DefaultClause *) +{ + endTag(QLatin1String("default-clause")); +} + +bool XmlGenerator::visit(AST::LabelledStatement *node) +{ + startTag(QLatin1String("labelled-statement"), node); + startTag(QLatin1String("label")); + out << escape(QScriptEnginePrivate::toString(node->label)); + out << QLatin1String("</label>"); + popIndentLevel(); + return true; +} + +void XmlGenerator::endVisit(AST::LabelledStatement *) +{ + endTag(QLatin1String("labelled-statement")); +} + +bool XmlGenerator::visit(AST::ThrowStatement *node) +{ + startTag(QLatin1String("throw"), node); + return true; +} + +void XmlGenerator::endVisit(AST::ThrowStatement *) +{ + endTag(QLatin1String("throw")); +} + +bool XmlGenerator::visit(AST::TryStatement *node) +{ + startTag(QLatin1String("try"), node); + return true; +} + +void XmlGenerator::endVisit(AST::TryStatement *) +{ + endTag(QLatin1String("try")); +} + +bool XmlGenerator::visit(AST::Catch *node) +{ + startTag(QLatin1String("catch")); + startTag(QLatin1String("identifier")); + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</identifier>"); + popIndentLevel(); + return true; +} + +void XmlGenerator::endVisit(AST::Catch *) +{ + endTag(QLatin1String("catch")); +} + +bool XmlGenerator::visit(AST::Finally *) +{ + startTag(QLatin1String("finally")); + return true; +} + +void XmlGenerator::endVisit(AST::Finally *) +{ + endTag(QLatin1String("finally")); +} + +bool XmlGenerator::visit(AST::FunctionDeclaration *node) +{ + startTag(QLatin1String("function-declaration"), node); + startTag(QLatin1String("name")); + if (node->name) + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</name>"); + popIndentLevel(); + if (!node->formals) { + startTag(QLatin1String("formal-parameter-list")); + endTag(QLatin1String("formal-parameter-list")); + } + if (!node->body) { + startTag(QLatin1String("function-body")); + endTag(QLatin1String("function-body")); + } + return true; +} + +void XmlGenerator::endVisit(AST::FunctionDeclaration *) +{ + endTag(QLatin1String("function-declaration")); +} + +bool XmlGenerator::visit(AST::FunctionExpression *node) +{ + startTag(QLatin1String("function-expression"), node); + startTag(QLatin1String("name")); + if (node->name) + out << escape(QScriptEnginePrivate::toString(node->name)); + out << QLatin1String("</name>"); + if (!node->formals) { + startTag(QLatin1String("formal-parameter-list")); + endTag(QLatin1String("formal-parameter-list")); + } + if (!node->body) { + startTag(QLatin1String("function-body")); + endTag(QLatin1String("function-body")); + } + return true; +} + +void XmlGenerator::endVisit(AST::FunctionExpression *) +{ + endTag(QLatin1String("function-expression")); +} + +bool XmlGenerator::visit(AST::FormalParameterList *node) +{ + Q_UNUSED(node); + startTag(QLatin1String("formal-parameter-list")); + for (AST::FormalParameterList *it = node; it; it = it->next) { + startTag(QLatin1String("identifier")); + out << escape(QScriptEnginePrivate::toString(it->name)); + out << QLatin1String("</identifier>"); + popIndentLevel(); + } + return true; +} + +void XmlGenerator::endVisit(AST::FormalParameterList *) +{ + endTag(QLatin1String("formal-parameter-list")); +} + +bool XmlGenerator::visit(AST::FunctionBody *) +{ + startTag(QLatin1String("function-body")); + return true; +} + +void XmlGenerator::endVisit(AST::FunctionBody *) +{ + endTag(QLatin1String("function-body")); +} + +bool XmlGenerator::visit(AST::Program *) +{ + startTag(QLatin1String("program")); + return true; +} + +void XmlGenerator::endVisit(AST::Program *) +{ + endTag(QLatin1String("program")); +} + +bool XmlGenerator::visit(AST::SourceElements *) +{ + startTag(QLatin1String("source-elements")); + return true; +} + +void XmlGenerator::endVisit(AST::SourceElements *) +{ + endTag(QLatin1String("source-elements")); +} + +bool XmlGenerator::visit(AST::FunctionSourceElement *) +{ + return true; +} + +void XmlGenerator::endVisit(AST::FunctionSourceElement *) +{ +} + +bool XmlGenerator::visit(AST::StatementSourceElement *) +{ + return true; +} + +void XmlGenerator::endVisit(AST::StatementSourceElement *) +{ +} + +bool XmlGenerator::visit(AST::DebuggerStatement *node) +{ + startTag(QLatin1String("debugger-statement"), node); + return true; +} + +void XmlGenerator::endVisit(AST::DebuggerStatement *) +{ + endTag(QLatin1String("debugger-statement")); +} + +bool XmlGenerator::preVisit(AST::Node *) +{ + return true; +} + +} // namespace QScript + +Q_SCRIPT_EXPORT QString qt_scriptToXml(const QString &program, int lineNumber = 1) +{ + QString result; + QTextStream out(&result, QIODevice::WriteOnly); + QScript::XmlGenerator gen(out); + gen(program, lineNumber); + out.flush(); + return result; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT diff --git a/src/script/qscriptxmlgenerator_p.h b/src/script/qscriptxmlgenerator_p.h new file mode 100644 index 0000000..c496816 --- /dev/null +++ b/src/script/qscriptxmlgenerator_p.h @@ -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 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 QSCRIPTXMLGENERATOR_P_H +#define QSCRIPTXMLGENERATOR_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/qobjectdefs.h> + +#ifndef QT_NO_SCRIPT + +#include "qscriptastvisitor_p.h" + +QT_BEGIN_NAMESPACE + +class QTextStream; + +namespace QScript { + +class XmlGenerator: protected AST::Visitor +{ +public: + XmlGenerator(QTextStream &out); + virtual ~XmlGenerator(); + + QTextStream &operator()(const QString &program, int lineNumber = 1); + +protected: + void accept(AST::Node *node); + + virtual bool preVisit(AST::Node *node); + + virtual bool visit(AST::ThisExpression *node); + virtual void endVisit(AST::ThisExpression *node); + + virtual bool visit(AST::IdentifierExpression *node); + virtual void endVisit(AST::IdentifierExpression *node); + + virtual bool visit(AST::NullExpression *node); + virtual void endVisit(AST::NullExpression *node); + + virtual bool visit(AST::TrueLiteral *node); + virtual void endVisit(AST::TrueLiteral *node); + + virtual bool visit(AST::FalseLiteral *node); + virtual void endVisit(AST::FalseLiteral *node); + + virtual bool visit(AST::StringLiteral *node); + virtual void endVisit(AST::StringLiteral *node); + + virtual bool visit(AST::NumericLiteral *node); + virtual void endVisit(AST::NumericLiteral *node); + + virtual bool visit(AST::RegExpLiteral *node); + virtual void endVisit(AST::RegExpLiteral *node); + + virtual bool visit(AST::ArrayLiteral *node); + virtual void endVisit(AST::ArrayLiteral *node); + + virtual bool visit(AST::ObjectLiteral *node); + virtual void endVisit(AST::ObjectLiteral *node); + + virtual bool visit(AST::ElementList *node); + virtual void endVisit(AST::ElementList *node); + + virtual bool visit(AST::Elision *node); + virtual void endVisit(AST::Elision *node); + + virtual bool visit(AST::PropertyNameAndValueList *node); + virtual void endVisit(AST::PropertyNameAndValueList *node); + + virtual bool visit(AST::IdentifierPropertyName *node); + virtual void endVisit(AST::IdentifierPropertyName *node); + + virtual bool visit(AST::StringLiteralPropertyName *node); + virtual void endVisit(AST::StringLiteralPropertyName *node); + + virtual bool visit(AST::NumericLiteralPropertyName *node); + virtual void endVisit(AST::NumericLiteralPropertyName *node); + + virtual bool visit(AST::ArrayMemberExpression *node); + virtual void endVisit(AST::ArrayMemberExpression *node); + + virtual bool visit(AST::FieldMemberExpression *node); + virtual void endVisit(AST::FieldMemberExpression *node); + + virtual bool visit(AST::NewMemberExpression *node); + virtual void endVisit(AST::NewMemberExpression *node); + + virtual bool visit(AST::NewExpression *node); + virtual void endVisit(AST::NewExpression *node); + + virtual bool visit(AST::CallExpression *node); + virtual void endVisit(AST::CallExpression *node); + + virtual bool visit(AST::ArgumentList *node); + virtual void endVisit(AST::ArgumentList *node); + + virtual bool visit(AST::PostIncrementExpression *node); + virtual void endVisit(AST::PostIncrementExpression *node); + + virtual bool visit(AST::PostDecrementExpression *node); + virtual void endVisit(AST::PostDecrementExpression *node); + + virtual bool visit(AST::DeleteExpression *node); + virtual void endVisit(AST::DeleteExpression *node); + + virtual bool visit(AST::VoidExpression *node); + virtual void endVisit(AST::VoidExpression *node); + + virtual bool visit(AST::TypeOfExpression *node); + virtual void endVisit(AST::TypeOfExpression *node); + + virtual bool visit(AST::PreIncrementExpression *node); + virtual void endVisit(AST::PreIncrementExpression *node); + + virtual bool visit(AST::PreDecrementExpression *node); + virtual void endVisit(AST::PreDecrementExpression *node); + + virtual bool visit(AST::UnaryPlusExpression *node); + virtual void endVisit(AST::UnaryPlusExpression *node); + + virtual bool visit(AST::UnaryMinusExpression *node); + virtual void endVisit(AST::UnaryMinusExpression *node); + + virtual bool visit(AST::TildeExpression *node); + virtual void endVisit(AST::TildeExpression *node); + + virtual bool visit(AST::NotExpression *node); + virtual void endVisit(AST::NotExpression *node); + + virtual bool visit(AST::BinaryExpression *node); + virtual void endVisit(AST::BinaryExpression *node); + + virtual bool visit(AST::ConditionalExpression *node); + virtual void endVisit(AST::ConditionalExpression *node); + + virtual bool visit(AST::Expression *node); + virtual void endVisit(AST::Expression *node); + + virtual bool visit(AST::Block *node); + virtual void endVisit(AST::Block *node); + + virtual bool visit(AST::StatementList *node); + virtual void endVisit(AST::StatementList *node); + + virtual bool visit(AST::VariableStatement *node); + virtual void endVisit(AST::VariableStatement *node); + + virtual bool visit(AST::VariableDeclarationList *node); + virtual void endVisit(AST::VariableDeclarationList *node); + + virtual bool visit(AST::VariableDeclaration *node); + virtual void endVisit(AST::VariableDeclaration *node); + + virtual bool visit(AST::EmptyStatement *node); + virtual void endVisit(AST::EmptyStatement *node); + + virtual bool visit(AST::ExpressionStatement *node); + virtual void endVisit(AST::ExpressionStatement *node); + + virtual bool visit(AST::IfStatement *node); + virtual void endVisit(AST::IfStatement *node); + + virtual bool visit(AST::DoWhileStatement *node); + virtual void endVisit(AST::DoWhileStatement *node); + + virtual bool visit(AST::WhileStatement *node); + virtual void endVisit(AST::WhileStatement *node); + + virtual bool visit(AST::ForStatement *node); + virtual void endVisit(AST::ForStatement *node); + + virtual bool visit(AST::LocalForStatement *node); + virtual void endVisit(AST::LocalForStatement *node); + + virtual bool visit(AST::ForEachStatement *node); + virtual void endVisit(AST::ForEachStatement *node); + + virtual bool visit(AST::LocalForEachStatement *node); + virtual void endVisit(AST::LocalForEachStatement *node); + + virtual bool visit(AST::ContinueStatement *node); + virtual void endVisit(AST::ContinueStatement *node); + + virtual bool visit(AST::BreakStatement *node); + virtual void endVisit(AST::BreakStatement *node); + + virtual bool visit(AST::ReturnStatement *node); + virtual void endVisit(AST::ReturnStatement *node); + + virtual bool visit(AST::WithStatement *node); + virtual void endVisit(AST::WithStatement *node); + + virtual bool visit(AST::SwitchStatement *node); + virtual void endVisit(AST::SwitchStatement *node); + + virtual bool visit(AST::CaseBlock *node); + virtual void endVisit(AST::CaseBlock *node); + + virtual bool visit(AST::CaseClauses *node); + virtual void endVisit(AST::CaseClauses *node); + + virtual bool visit(AST::CaseClause *node); + virtual void endVisit(AST::CaseClause *node); + + virtual bool visit(AST::DefaultClause *node); + virtual void endVisit(AST::DefaultClause *node); + + virtual bool visit(AST::LabelledStatement *node); + virtual void endVisit(AST::LabelledStatement *node); + + virtual bool visit(AST::ThrowStatement *node); + virtual void endVisit(AST::ThrowStatement *node); + + virtual bool visit(AST::TryStatement *node); + virtual void endVisit(AST::TryStatement *node); + + virtual bool visit(AST::Catch *node); + virtual void endVisit(AST::Catch *node); + + virtual bool visit(AST::Finally *node); + virtual void endVisit(AST::Finally *node); + + virtual bool visit(AST::FunctionDeclaration *node); + virtual void endVisit(AST::FunctionDeclaration *node); + + virtual bool visit(AST::FunctionExpression *node); + virtual void endVisit(AST::FunctionExpression *node); + + virtual bool visit(AST::FormalParameterList *node); + virtual void endVisit(AST::FormalParameterList *node); + + virtual bool visit(AST::FunctionBody *node); + virtual void endVisit(AST::FunctionBody *node); + + virtual bool visit(AST::Program *node); + virtual void endVisit(AST::Program *node); + + virtual bool visit(AST::SourceElements *node); + virtual void endVisit(AST::SourceElements *node); + + virtual bool visit(AST::FunctionSourceElement *node); + virtual void endVisit(AST::FunctionSourceElement *node); + + virtual bool visit(AST::StatementSourceElement *node); + virtual void endVisit(AST::StatementSourceElement *node); + + virtual bool visit(AST::DebuggerStatement *node); + virtual void endVisit(AST::DebuggerStatement *node); + +private: + int indentLevel(int level) + { + int was = m_indentLevel; + m_indentLevel = level; + return was; + } + + void pushIndentLevel() + { ++m_indentLevel; } + + void popIndentLevel() + { --m_indentLevel; } + + QTextStream &newlineAndIndent(); + QTextStream &startTag(const QString &name, AST::Node *locationNode = 0); + QTextStream &endTag(const QString &name); + +private: + QTextStream &out; + int m_indentLevel; + bool m_formatOutput; +}; + +} // namespace QScript + +#endif // QT_NO_SCRIPT + +QT_END_NAMESPACE + +#endif diff --git a/src/script/script.pri b/src/script/script.pri new file mode 100644 index 0000000..15e68de --- /dev/null +++ b/src/script/script.pri @@ -0,0 +1,124 @@ + +*-g++:DEFINES += Q_SCRIPT_DIRECT_CODE + +SOURCES += \ + $$PWD/qscriptasm.cpp \ + $$PWD/qscriptast.cpp \ + $$PWD/qscriptastvisitor.cpp \ + $$PWD/qscriptcompiler.cpp \ + $$PWD/qscriptecmaarray.cpp \ + $$PWD/qscriptecmaboolean.cpp \ + $$PWD/qscriptecmacore.cpp \ + $$PWD/qscriptecmadate.cpp \ + $$PWD/qscriptecmafunction.cpp \ + $$PWD/qscriptecmaglobal.cpp \ + $$PWD/qscriptecmamath.cpp \ + $$PWD/qscriptecmanumber.cpp \ + $$PWD/qscriptecmaobject.cpp \ + $$PWD/qscriptecmaregexp.cpp \ + $$PWD/qscriptecmastring.cpp \ + $$PWD/qscriptecmaerror.cpp \ + $$PWD/qscriptcontext_p.cpp \ + $$PWD/qscriptengine.cpp \ + $$PWD/qscriptengine_p.cpp \ + $$PWD/qscriptengineagent.cpp \ + $$PWD/qscriptextenumeration.cpp \ + $$PWD/qscriptextvariant.cpp \ + $$PWD/qscriptcontext.cpp \ + $$PWD/qscriptcontextinfo.cpp \ + $$PWD/qscriptfunction.cpp \ + $$PWD/qscriptgrammar.cpp \ + $$PWD/qscriptlexer.cpp \ + $$PWD/qscriptclassdata.cpp \ + $$PWD/qscriptparser.cpp \ + $$PWD/qscriptprettypretty.cpp \ + $$PWD/qscriptxmlgenerator.cpp \ + $$PWD/qscriptsyntaxchecker.cpp \ + $$PWD/qscriptstring.cpp \ + $$PWD/qscriptclass.cpp \ + $$PWD/qscriptclasspropertyiterator.cpp \ + $$PWD/qscriptvalueiteratorimpl.cpp \ + $$PWD/qscriptvalueiterator.cpp \ + $$PWD/qscriptvalueimpl.cpp \ + $$PWD/qscriptvalue.cpp + +HEADERS += \ + $$PWD/qscriptarray_p.h \ + $$PWD/qscriptasm_p.h \ + $$PWD/qscriptastfwd_p.h \ + $$PWD/qscriptast_p.h \ + $$PWD/qscriptastvisitor_p.h \ + $$PWD/qscriptbuffer_p.h \ + $$PWD/qscriptcompiler_p.h \ + $$PWD/qscriptcontext.h \ + $$PWD/qscriptcontextfwd_p.h \ + $$PWD/qscriptcontext_p.h \ + $$PWD/qscriptcontextinfo.h \ + $$PWD/qscriptcontextinfo_p.h \ + $$PWD/qscriptecmaarray_p.h \ + $$PWD/qscriptecmaboolean_p.h \ + $$PWD/qscriptecmacore_p.h \ + $$PWD/qscriptecmadate_p.h \ + $$PWD/qscriptecmafunction_p.h \ + $$PWD/qscriptecmaglobal_p.h \ + $$PWD/qscriptecmamath_p.h \ + $$PWD/qscriptecmanumber_p.h \ + $$PWD/qscriptecmaobject_p.h \ + $$PWD/qscriptecmaregexp_p.h \ + $$PWD/qscriptecmastring_p.h \ + $$PWD/qscriptecmaerror_p.h \ + $$PWD/qscriptengine.h \ + $$PWD/qscriptenginefwd_p.h \ + $$PWD/qscriptengine_p.h \ + $$PWD/qscriptengineagent.h \ + $$PWD/qscriptengineagent_p.h \ + $$PWD/qscriptable.h \ + $$PWD/qscriptable_p.h \ + $$PWD/qscriptextenumeration_p.h \ + $$PWD/qscriptextvariant_p.h \ + $$PWD/qscriptfunction_p.h \ + $$PWD/qscriptgc_p.h \ + $$PWD/qscriptglobals_p.h \ + $$PWD/qscriptgrammar_p.h \ + $$PWD/qscriptobjectdata_p.h \ + $$PWD/qscriptobjectfwd_p.h \ + $$PWD/qscriptobject_p.h \ + $$PWD/qscriptlexer_p.h \ + $$PWD/qscriptmemberfwd_p.h \ + $$PWD/qscriptmember_p.h \ + $$PWD/qscriptmemorypool_p.h \ + $$PWD/qscriptnodepool_p.h \ + $$PWD/qscriptclassinfo_p.h \ + $$PWD/qscriptparser_p.h \ + $$PWD/qscriptprettypretty_p.h \ + $$PWD/qscriptsyntaxcheckresult_p.h \ + $$PWD/qscriptxmlgenerator_p.h \ + $$PWD/qscriptrepository_p.h \ + $$PWD/qscriptsyntaxchecker_p.h \ + $$PWD/qscriptstring.h \ + $$PWD/qscriptstring_p.h \ + $$PWD/qscriptclass.h \ + $$PWD/qscriptclass_p.h \ + $$PWD/qscriptclasspropertyiterator.h \ + $$PWD/qscriptclasspropertyiterator_p.h \ + $$PWD/qscriptvalue.h \ + $$PWD/qscriptvaluefwd_p.h \ + $$PWD/qscriptvalue_p.h \ + $$PWD/qscriptvalueimplfwd_p.h \ + $$PWD/qscriptvalueimpl_p.h \ + $$PWD/qscriptvalueiteratorimpl_p.h \ + $$PWD/qscriptvalueiterator.h \ + $$PWD/qscriptvalueiterator_p.h \ + $$PWD/qscriptextensioninterface.h \ + $$PWD/qscriptextensionplugin.h \ + $$PWD/qscriptnameid_p.h \ + $$PWD/qscriptclassdata_p.h + +!contains(DEFINES, QT_NO_QOBJECT) { + HEADERS += $$PWD/qscriptextqobject_p.h + SOURCES += $$PWD/qscriptextqobject.cpp \ + $$PWD/qscriptable.cpp \ + $$PWD/qscriptextensionplugin.cpp +} else { + INCLUDEPATH += $$PWD +} diff --git a/src/script/script.pro b/src/script/script.pro new file mode 100644 index 0000000..9aa9bc2 --- /dev/null +++ b/src/script/script.pro @@ -0,0 +1,12 @@ +TARGET = QtScript +QPRO_PWD = $$PWD +QT = core +DEFINES += QT_BUILD_SCRIPT_LIB +DEFINES += QT_NO_USING_NAMESPACE +DEFINES += QLALR_NO_QSCRIPTGRAMMAR_DEBUG_INFO +#win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 ### FIXME + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore + +include(../qbase.pri) +include(script.pri) |