summaryrefslogtreecommitdiffstats
path: root/src/script/qscriptcompiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/qscriptcompiler.cpp')
-rw-r--r--src/script/qscriptcompiler.cpp2111
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