diff options
Diffstat (limited to 'src/script/qscriptcompiler.cpp')
-rw-r--r-- | src/script/qscriptcompiler.cpp | 2111 |
1 files changed, 2111 insertions, 0 deletions
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 |