a210e4e1d7ee56398c78d22d8a6fe4afb4bd35fb
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativeexpression.h"
43 #include "private/qdeclarativeexpression_p.h"
44
45 #include "private/qdeclarativeengine_p.h"
46 #include "private/qdeclarativecontext_p.h"
47 #include "private/qdeclarativerewrite_p.h"
48 #include "private/qdeclarativecompiler_p.h"
49
50 #include <QtCore/qdebug.h>
51 #include <QtScript/qscriptprogram.h>
52
53 #include <private/qscriptdeclarativeclass_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
58 {
59     if (!e) return false;
60
61     if (e->inProgressCreations == 0) return false; // Not in construction
62
63     if (prevError) return true; // Already in error chain
64
65     prevError = &e->erroredBindings;
66     nextError = e->erroredBindings;
67     e->erroredBindings = this;
68     if (nextError) nextError->prevError = &nextError;
69
70     return true;
71 }
72
73 QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
74 : dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), 
75   guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
76 {
77 }
78
79 QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
80 {
81     v8function.Dispose();
82     v8qmlscope.Dispose();
83     v8function = v8::Persistent<v8::Function>();
84     v8qmlscope = v8::Persistent<v8::Function>();
85
86     if (guardList) { delete [] guardList; guardList = 0; }
87     if (dataRef) dataRef->release();
88     if (deleted) *deleted = true;
89 }
90
91 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
92 : expressionFunctionValid(true), line(-1)
93 {
94 }
95
96 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
97 {
98 }
99
100 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
101                                          QObject *me)
102 {
103     expression = expr;
104
105     QDeclarativeAbstractExpression::setContext(ctxt);
106     scopeObject = me;
107     expressionFunctionValid = false;
108 }
109
110 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
111                                          QObject *me)
112 {
113     // XXX aakenned
114     // expression = func.toString();
115
116     QDeclarativeAbstractExpression::setContext(ctxt);
117     scopeObject = me;
118
119     v8function = v8::Persistent<v8::Function>::New(func);
120     expressionFunctionMode = ExplicitContext;
121     expressionFunctionValid = true;
122 }
123
124 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, 
125                                          QDeclarativeRefCount *rc, 
126                                          QObject *me, const QString &srcUrl, int lineNumber)
127 {
128     url = srcUrl;
129     line = lineNumber;
130
131     Q_ASSERT(!dataRef);
132
133     dataRef = rc;
134     if (dataRef) dataRef->addref();
135
136     quint32 *exprData = (quint32 *)expr;
137     QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
138
139     expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
140
141     int progIdx = *(exprData);
142     bool isSharedProgram = progIdx & 0x80000000;
143     progIdx &= 0x7FFFFFFF;
144
145     v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
146
147     expressionFunctionMode = ExplicitContext;
148     expressionFunctionValid = true;
149
150     QDeclarativeAbstractExpression::setContext(ctxt);
151     scopeObject = me;
152 }
153
154 // Callee owns the persistent handle
155 v8::Persistent<v8::Function> 
156 QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, 
157                                             const QString &code, const QString &filename, int line,
158                                             v8::Persistent<v8::Object> *qmlscope)
159 {
160     QDeclarativeEngine *engine = ctxt->engine;
161     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
162
163     // XXX aakenned optimize
164     v8::HandleScope handle_scope;
165     v8::Context::Scope ctxtscope(ep->v8engine.context());
166     
167     // XXX try/catch?
168
169     v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
170     v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
171     v8::Local<v8::Value> result = script->Run(scopeobject);
172     if (qmlscope) *qmlscope = v8::Persistent<v8::Object>::New(scopeobject);
173     return v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(result));
174 }
175
176 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
177                                                               const QString &program, const QString &fileName,
178                                                               int lineNumber, QScriptValue *contextObject)
179 {
180 #if 0
181     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
182     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
183     if (contextObject) {
184         *contextObject = ep->contextClass->newContext(context, object);
185         scriptContext->pushScope(*contextObject);
186     } else {
187         scriptContext->pushScope(ep->contextClass->newContext(context, object));
188     }
189     scriptContext->pushScope(ep->globalClass->staticGlobalObject());
190     QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
191     ep->scriptEngine.popContext();
192     return rv;
193 #else
194     qFatal("Not impl");
195 #endif
196 }
197
198 QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
199                                                               const QScriptProgram &program, 
200                                                               QScriptValue *contextObject)
201 {
202 #if 0
203     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
204     QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
205     if (contextObject) {
206         *contextObject = ep->contextClass->newContext(context, object);
207         scriptContext->pushScope(*contextObject);
208     } else {
209         scriptContext->pushScope(ep->contextClass->newContext(context, object));
210     }
211     scriptContext->pushScope(ep->globalClass->staticGlobalObject());
212     QScriptValue rv = ep->scriptEngine.evaluate(program);
213     ep->scriptEngine.popContext();
214     return rv;
215 #else
216     qFatal("Not impl");
217 #endif
218 }
219
220 /*!
221     \class QDeclarativeExpression
222     \since 4.7
223     \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
224
225     For example, given a file \c main.qml like this:
226
227     \qml
228     import QtQuick 1.0
229
230     Item {
231         width: 200; height: 200
232     }
233     \endqml
234
235     The following code evaluates a JavaScript expression in the context of the
236     above QML:
237
238     \code
239     QDeclarativeEngine *engine = new QDeclarativeEngine;
240     QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
241
242     QObject *myObject = component.create();
243     QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2");
244     int result = expr->evaluate().toInt();  // result = 400
245     \endcode
246 */
247
248 static int QDeclarativeExpression_notifyIdx = -1;
249
250 /*!
251     Create an invalid QDeclarativeExpression.
252
253     As the expression will not have an associated QDeclarativeContext, this will be a
254     null expression object and its value will always be an invalid QVariant.
255  */
256 QDeclarativeExpression::QDeclarativeExpression()
257 : QObject(*new QDeclarativeExpressionPrivate, 0)
258 {
259     Q_D(QDeclarativeExpression);
260
261     if (QDeclarativeExpression_notifyIdx == -1) 
262         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
263     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
264 }
265
266 /*!  \internal */
267 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
268                                                QDeclarativeRefCount *rc, QObject *me, 
269                                                const QString &url, int lineNumber,
270                                                QDeclarativeExpressionPrivate &dd)
271 : QObject(dd, 0)
272 {
273     Q_D(QDeclarativeExpression);
274     d->init(ctxt, expr, rc, me, url, lineNumber);
275
276     if (QDeclarativeExpression_notifyIdx == -1) 
277         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
278     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
279 }
280
281 /*!
282     Create a QDeclarativeExpression object that is a child of \a parent.
283
284     The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext.
285     If specified, the \a scope object's properties will also be in scope during
286     the expression's execution.
287 */
288 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
289                                                QObject *scope,
290                                                const QString &expression,
291                                                QObject *parent)
292 : QObject(*new QDeclarativeExpressionPrivate, parent)
293 {
294     Q_D(QDeclarativeExpression);
295     d->init(QDeclarativeContextData::get(ctxt), expression, scope);
296
297     if (QDeclarativeExpression_notifyIdx == -1) 
298         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
299     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
300 }
301
302 /*! 
303     \internal
304 */
305 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
306                                                const QString &expression)
307 : QObject(*new QDeclarativeExpressionPrivate, 0)
308 {
309     Q_D(QDeclarativeExpression);
310     d->init(ctxt, expression, scope);
311
312     if (QDeclarativeExpression_notifyIdx == -1) 
313         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
314     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
315 }
316
317 /*!  \internal */
318 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
319                                                const QString &expression, QDeclarativeExpressionPrivate &dd)
320 : QObject(dd, 0)
321 {
322     Q_D(QDeclarativeExpression);
323     d->init(ctxt, expression, scope);
324
325     if (QDeclarativeExpression_notifyIdx == -1) 
326         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
327     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
328 }
329
330 /*!  
331     \internal 
332
333     To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
334     For example:
335         v8::Handle<v8::Function> function;
336         new QDeclarativeExpression(ctxt, scope, &function, ...);
337  */
338 QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
339                        QDeclarativeExpressionPrivate &dd)
340 : QObject(dd, 0)
341 {
342     v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
343
344     Q_D(QDeclarativeExpression);
345     d->init(ctxt, function, scope);
346
347     if (QDeclarativeExpression_notifyIdx == -1)
348         QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
349
350     d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
351 }
352
353 /*!
354     Destroy the QDeclarativeExpression instance.
355 */
356 QDeclarativeExpression::~QDeclarativeExpression()
357 {
358 }
359
360 /*!
361     Returns the QDeclarativeEngine this expression is associated with, or 0 if there
362     is no association or the QDeclarativeEngine has been destroyed.
363 */
364 QDeclarativeEngine *QDeclarativeExpression::engine() const
365 {
366     Q_D(const QDeclarativeExpression);
367     return d->context()?d->context()->engine:0;
368 }
369
370 /*!
371     Returns the QDeclarativeContext this expression is associated with, or 0 if there
372     is no association or the QDeclarativeContext has been destroyed.
373 */
374 QDeclarativeContext *QDeclarativeExpression::context() const
375 {
376     Q_D(const QDeclarativeExpression);
377     QDeclarativeContextData *data = d->context();
378     return data?data->asQDeclarativeContext():0;
379 }
380
381 /*!
382     Returns the expression string.
383 */
384 QString QDeclarativeExpression::expression() const
385 {
386     Q_D(const QDeclarativeExpression);
387     return d->expression;
388 }
389
390 /*!
391     Set the expression to \a expression.
392 */
393 void QDeclarativeExpression::setExpression(const QString &expression)
394 {
395     Q_D(QDeclarativeExpression);
396
397     d->resetNotifyOnChange();
398     d->expression = expression;
399     d->expressionFunctionValid = false;
400     d->v8function.Dispose();
401     d->v8qmlscope.Dispose();
402     d->v8function = v8::Persistent<v8::Function>();
403     d->v8qmlscope = v8::Persistent<v8::Function>();
404 }
405
406 void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
407                                                      QDeclarativeError &error)
408 {
409     Q_ASSERT(!message.IsEmpty());
410
411     v8::Handle<v8::Value> name = message->GetScriptResourceName();
412     v8::Handle<v8::String> description = message->Get();
413     int lineNumber = message->GetLineNumber();
414
415     Q_ASSERT(name->IsString());
416
417     v8::Local<v8::String> file = name->ToString();
418     if (file->Length() == 0) 
419         error.setUrl(QUrl(QLatin1String("<Unknown File>")));
420     else 
421         error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
422
423     error.setLine(lineNumber);
424     error.setColumn(-1);
425
426     QString qDescription = QV8Engine::toStringStatic(description);
427     if (qDescription.startsWith(QLatin1String("Uncaught ")))
428         qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
429
430     error.setDescription(qDescription);
431 }
432
433 void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, 
434                                                      QDeclarativeError &error)
435 {
436     qFatal("Not implemented - we use v8 now");
437 }
438
439 bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
440 {
441     return trackChange;
442 }
443
444 void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
445 {
446     trackChange = notify;
447     if (!notify && guardList) 
448         clearGuards();
449 }
450
451 void QDeclarativeQtScriptExpression::resetNotifyOnChange()
452 {
453     clearGuards();
454 }
455
456 void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
457 {
458     if (guardList) clearGuards();
459
460     if (!object || notifyIndex == -1) {
461         guardObject = 0;
462         notifyIndex = -1;
463     } else {
464         guardObject = object;
465         guardObjectNotifyIndex = notifyIndex;
466
467     }
468 }
469
470 void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags)
471 {
472     evalFlags = flags;
473 }
474
475 QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const
476 {
477     return evalFlags;
478 }
479
480 v8::Local<v8::Value> QDeclarativeQtScriptExpression::v8value(QObject *secondaryScope, bool *isUndefined)
481 {
482     Q_ASSERT(context() && context()->engine);
483     Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
484
485     if (v8function.IsEmpty() || v8function->IsUndefined()) {
486         if (isUndefined) *isUndefined = true;
487         return v8::Local<v8::Value>();
488     }
489
490     DeleteWatcher watcher(this);
491
492     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
493
494     bool lastCaptureProperties = ep->captureProperties;
495     QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
496     ep->captureProperties = trackChange;
497     ep->capturedProperties.copyAndClear(lastCapturedProperties);
498
499     v8::Local<v8::Value> value = eval(secondaryScope, isUndefined);
500
501     if (!watcher.wasDeleted() && trackChange) {
502         if (ep->capturedProperties.count() == 0) {
503
504             if (guardList) clearGuards();
505
506         } else {
507
508             updateGuards(ep->capturedProperties);
509
510         }
511     }
512
513     lastCapturedProperties.copyAndClear(ep->capturedProperties);
514     ep->captureProperties = lastCaptureProperties;
515
516     return value;
517 }
518
519 v8::Local<v8::Value> QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
520 {
521     Q_ASSERT(context() && context()->engine);
522     DeleteWatcher watcher(this);
523
524     QDeclarativeEngine *engine = context()->engine;
525     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
526
527     QObject *restoreSecondaryScope = 0;
528     if (secondaryScope) 
529         restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
530
531     v8::TryCatch try_catch;
532     v8::Context::Scope scope(ep->v8engine.context()); // XXX is this needed?
533
534     v8::Handle<v8::Object> This;
535
536     if (evaluateFlags() & RequiresThisObject) {
537         v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject);
538         if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
539     }
540     if (This.IsEmpty()) {
541         This = ep->v8engine.global();
542     }
543
544     v8::Local<v8::Value> result = v8function->Call(This, 0, 0);
545
546     if (secondaryScope) 
547         ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
548
549     if (isUndefined)
550         *isUndefined = try_catch.HasCaught() || result->IsUndefined();
551
552     if (watcher.wasDeleted()) {
553     } else if (try_catch.HasCaught()) {
554         v8::Local<v8::Message> message = try_catch.Message();
555         if (!message.IsEmpty()) {
556             QDeclarativeExpressionPrivate::exceptionToError(message, error);
557         } else {
558             error = QDeclarativeError();
559         }
560     } else {
561         error = QDeclarativeError();
562     }
563
564     return result;
565 }
566
567 void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
568 {
569     Q_ASSERT(guardObject);
570     Q_ASSERT(guardObjectNotifyIndex != -1);
571
572     if (properties.count() != guardListLength) {
573         QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
574
575         for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) 
576            guardList[ii].copyAndClear(newGuardList[ii]);
577
578         delete [] guardList;
579         guardList = newGuardList;
580         guardListLength = properties.count();
581     }
582
583     bool outputWarningHeader = false;
584     bool noChanges = true;
585     for (int ii = 0; ii < properties.count(); ++ii) {
586         QDeclarativeNotifierEndpoint &guard = guardList[ii];
587         const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
588
589         guard.target = guardObject;
590         guard.targetMethod = guardObjectNotifyIndex;
591
592         if (property.notifier != 0) {
593
594             if (!noChanges && guard.isConnected(property.notifier)) {
595                 // Nothing to do
596
597             } else {
598                 noChanges = false;
599
600                 bool existing = false;
601                 for (int jj = 0; !existing && jj < ii; ++jj) 
602                     if (guardList[jj].isConnected(property.notifier)) 
603                         existing = true;
604
605                 if (existing) {
606                     // duplicate
607                     guard.disconnect();
608                 } else {
609                     guard.connect(property.notifier);
610                 }
611             }
612
613
614         } else if (property.notifyIndex != -1) {
615
616             if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
617                 // Nothing to do
618
619             } else {
620                 noChanges = false;
621
622                 bool existing = false;
623                 for (int jj = 0; !existing && jj < ii; ++jj) 
624                     if (guardList[jj].isConnected(property.object, property.notifyIndex)) 
625                         existing = true;
626
627                 if (existing) {
628                     // duplicate
629                     guard.disconnect();
630                 } else {
631                     guard.connect(property.object, property.notifyIndex);
632                 }
633             }
634
635         } else {
636             if (!outputWarningHeader) {
637                 outputWarningHeader = true;
638                 qWarning() << "QDeclarativeExpression: Expression" << expression
639                            << "depends on non-NOTIFYable properties:";
640             }
641
642             const QMetaObject *metaObj = property.object->metaObject();
643             QMetaProperty metaProp = metaObj->property(property.coreIndex);
644
645             qWarning().nospace() << "    " << metaObj->className() << "::" << metaProp.name();
646         }
647     }
648 }
649
650 // Must be called with a valid handle scope
651 v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
652 {
653     if (!expressionFunctionValid) {
654         QDeclarativeEngine *engine = context()->engine;
655         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
656
657         QDeclarativeRewrite::RewriteBinding rewriteBinding;
658         rewriteBinding.setName(name);
659         bool ok = true;
660         const QString code = rewriteBinding(expression, &ok);
661         if (ok) v8function = evalFunction(context(), scopeObject, code, url, line, &v8qmlscope);
662         expressionFunctionMode = ExplicitContext;
663         expressionFunctionValid = true;
664     }
665
666     return QDeclarativeQtScriptExpression::v8value(secondaryScope, isUndefined);
667 }
668
669 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
670 {
671     Q_Q(QDeclarativeExpression);
672
673     if (!context() || !context()->isValid()) {
674         qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
675         return QVariant();
676     }
677
678     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
679     QVariant rv;
680
681     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
682
683     {
684         v8::HandleScope handle_scope;
685         v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
686         rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >());
687     }
688
689     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
690
691     return rv;
692 }
693
694 /*!
695     Evaulates the expression, returning the result of the evaluation,
696     or an invalid QVariant if the expression is invalid or has an error.
697
698     \a valueIsUndefined is set to true if the expression resulted in an
699     undefined value.
700
701     \sa hasError(), error()
702 */
703 QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
704 {
705     Q_D(QDeclarativeExpression);
706     return d->value(0, valueIsUndefined);
707 }
708
709 /*!
710 Returns true if the valueChanged() signal is emitted when the expression's evaluated
711 value changes.
712 */
713 bool QDeclarativeExpression::notifyOnValueChanged() const
714 {
715     Q_D(const QDeclarativeExpression);
716     return d->notifyOnValueChange();
717 }
718
719 /*!
720   Sets whether the valueChanged() signal is emitted when the
721   expression's evaluated value changes.
722
723   If \a notifyOnChange is true, the QDeclarativeExpression will
724   monitor properties involved in the expression's evaluation, and emit
725   QDeclarativeExpression::valueChanged() if they have changed.  This
726   allows an application to ensure that any value associated with the
727   result of the expression remains up to date.
728
729   If \a notifyOnChange is false (default), the QDeclarativeExpression
730   will not montitor properties involved in the expression's
731   evaluation, and QDeclarativeExpression::valueChanged() will never be
732   emitted.  This is more efficient if an application wants a "one off"
733   evaluation of the expression.
734 */
735 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
736 {
737     Q_D(QDeclarativeExpression);
738     d->setNotifyOnValueChange(notifyOnChange);
739 }
740
741 /*!
742     Returns the source file URL for this expression.  The source location must
743     have been previously set by calling setSourceLocation().
744 */
745 QString QDeclarativeExpression::sourceFile() const
746 {
747     Q_D(const QDeclarativeExpression);
748     return d->url;
749 }
750
751 /*!
752     Returns the source file line number for this expression.  The source location 
753     must have been previously set by calling setSourceLocation().
754 */
755 int QDeclarativeExpression::lineNumber() const
756 {
757     Q_D(const QDeclarativeExpression);
758     return d->line;
759 }
760
761 /*!
762     Set the location of this expression to \a line of \a url. This information
763     is used by the script engine.
764 */
765 void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
766 {
767     Q_D(QDeclarativeExpression);
768     d->url = url;
769     d->line = line;
770 }
771
772 /*!
773     Returns the expression's scope object, if provided, otherwise 0.
774
775     In addition to data provided by the expression's QDeclarativeContext, the scope
776     object's properties are also in scope during the expression's evaluation.
777 */
778 QObject *QDeclarativeExpression::scopeObject() const
779 {
780     Q_D(const QDeclarativeExpression);
781     return d->scopeObject;
782 }
783
784 /*!
785     Returns true if the last call to evaluate() resulted in an error,
786     otherwise false.
787     
788     \sa error(), clearError()
789 */
790 bool QDeclarativeExpression::hasError() const
791 {
792     Q_D(const QDeclarativeExpression);
793     return d->error.isValid();
794 }
795
796 /*!
797     Clear any expression errors.  Calls to hasError() following this will
798     return false.
799
800     \sa hasError(), error()
801 */
802 void QDeclarativeExpression::clearError()
803 {
804     Q_D(QDeclarativeExpression);
805     d->error = QDeclarativeError();
806 }
807
808 /*!
809     Return any error from the last call to evaluate().  If there was no error,
810     this returns an invalid QDeclarativeError instance.
811
812     \sa hasError(), clearError()
813 */
814
815 QDeclarativeError QDeclarativeExpression::error() const
816 {
817     Q_D(const QDeclarativeExpression);
818     return d->error;
819 }
820
821 /*! \internal */
822 void QDeclarativeExpressionPrivate::_q_notify()
823 {
824     emitValueChanged();
825 }
826
827 void QDeclarativeQtScriptExpression::clearGuards()
828 {
829     delete [] guardList; 
830     guardList = 0; 
831     guardListLength = 0;
832 }
833
834 /*!
835     \fn void QDeclarativeExpression::valueChanged()
836
837     Emitted each time the expression value changes from the last time it was
838     evaluated.  The expression must have been evaluated at least once (by
839     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
840 */
841
842 void QDeclarativeExpressionPrivate::emitValueChanged()
843 {
844     Q_Q(QDeclarativeExpression);
845     emit q->valueChanged();
846 }
847
848 QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
849 : m_context(0), m_prevExpression(0), m_nextExpression(0)
850 {
851 }
852
853 QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
854 {
855     if (m_prevExpression) {
856         *m_prevExpression = m_nextExpression;
857         if (m_nextExpression) 
858             m_nextExpression->m_prevExpression = m_prevExpression;
859     }
860 }
861
862 QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
863 {
864     return m_context;
865 }
866
867 void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
868 {
869     if (m_prevExpression) {
870         *m_prevExpression = m_nextExpression;
871         if (m_nextExpression) 
872             m_nextExpression->m_prevExpression = m_prevExpression;
873         m_prevExpression = 0;
874         m_nextExpression = 0;
875     }
876
877     m_context = context;
878
879     if (m_context) {
880         m_nextExpression = m_context->expressions;
881         if (m_nextExpression) 
882             m_nextExpression->m_prevExpression = &m_nextExpression;
883         m_prevExpression = &context->expressions;
884         m_context->expressions = this;
885     }
886 }
887
888 void QDeclarativeAbstractExpression::refresh()
889 {
890 }
891
892 bool QDeclarativeAbstractExpression::isValid() const
893 {
894     return m_context != 0;
895 }
896
897 QT_END_NAMESPACE
898
899 #include <moc_qdeclarativeexpression.cpp>