/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
**
**
**
+**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativeexpression.h"
-#include "private/qdeclarativeexpression_p.h"
+#include "qdeclarativeexpression_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativerewrite_p.h"
-#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "qdeclarativeengine_p.h"
+#include "qdeclarativecontext_p.h"
+#include "qdeclarativerewrite_p.h"
+#include "qdeclarativescriptstring_p.h"
+#include "qdeclarativecompiler_p.h"
#include <QtCore/qdebug.h>
-#include <QtScript/qscriptprogram.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
QT_BEGIN_NAMESPACE
return true;
}
-QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
-: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false),
- guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
+QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression()
+: m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0),
+ m_scopeObject(0), guardCapture(0)
{
}
-QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
+QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
{
- if (guardList) { delete [] guardList; guardList = 0; }
- if (dataRef) dataRef->release();
- if (deleted) *deleted = true;
+ if (guardCapture) guardCapture->expression = 0;
+ clearGuards();
}
QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
-: expressionFunctionValid(true), line(-1)
+: expressionFunctionValid(true), expressionFunctionRewritten(false),
+ extractExpressionFromFunction(false), line(-1), dataRef(0)
{
}
QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
{
+ qPersistentDispose(v8qmlscope);
+ qPersistentDispose(v8function);
+ if (dataRef) dataRef->release();
+ dataRef = 0;
}
void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
expression = expr;
QDeclarativeAbstractExpression::setContext(ctxt);
- scopeObject = me;
+ setScopeObject(me);
expressionFunctionValid = false;
+ expressionFunctionRewritten = false;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
QObject *me)
{
- expression = func.toString();
-
QDeclarativeAbstractExpression::setContext(ctxt);
- scopeObject = me;
+ setScopeObject(me);
- expressionFunction = func;
- expressionFunctionMode = ExplicitContext;
+ v8function = qPersistentNew<v8::Function>(func);
+ setUseSharedContext(false);
expressionFunctionValid = true;
+ expressionFunctionRewritten = false;
+ extractExpressionFromFunction = true;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr,
- QDeclarativeRefCount *rc,
- QObject *me, const QString &srcUrl, int lineNumber)
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
{
url = srcUrl;
line = lineNumber;
+ column = columnNumber;
- if (dataRef) dataRef->release();
- dataRef = rc;
- if (dataRef) dataRef->addref();
-
- quint32 *exprData = (quint32 *)expr;
- QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
-
- expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
-
- int progIdx = *(exprData);
- bool isSharedProgram = progIdx & 0x80000000;
- progIdx &= 0x7FFFFFFF;
-
- QDeclarativeEngine *engine = ctxt->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (isSharedProgram) {
-
- if (!dd->cachedClosures.at(progIdx)) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- scriptContext->pushScope(ep->contextClass->newSharedContext());
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
- scriptEngine->popContext();
- }
-
- expressionFunction = *dd->cachedClosures.at(progIdx);
- expressionFunctionMode = SharedContext;
- expressionFunctionValid = true;
-
- } else {
-
- if (!dd->cachedPrograms.at(progIdx)) {
- dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
- }
-
- expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
- &expressionContext);
+ expression = expr;
- expressionFunctionMode = ExplicitContext;
- expressionFunctionValid = true;
- }
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = isRewritten;
QDeclarativeAbstractExpression::setContext(ctxt);
- scopeObject = me;
+ setScopeObject(me);
}
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
- const QString &program, const QString &fileName,
- int lineNumber, QScriptValue *contextObject)
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
- if (contextObject) {
- *contextObject = ep->contextClass->newContext(context, object);
- scriptContext->pushScope(*contextObject);
- } else {
- scriptContext->pushScope(ep->contextClass->newContext(context, object));
- }
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
- ep->scriptEngine.popContext();
- return rv;
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
+ // QtScript days
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ v8::TryCatch tc;
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
+ if (tc.HasCaught()) return v8::Persistent<v8::Function>();
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) return v8::Persistent<v8::Function>();
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
}
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
- const QScriptProgram &program,
- QScriptValue *contextObject)
+QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber)
{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
- if (contextObject) {
- *contextObject = ep->contextClass->newContext(context, object);
- scriptContext->pushScope(*contextObject);
- } else {
- scriptContext->pushScope(ep->contextClass->newContext(context, object));
- }
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue rv = ep->scriptEngine.evaluate(program);
- ep->scriptEngine.popContext();
- return rv;
+ return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate);
}
/*!
\endcode
*/
-static int QDeclarativeExpression_notifyIdx = -1;
-
/*!
Create an invalid QDeclarativeExpression.
QDeclarativeExpression::QDeclarativeExpression()
: QObject(*new QDeclarativeExpressionPrivate, 0)
{
- Q_D(QDeclarativeExpression);
-
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*! \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
- QDeclarativeRefCount *rc, QObject *me,
- const QString &url, int lineNumber,
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt,
+ QObject *object, const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber,
QDeclarativeExpressionPrivate &dd)
: QObject(dd, 0)
{
Q_D(QDeclarativeExpression);
- d->init(ctxt, expr, rc, me, url, lineNumber);
+ d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
+}
+
+/*!
+ Create a QDeclarativeExpression object that is a child of \a parent.
+
+ The \script provides the expression to be evaluated, the context to evaluate it in,
+ and the scope object to evaluate it with.
+
+ This constructor is functionally equivalent to the following, but in most cases
+ is more efficient.
+ \code
+ QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent);
+ \endcode
+
+ \sa QDeclarativeScriptString
+*/
+QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent)
+: QObject(*new QDeclarativeExpressionPrivate, parent)
+{
+ Q_D(QDeclarativeExpression);
+ bool defaultConstruction = false;
+
+ int id = script.d.data()->bindingId;
+ if (id < 0) {
+ defaultConstruction = true;
+ } else {
+ QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context());
+
+ QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(script.context()->engine());
+ QDeclarativeCompiledData *cdata = 0;
+ QDeclarativeTypeData *typeData = 0;
+ if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+ typeData = engine->typeLoader.get(ctxtdata->url);
+ cdata = typeData->compiledData();
+ }
+
+ if (cdata)
+ d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
+ cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
+ else
+ defaultConstruction = true;
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+ if (cdata)
+ cdata->release();
+ if (typeData)
+ typeData->release();
+ }
+
+ if (defaultConstruction)
+ d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject());
}
/*!
{
Q_D(QDeclarativeExpression);
d->init(QDeclarativeContextData::get(ctxt), expression, scope);
-
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*!
{
Q_D(QDeclarativeExpression);
d->init(ctxt, expression, scope);
-
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
/*! \internal */
{
Q_D(QDeclarativeExpression);
d->init(ctxt, expression, scope);
-
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
-/*! \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
- QDeclarativeExpressionPrivate &dd)
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QDeclarativeExpression(ctxt, scope, &function, ...);
+ */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
+ QDeclarativeExpressionPrivate &dd)
: QObject(dd, 0)
{
- Q_D(QDeclarativeExpression);
- d->init(ctxt, func, scope);
+ v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
- if (QDeclarativeExpression_notifyIdx == -1)
- QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
- d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, function, scope);
}
/*!
QString QDeclarativeExpression::expression() const
{
Q_D(const QDeclarativeExpression);
+ if (d->extractExpressionFromFunction && context()->engine()) {
+ QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine());
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+
+ return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
+ }
return d->expression;
}
{
Q_D(QDeclarativeExpression);
- d->resetNotifyOnChange();
+ d->resetNotifyOnValueChanged();
d->expression = expression;
d->expressionFunctionValid = false;
- d->expressionFunction = QScriptValue();
+ d->expressionFunctionRewritten = false;
+ qPersistentDispose(d->v8function);
+ qPersistentDispose(d->v8qmlscope);
}
-void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
- QDeclarativeError &error)
+void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
+ QDeclarativeError &error)
{
- if (scriptEngine->hasUncaughtException() &&
- scriptEngine->uncaughtException().isError()) {
+ Q_ASSERT(!message.IsEmpty());
- QString fileName;
- int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
+ v8::Handle<v8::Value> name = message->GetScriptResourceName();
+ v8::Handle<v8::String> description = message->Get();
+ int lineNumber = message->GetLineNumber();
- QScriptValue exception = scriptEngine->uncaughtException();
- QLatin1String fileNameProp("fileName");
+ v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
+ if (file.IsEmpty() || file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
- if (!exception.property(fileNameProp).toString().isEmpty()){
- fileName = exception.property(fileNameProp).toString();
- } else {
- fileName = QLatin1String("<Unknown File>");
- }
+ error.setLine(lineNumber);
+ error.setColumn(-1);
- error.setUrl(QUrl(fileName));
- error.setLine(lineNumber);
- error.setColumn(-1);
- error.setDescription(exception.toString());
- } else {
- error = QDeclarativeError();
- }
-}
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
-bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
-{
- return trackChange;
+ error.setDescription(qDescription);
}
-void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
+void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
- trackChange = notify;
- if (!notify && guardList)
- clearGuards();
+ m_notifyOnValueChanged = v;
+ if (!v) clearGuards();
}
-void QDeclarativeQtScriptExpression::resetNotifyOnChange()
+void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
{
clearGuards();
}
-void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
-{
- if (guardList) clearGuards();
-
- if (!object || notifyIndex == -1) {
- guardObject = 0;
- notifyIndex = -1;
- } else {
- guardObject = object;
- guardObjectNotifyIndex = notifyIndex;
-
- }
-}
-
-void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags)
-{
- evalFlags = flags;
-}
-
-QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const
-{
- return evalFlags;
-}
-
-QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
- Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
- if (!expressionFunction.isValid()) {
+ if (function.IsEmpty() || function->IsUndefined()) {
if (isUndefined) *isUndefined = true;
- return QScriptValue();
+ return v8::Local<v8::Value>();
}
- DeleteWatcher watcher(this);
-
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
- bool lastCaptureProperties = ep->captureProperties;
- QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
- ep->captureProperties = trackChange;
- ep->capturedProperties.copyAndClear(lastCapturedProperties);
-
- QScriptValue value = eval(secondaryScope, isUndefined);
-
- if (!watcher.wasDeleted() && trackChange) {
- if (ep->capturedProperties.count() == 0) {
+ Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+ GuardCapture capture(this);
- if (guardList) clearGuards();
-
- } else {
+ QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = notifyOnValueChanged()?&capture:0;
- updateGuards(ep->capturedProperties);
- }
- }
+ if (notifyOnValueChanged())
+ capture.guards.copyAndClear(activeGuards);
- lastCapturedProperties.copyAndClear(ep->capturedProperties);
- ep->captureProperties = lastCaptureProperties;
+ QDeclarativeContextData *lastSharedContext = 0;
+ QObject *lastSharedScope = 0;
- return value;
-}
+ bool sharedContext = useSharedContext();
-QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
-{
- Q_ASSERT(context() && context()->engine);
+ // All code that follows must check with watcher before it accesses data members
+ // incase we have been deleted.
+ QDeleteWatcher watcher(this);
- DeleteWatcher watcher(this);
+ if (sharedContext) {
+ lastSharedContext = ep->sharedContext;
+ lastSharedScope = ep->sharedScope;
+ ep->sharedContext = context();
+ ep->sharedScope = scopeObject();
+ }
- QDeclarativeEngine *engine = context()->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ v8::Local<v8::Value> result;
+ {
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Object> This = ep->v8engine()->global();
+ if (scopeObject() && requiresThisObject()) {
+ v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
+ if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ }
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ result = function->Call(This, 0, 0);
- QDeclarativeContextData *oldSharedContext = 0;
- QObject *oldSharedScope = 0;
- QObject *oldOverride = 0;
- bool isShared = (expressionFunctionMode == SharedContext);
+ if (isUndefined)
+ *isUndefined = try_catch.HasCaught() || result->IsUndefined();
- if (isShared) {
- oldSharedContext = ep->sharedContext;
- oldSharedScope = ep->sharedScope;
- ep->sharedContext = context();
- ep->sharedScope = scopeObject;
- } else {
- oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
+ if (watcher.wasDeleted()) {
+ } else if (try_catch.HasCaught()) {
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ } else {
+ error = QDeclarativeError();
+ }
+ } else {
+ error = QDeclarativeError();
+ }
}
- QScriptValue thisObject;
- if (evalFlags & RequiresThisObject)
- thisObject = ep->objectClass->newQObject(scopeObject);
- QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
-
- if (isShared) {
- ep->sharedContext = oldSharedContext;
- ep->sharedScope = oldSharedScope;
- } else if (!watcher.wasDeleted()) {
- ep->contextClass->setOverrideObject(expressionContext, oldOverride);
+ if (sharedContext) {
+ ep->sharedContext = lastSharedContext;
+ ep->sharedScope = lastSharedScope;
}
- if (isUndefined)
- *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->count(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = 0;
+ }
- // Handle exception
- if (scriptEngine->hasUncaughtException()) {
- if (!watcher.wasDeleted())
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+ while (Guard *g = capture.guards.takeFirst())
+ g->Delete();
- scriptEngine->clearExceptions();
- return QScriptValue();
- } else {
- if (!watcher.wasDeleted())
- error = QDeclarativeError();
+ ep->propertyCapture = lastPropertyCapture;
- return svalue;
- }
+ return result;
}
-void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n)
{
- Q_ASSERT(guardObject);
- Q_ASSERT(guardObjectNotifyIndex != -1);
+ if (expression) {
- if (properties.count() != guardListLength) {
- QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(n))
+ guards.takeFirst()->Delete();
- for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii)
- guardList[ii].copyAndClear(newGuardList[ii]);
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(n));
+ } else {
+ g = Guard::New(expression);
+ g->connect(n);
+ }
- delete [] guardList;
- guardList = newGuardList;
- guardListLength = properties.count();
+ expression->activeGuards.append(g);
}
+}
- bool outputWarningHeader = false;
- bool noChanges = true;
- for (int ii = 0; ii < properties.count(); ++ii) {
- QDeclarativeNotifierEndpoint &guard = guardList[ii];
- const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
-
- guard.target = guardObject;
- guard.targetMethod = guardObjectNotifyIndex;
-
- if (property.notifier != 0) {
-
- if (!noChanges && guard.isConnected(property.notifier)) {
- // Nothing to do
-
- } else {
- noChanges = false;
-
- bool existing = false;
- for (int jj = 0; !existing && jj < ii; ++jj)
- if (guardList[jj].isConnected(property.notifier))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.notifier);
- }
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+ if (expression) {
+ if (n == -1) {
+ if (!errorString) {
+ errorString = new QStringList;
+ QString preamble = QLatin1String("QDeclarativeExpression: Expression ") +
+ expression->expressionIdentifier() +
+ QLatin1String(" depends on non-NOTIFYable properties:");
+ errorString->append(preamble);
}
+ const QMetaObject *metaObj = o->metaObject();
+ QMetaProperty metaProp = metaObj->property(c);
- } else if (property.notifyIndex != -1) {
+ QString error = QLatin1String(" ") +
+ QString::fromUtf8(metaObj->className()) +
+ QLatin1String("::") +
+ QString::fromUtf8(metaProp.name());
+ errorString->append(error);
+ } else {
- if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
- // Nothing to do
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
+ guards.takeFirst()->Delete();
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(o, n));
} else {
- noChanges = false;
-
- bool existing = false;
- for (int jj = 0; !existing && jj < ii; ++jj)
- if (guardList[jj].isConnected(property.object, property.notifyIndex))
- existing = true;
-
- if (existing) {
- // duplicate
- guard.disconnect();
- } else {
- guard.connect(property.object, property.notifyIndex);
- }
+ g = Guard::New(expression);
+ g->connect(o, n);
}
- } else {
- if (!outputWarningHeader) {
- outputWarningHeader = true;
- qWarning() << "QDeclarativeExpression: Expression" << expression
- << "depends on non-NOTIFYable properties:";
- }
-
- const QMetaObject *metaObj = property.object->metaObject();
- QMetaProperty metaProp = metaObj->property(property.coreIndex);
-
- qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
+ expression->activeGuards.append(g);
}
}
}
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+void QDeclarativeJavaScriptExpression::clearGuards()
{
- if (!expressionFunctionValid) {
- QDeclarativeEngine *engine = context()->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ while (Guard *g = activeGuards.takeFirst())
+ g->Delete();
+}
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- expressionContext = ep->contextClass->newContext(context(), scopeObject);
- scriptContext->pushScope(expressionContext);
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
+{
+ if (!expressionFunctionValid) {
+ bool ok = true;
QDeclarativeRewrite::RewriteBinding rewriteBinding;
rewriteBinding.setName(name);
- bool ok = true;
- const QString code = rewriteBinding(expression, &ok);
- if (ok)
- expressionFunction = scriptEngine->evaluate(code, url, line);
-
- scriptEngine->popContext();
- expressionFunctionMode = ExplicitContext;
+ QString code;
+ if (expressionFunctionRewritten)
+ code = expression;
+ else
+ code = rewriteBinding(expression, &ok);
+
+ if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
+ setUseSharedContext(false);
expressionFunctionValid = true;
}
- return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+
+ if (secondaryScope) {
+ v8::Local<v8::Value> result;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
+ QObject *restoreSecondaryScope = 0;
+ restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
+ result = evaluate(v8function, isUndefined);
+ ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
+ return result;
+ } else {
+ return evaluate(v8function, isUndefined);
+ }
}
QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+ QVariant rv;
+
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+
+ {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(ep->v8engine()->context());
+ v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+ rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
+ }
+
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
- return retn;
+
+ return rv;
}
/*!
bool QDeclarativeExpression::notifyOnValueChanged() const
{
Q_D(const QDeclarativeExpression);
- return d->notifyOnValueChange();
+ return d->notifyOnValueChanged();
}
/*!
void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
{
Q_D(QDeclarativeExpression);
- d->setNotifyOnValueChange(notifyOnChange);
+ d->setNotifyOnValueChanged(notifyOnChange);
}
/*!
}
/*!
+ Returns the source file column number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QDeclarativeExpression::columnNumber() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->column;
+}
+
+/*!
Set the location of this expression to \a line of \a url. This information
is used by the script engine.
*/
-void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
+void QDeclarativeExpression::setSourceLocation(const QString &url, int line, int column)
{
Q_D(QDeclarativeExpression);
d->url = url;
d->line = line;
+ d->column = column;
}
/*!
QObject *QDeclarativeExpression::scopeObject() const
{
Q_D(const QDeclarativeExpression);
- return d->scopeObject;
+ return d->scopeObject();
}
/*!
return d->error;
}
-/*! \internal */
-void QDeclarativeExpressionPrivate::_q_notify()
-{
- emitValueChanged();
-}
-
-void QDeclarativeQtScriptExpression::clearGuards()
-{
- delete [] guardList;
- guardList = 0;
- guardListLength = 0;
-}
-
/*!
\fn void QDeclarativeExpression::valueChanged()
calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
*/
-void QDeclarativeExpressionPrivate::emitValueChanged()
+void QDeclarativeExpressionPrivate::expressionChanged()
{
Q_Q(QDeclarativeExpression);
emit q->valueChanged();