Merge branch 'master' of git://gitorious.org/qt/qtdeclarative into api_changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlexpression.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlexpression.h"
43 #include "qqmlexpression_p.h"
44
45 #include "qqmlengine_p.h"
46 #include "qqmlcontext_p.h"
47 #include "qqmlrewrite_p.h"
48 #include "qqmlscriptstring_p.h"
49 #include "qqmlcompiler_p.h"
50
51 #include <QtCore/qdebug.h>
52
53 QT_BEGIN_NAMESPACE
54
55 bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
56 {
57     if (!e) return false;
58
59     if (e->inProgressCreations == 0) return false; // Not in construction
60
61     if (prevError) return true; // Already in error chain
62
63     prevError = &e->erroredBindings;
64     nextError = e->erroredBindings;
65     e->erroredBindings = this;
66     if (nextError) nextError->prevError = &nextError;
67
68     return true;
69 }
70
71 QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
72 : m_vtable(v)
73 {
74 }
75
76 QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
77 {
78     clearGuards();
79 }
80
81 static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
82     QQmlExpressionPrivate::expressionIdentifier,
83     QQmlExpressionPrivate::expressionChanged
84 };
85
86 QQmlExpressionPrivate::QQmlExpressionPrivate()
87 : QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable),
88   expressionFunctionValid(true), expressionFunctionRewritten(false),
89   extractExpressionFromFunction(false), line(-1), dataRef(0)
90 {
91 }
92
93 QQmlExpressionPrivate::~QQmlExpressionPrivate()
94 {
95     qPersistentDispose(v8qmlscope);
96     qPersistentDispose(v8function);
97     if (dataRef) dataRef->release();
98     dataRef = 0;
99 }
100
101 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, 
102                                          QObject *me)
103 {
104     expression = expr;
105
106     QQmlAbstractExpression::setContext(ctxt);
107     setScopeObject(me);
108     expressionFunctionValid = false;
109     expressionFunctionRewritten = false;
110 }
111
112 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, v8::Handle<v8::Function> func,
113                                          QObject *me)
114 {
115     QQmlAbstractExpression::setContext(ctxt);
116     setScopeObject(me);
117
118     v8function = qPersistentNew<v8::Function>(func);
119     setUseSharedContext(false);
120     expressionFunctionValid = true;
121     expressionFunctionRewritten = false;
122     extractExpressionFromFunction = true;
123 }
124
125 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
126                                          bool isRewritten, QObject *me, const QString &srcUrl,
127                                          int lineNumber, int columnNumber)
128 {
129     url = srcUrl;
130     line = lineNumber;
131     column = columnNumber;
132
133     expression = expr;
134
135     expressionFunctionValid = false;
136     expressionFunctionRewritten = isRewritten;
137
138     QQmlAbstractExpression::setContext(ctxt);
139     setScopeObject(me);
140 }
141
142 void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
143                                          bool isRewritten, QObject *me, const QString &srcUrl,
144                                          int lineNumber, int columnNumber)
145 {
146     url = srcUrl;
147     line = lineNumber;
148     column = columnNumber;
149
150     if (isRewritten) {
151         expressionFunctionValid = true;
152         expressionFunctionRewritten = true;
153         v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
154                                   srcUrl, lineNumber, &v8qmlscope);
155         setUseSharedContext(false);
156
157         expressionUtf8 = expr;
158     } else {
159         expression = QString::fromUtf8(expr);
160
161         expressionFunctionValid = false;
162         expressionFunctionRewritten = isRewritten;
163     }
164
165     QQmlAbstractExpression::setContext(ctxt);
166     setScopeObject(me);
167 }
168
169 // Callee owns the persistent handle
170 v8::Persistent<v8::Function>
171 QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
172                                             const char *code, int codeLength,
173                                             const QString &filename, int line,
174                                             v8::Persistent<v8::Object> *qmlscope)
175 {
176     QQmlEngine *engine = ctxt->engine;
177     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
178
179     v8::HandleScope handle_scope;
180     v8::Context::Scope ctxtscope(ep->v8engine()->context());
181
182     v8::TryCatch tc;
183     v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
184     v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
185     if (tc.HasCaught()) {
186         QQmlError error;
187         error.setDescription(QLatin1String("Exception occurred during function compilation"));
188         error.setLine(line);
189         error.setUrl(QUrl::fromLocalFile(filename));
190         v8::Local<v8::Message> message = tc.Message();
191         if (!message.IsEmpty())
192             QQmlExpressionPrivate::exceptionToError(message, error);
193         ep->warning(error);
194         return v8::Persistent<v8::Function>();
195     }
196     v8::Local<v8::Value> result = script->Run(scopeobject);
197     if (tc.HasCaught()) {
198         QQmlError error;
199         error.setDescription(QLatin1String("Exception occurred during function evaluation"));
200         error.setLine(line);
201         error.setUrl(QUrl::fromLocalFile(filename));
202         v8::Local<v8::Message> message = tc.Message();
203         if (!message.IsEmpty())
204             QQmlExpressionPrivate::exceptionToError(message, error);
205         ep->warning(error);
206         return v8::Persistent<v8::Function>();
207     }
208     if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
209     return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
210 }
211
212 // Callee owns the persistent handle
213 v8::Persistent<v8::Function> 
214 QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope, 
215                                             const QString &code, const QString &filename, int line,
216                                             v8::Persistent<v8::Object> *qmlscope)
217 {
218     QQmlEngine *engine = ctxt->engine;
219     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
220
221     v8::HandleScope handle_scope;
222     v8::Context::Scope ctxtscope(ep->v8engine()->context());
223
224     v8::TryCatch tc;
225     v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
226     v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
227     if (tc.HasCaught()) {
228         QQmlError error;
229         error.setDescription(QLatin1String("Exception occurred during function compilation"));
230         error.setLine(line);
231         error.setUrl(QUrl::fromLocalFile(filename));
232         v8::Local<v8::Message> message = tc.Message();
233         if (!message.IsEmpty())
234             QQmlExpressionPrivate::exceptionToError(message, error);
235         ep->warning(error);
236         return v8::Persistent<v8::Function>();
237     }
238     v8::Local<v8::Value> result = script->Run(scopeobject);
239     if (tc.HasCaught()) {
240         QQmlError error;
241         error.setDescription(QLatin1String("Exception occurred during function evaluation"));
242         error.setLine(line);
243         error.setUrl(QUrl::fromLocalFile(filename));
244         v8::Local<v8::Message> message = tc.Message();
245         if (!message.IsEmpty())
246             QQmlExpressionPrivate::exceptionToError(message, error);
247         ep->warning(error);
248         return v8::Persistent<v8::Function>();
249     }
250     if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
251     return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
252 }
253
254 QQmlExpression *
255 QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
256                                       const QString &expr, bool isRewritten,
257                                       const QString &url, int lineNumber, int columnNumber)
258 {
259     return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QQmlExpressionPrivate);
260 }
261
262 /*!
263     \class QQmlExpression
264     \since 4.7
265     \brief The QQmlExpression class evaluates JavaScript in a QML context.
266
267     For example, given a file \c main.qml like this:
268
269     \qml
270     import QtQuick 2.0
271
272     Item {
273         width: 200; height: 200
274     }
275     \endqml
276
277     The following code evaluates a JavaScript expression in the context of the
278     above QML:
279
280     \code
281     QQmlEngine *engine = new QQmlEngine;
282     QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
283
284     QObject *myObject = component.create();
285     QQmlExpression *expr = new QQmlExpression(engine->rootContext(), myObject, "width * 2");
286     int result = expr->evaluate().toInt();  // result = 400
287     \endcode
288 */
289
290 /*!
291     Create an invalid QQmlExpression.
292
293     As the expression will not have an associated QQmlContext, this will be a
294     null expression object and its value will always be an invalid QVariant.
295  */
296 QQmlExpression::QQmlExpression()
297 : QObject(*new QQmlExpressionPrivate, 0)
298 {
299 }
300
301 /*!  \internal */
302 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, 
303                                                QObject *object, const QString &expr, bool isRewritten,
304                                                const QString &url, int lineNumber, int columnNumber,
305                                                QQmlExpressionPrivate &dd)
306 : QObject(dd, 0)
307 {
308     Q_D(QQmlExpression);
309     d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
310 }
311
312 /*!  \internal */
313 QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
314                                                QObject *object, const QByteArray &expr,
315                                                bool isRewritten,
316                                                const QString &url, int lineNumber, int columnNumber,
317                                                QQmlExpressionPrivate &dd)
318 : QObject(dd, 0)
319 {
320     Q_D(QQmlExpression);
321     d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
322 }
323
324 /*!
325     Create a QQmlExpression object that is a child of \a parent.
326
327     The \script provides the expression to be evaluated, the context to evaluate it in,
328     and the scope object to evaluate it with.
329
330     This constructor is functionally equivalent to the following, but in most cases
331     is more efficient.
332     \code
333     QQmlExpression expression(script.context(), script.scopeObject(), script.script(), parent);
334     \endcode
335
336     \sa QQmlScriptString
337 */
338 QQmlExpression::QQmlExpression(const QQmlScriptString &script, QObject *parent)
339 : QObject(*new QQmlExpressionPrivate, parent)
340 {
341     Q_D(QQmlExpression);
342     bool defaultConstruction = false;
343
344     int id = script.d.data()->bindingId;
345     if (id < 0) {
346         defaultConstruction = true;
347     } else {
348         QQmlContextData *ctxtdata = QQmlContextData::get(script.context());
349
350         QQmlEnginePrivate *engine = QQmlEnginePrivate::get(script.context()->engine());
351         QQmlCompiledData *cdata = 0;
352         QQmlTypeData *typeData = 0;
353         if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
354             typeData = engine->typeLoader.get(ctxtdata->url);
355             cdata = typeData->compiledData();
356         }
357
358         if (cdata)
359             d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
360                     cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
361         else
362            defaultConstruction = true;
363
364         if (cdata)
365             cdata->release();
366         if (typeData)
367             typeData->release();
368     }
369
370     if (defaultConstruction)
371         d->init(QQmlContextData::get(script.context()), script.script(), script.scopeObject());
372 }
373
374 /*!
375     Create a QQmlExpression object that is a child of \a parent.
376
377     The \a expression JavaScript will be executed in the \a ctxt QQmlContext.
378     If specified, the \a scope object's properties will also be in scope during
379     the expression's execution.
380 */
381 QQmlExpression::QQmlExpression(QQmlContext *ctxt,
382                                                QObject *scope,
383                                                const QString &expression,
384                                                QObject *parent)
385 : QObject(*new QQmlExpressionPrivate, parent)
386 {
387     Q_D(QQmlExpression);
388     d->init(QQmlContextData::get(ctxt), expression, scope);
389 }
390
391 /*! 
392     \internal
393 */
394 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
395                                                const QString &expression)
396 : QObject(*new QQmlExpressionPrivate, 0)
397 {
398     Q_D(QQmlExpression);
399     d->init(ctxt, expression, scope);
400 }
401
402 /*!  \internal */
403 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
404                                                const QString &expression, QQmlExpressionPrivate &dd)
405 : QObject(dd, 0)
406 {
407     Q_D(QQmlExpression);
408     d->init(ctxt, expression, scope);
409 }
410
411 /*!  
412     \internal 
413
414     To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
415     For example:
416         v8::Handle<v8::Function> function;
417         new QQmlExpression(ctxt, scope, &function, ...);
418  */
419 QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, void *functionPtr,
420                                                QQmlExpressionPrivate &dd)
421 : QObject(dd, 0)
422 {
423     v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
424
425     Q_D(QQmlExpression);
426     d->init(ctxt, function, scope);
427 }
428
429 /*!
430     Destroy the QQmlExpression instance.
431 */
432 QQmlExpression::~QQmlExpression()
433 {
434 }
435
436 /*!
437     Returns the QQmlEngine this expression is associated with, or 0 if there
438     is no association or the QQmlEngine has been destroyed.
439 */
440 QQmlEngine *QQmlExpression::engine() const
441 {
442     Q_D(const QQmlExpression);
443     return d->context()?d->context()->engine:0;
444 }
445
446 /*!
447     Returns the QQmlContext this expression is associated with, or 0 if there
448     is no association or the QQmlContext has been destroyed.
449 */
450 QQmlContext *QQmlExpression::context() const
451 {
452     Q_D(const QQmlExpression);
453     QQmlContextData *data = d->context();
454     return data?data->asQQmlContext():0;
455 }
456
457 /*!
458     Returns the expression string.
459 */
460 QString QQmlExpression::expression() const
461 {
462     Q_D(const QQmlExpression);
463     if (d->extractExpressionFromFunction && context()->engine()) {
464         QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(context()->engine());
465         v8::HandleScope handle_scope;
466         v8::Context::Scope scope(v8engine->context());
467
468         return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
469     } else if (!d->expressionUtf8.isEmpty()) {
470         return QString::fromUtf8(d->expressionUtf8);
471     } else {
472         return d->expression;
473     }
474 }
475
476 /*!
477     Set the expression to \a expression.
478 */
479 void QQmlExpression::setExpression(const QString &expression)
480 {
481     Q_D(QQmlExpression);
482
483     d->resetNotifyOnValueChanged();
484     d->expression = expression;
485     d->expressionUtf8.clear();
486     d->expressionFunctionValid = false;
487     d->expressionFunctionRewritten = false;
488     qPersistentDispose(d->v8function);
489     qPersistentDispose(d->v8qmlscope);
490 }
491
492 void QQmlExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
493                                                      QQmlError &error)
494 {
495     Q_ASSERT(!message.IsEmpty());
496
497     v8::Handle<v8::Value> name = message->GetScriptResourceName();
498     v8::Handle<v8::String> description = message->Get();
499     int lineNumber = message->GetLineNumber();
500
501     v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
502     if (file.IsEmpty() || file->Length() == 0) 
503         error.setUrl(QUrl(QLatin1String("<Unknown File>")));
504     else 
505         error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
506
507     error.setLine(lineNumber);
508     error.setColumn(-1);
509
510     QString qDescription = QV8Engine::toStringStatic(description);
511     if (qDescription.startsWith(QLatin1String("Uncaught ")))
512         qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
513
514     error.setDescription(qDescription);
515 }
516
517 void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
518 {
519     activeGuards.setFlagValue(v);
520     if (!v) clearGuards();
521 }
522
523 void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
524 {
525     clearGuards();
526 }
527
528 v8::Local<v8::Value>
529 QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
530                                            v8::Handle<v8::Function> function, bool *isUndefined)
531 {
532     Q_ASSERT(context && context->engine);
533
534     if (function.IsEmpty() || function->IsUndefined()) {
535         if (isUndefined) *isUndefined = true;
536         return v8::Local<v8::Value>();
537     }
538
539     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
540
541     Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
542     GuardCapture capture(context->engine, this);
543
544     QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
545     ep->propertyCapture = notifyOnValueChanged()?&capture:0;
546
547
548     if (notifyOnValueChanged())
549         capture.guards.copyAndClearPrepend(activeGuards);
550
551     QQmlContextData *lastSharedContext = 0;
552     QObject *lastSharedScope = 0;
553
554     bool sharedContext = useSharedContext();
555
556     // All code that follows must check with watcher before it accesses data members 
557     // incase we have been deleted.
558     DeleteWatcher watcher(this);
559
560     if (sharedContext) {
561         lastSharedContext = ep->sharedContext;
562         lastSharedScope = ep->sharedScope;
563         ep->sharedContext = context;
564         ep->sharedScope = scopeObject();
565     }
566
567     v8::Local<v8::Value> result;
568     {
569         v8::TryCatch try_catch;
570         v8::Handle<v8::Object> This = ep->v8engine()->global();
571         if (scopeObject() && requiresThisObject()) {
572             v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
573             if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
574         }
575
576         result = function->Call(This, 0, 0);
577
578         if (isUndefined)
579             *isUndefined = try_catch.HasCaught() || result->IsUndefined();
580
581         if (watcher.wasDeleted()) {
582         } else if (try_catch.HasCaught()) {
583             v8::Context::Scope scope(ep->v8engine()->context());
584             v8::Local<v8::Message> message = try_catch.Message();
585             if (!message.IsEmpty()) {
586                 QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
587             } else {
588                 if (hasDelayedError()) delayedError()->error = QQmlError();
589             }
590         } else {
591             if (hasDelayedError()) delayedError()->error = QQmlError();
592         }
593     }
594
595     if (sharedContext) {
596         ep->sharedContext = lastSharedContext;
597         ep->sharedScope = lastSharedScope;
598     }
599
600     if (capture.errorString) {
601         for (int ii = 0; ii < capture.errorString->count(); ++ii)
602             qWarning("%s", qPrintable(capture.errorString->at(ii)));
603         delete capture.errorString;
604         capture.errorString = 0;
605     }
606
607     while (Guard *g = capture.guards.takeFirst())
608         g->Delete();
609
610     ep->propertyCapture = lastPropertyCapture;
611
612     return result;
613 }
614
615 void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
616 {
617     if (expression) {
618
619         // Try and find a matching guard
620         while (!guards.isEmpty() && !guards.first()->isConnected(n))
621             guards.takeFirst()->Delete();
622
623         Guard *g = 0;
624         if (!guards.isEmpty()) {
625             g = guards.takeFirst();
626             g->cancelNotify();
627             Q_ASSERT(g->isConnected(n));
628         } else {
629             g = Guard::New(expression, engine);
630             g->connect(n);
631         }
632
633         expression->activeGuards.prepend(g);
634     }
635 }
636
637 void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
638 {
639     if (expression) {
640         if (n == -1) {
641             if (!errorString) {
642                 errorString = new QStringList;
643                 QString preamble = QLatin1String("QQmlExpression: Expression ") +
644                                    expression->m_vtable->expressionIdentifier(expression) +
645                                    QLatin1String(" depends on non-NOTIFYable properties:");
646                 errorString->append(preamble);
647             }
648
649             const QMetaObject *metaObj = o->metaObject();
650             QMetaProperty metaProp = metaObj->property(c);
651
652             QString error = QLatin1String("    ") +
653                             QString::fromUtf8(metaObj->className()) +
654                             QLatin1String("::") +
655                             QString::fromUtf8(metaProp.name());
656             errorString->append(error);
657         } else {
658
659             // Try and find a matching guard
660             while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
661                 guards.takeFirst()->Delete();
662
663             Guard *g = 0;
664             if (!guards.isEmpty()) {
665                 g = guards.takeFirst();
666                 g->cancelNotify();
667                 Q_ASSERT(g->isConnected(o, n));
668             } else {
669                 g = Guard::New(expression, engine);
670                 g->connect(o, n);
671             }
672
673             expression->activeGuards.prepend(g);
674         }
675     }
676 }
677
678 void QQmlJavaScriptExpression::clearError()
679 {
680     if (m_vtable.hasValue()) {
681         m_vtable.value().error = QQmlError();
682         m_vtable.value().removeError();
683     }
684 }
685
686 QQmlError QQmlJavaScriptExpression::error() const
687 {
688     if (m_vtable.hasValue()) return m_vtable.constValue()->error;
689     else return QQmlError();
690 }
691
692 QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
693 {
694     return &m_vtable.value();
695 }
696
697 void QQmlJavaScriptExpression::clearGuards()
698 {
699     while (Guard *g = activeGuards.takeFirst())
700         g->Delete();
701 }
702
703 // Must be called with a valid handle scope
704 v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
705 {
706     if (!expressionFunctionValid) {
707         bool ok = true;
708
709         QQmlRewrite::RewriteBinding rewriteBinding;
710         rewriteBinding.setName(name);
711         QString code;
712         if (expressionFunctionRewritten)
713             code = expression;
714         else
715             code = rewriteBinding(expression, &ok);
716
717         if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
718         setUseSharedContext(false);
719         expressionFunctionValid = true;
720     }
721
722
723     if (secondaryScope) {
724         v8::Local<v8::Value> result;
725         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
726         QObject *restoreSecondaryScope = 0;
727         restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
728         result = evaluate(context(), v8function, isUndefined);
729         ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
730         return result;
731     } else {
732         return evaluate(context(), v8function, isUndefined);
733     }
734 }
735
736 QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
737 {
738     Q_Q(QQmlExpression);
739
740     if (!context() || !context()->isValid()) {
741         qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
742         return QVariant();
743     }
744
745     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(q->engine());
746     QVariant rv;
747
748     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
749
750     {
751         v8::HandleScope handle_scope;
752         v8::Context::Scope context_scope(ep->v8engine()->context());
753         v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
754         rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
755     }
756
757     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
758
759     return rv;
760 }
761
762 /*!
763     Evaulates the expression, returning the result of the evaluation,
764     or an invalid QVariant if the expression is invalid or has an error.
765
766     \a valueIsUndefined is set to true if the expression resulted in an
767     undefined value.
768
769     \sa hasError(), error()
770 */
771 QVariant QQmlExpression::evaluate(bool *valueIsUndefined)
772 {
773     Q_D(QQmlExpression);
774     return d->value(0, valueIsUndefined);
775 }
776
777 /*!
778 Returns true if the valueChanged() signal is emitted when the expression's evaluated
779 value changes.
780 */
781 bool QQmlExpression::notifyOnValueChanged() const
782 {
783     Q_D(const QQmlExpression);
784     return d->notifyOnValueChanged();
785 }
786
787 /*!
788   Sets whether the valueChanged() signal is emitted when the
789   expression's evaluated value changes.
790
791   If \a notifyOnChange is true, the QQmlExpression will
792   monitor properties involved in the expression's evaluation, and emit
793   QQmlExpression::valueChanged() if they have changed.  This
794   allows an application to ensure that any value associated with the
795   result of the expression remains up to date.
796
797   If \a notifyOnChange is false (default), the QQmlExpression
798   will not montitor properties involved in the expression's
799   evaluation, and QQmlExpression::valueChanged() will never be
800   emitted.  This is more efficient if an application wants a "one off"
801   evaluation of the expression.
802 */
803 void QQmlExpression::setNotifyOnValueChanged(bool notifyOnChange)
804 {
805     Q_D(QQmlExpression);
806     d->setNotifyOnValueChanged(notifyOnChange);
807 }
808
809 /*!
810     Returns the source file URL for this expression.  The source location must
811     have been previously set by calling setSourceLocation().
812 */
813 QString QQmlExpression::sourceFile() const
814 {
815     Q_D(const QQmlExpression);
816     return d->url;
817 }
818
819 /*!
820     Returns the source file line number for this expression.  The source location 
821     must have been previously set by calling setSourceLocation().
822 */
823 int QQmlExpression::lineNumber() const
824 {
825     Q_D(const QQmlExpression);
826     return d->line;
827 }
828
829 /*!
830     Returns the source file column number for this expression.  The source location
831     must have been previously set by calling setSourceLocation().
832 */
833 int QQmlExpression::columnNumber() const
834 {
835     Q_D(const QQmlExpression);
836     return d->column;
837 }
838
839 /*!
840     Set the location of this expression to \a line of \a url. This information
841     is used by the script engine.
842 */
843 void QQmlExpression::setSourceLocation(const QString &url, int line, int column)
844 {
845     Q_D(QQmlExpression);
846     d->url = url;
847     d->line = line;
848     d->column = column;
849 }
850
851 /*!
852     Returns the expression's scope object, if provided, otherwise 0.
853
854     In addition to data provided by the expression's QQmlContext, the scope
855     object's properties are also in scope during the expression's evaluation.
856 */
857 QObject *QQmlExpression::scopeObject() const
858 {
859     Q_D(const QQmlExpression);
860     return d->scopeObject();
861 }
862
863 /*!
864     Returns true if the last call to evaluate() resulted in an error,
865     otherwise false.
866     
867     \sa error(), clearError()
868 */
869 bool QQmlExpression::hasError() const
870 {
871     Q_D(const QQmlExpression);
872     return d->hasError();
873 }
874
875 /*!
876     Clear any expression errors.  Calls to hasError() following this will
877     return false.
878
879     \sa hasError(), error()
880 */
881 void QQmlExpression::clearError()
882 {
883     Q_D(QQmlExpression);
884     d->clearError();
885 }
886
887 /*!
888     Return any error from the last call to evaluate().  If there was no error,
889     this returns an invalid QQmlError instance.
890
891     \sa hasError(), clearError()
892 */
893
894 QQmlError QQmlExpression::error() const
895 {
896     Q_D(const QQmlExpression);
897     return d->error();
898 }
899
900 /*!
901     \fn void QQmlExpression::valueChanged()
902
903     Emitted each time the expression value changes from the last time it was
904     evaluated.  The expression must have been evaluated at least once (by
905     calling QQmlExpression::evaluate()) before this signal will be emitted.
906 */
907
908 void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e)
909 {
910     QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
911     This->expressionChanged();
912 }
913
914 void QQmlExpressionPrivate::expressionChanged()
915 {
916     Q_Q(QQmlExpression);
917     emit q->valueChanged();
918 }
919
920 QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e)
921 {
922     QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
923     return QLatin1String("\"") + This->expression + QLatin1String("\"");
924 }
925
926 QQmlAbstractExpression::QQmlAbstractExpression()
927 : m_prevExpression(0), m_nextExpression(0)
928 {
929 }
930
931 QQmlAbstractExpression::~QQmlAbstractExpression()
932 {
933     if (m_prevExpression) {
934         *m_prevExpression = m_nextExpression;
935         if (m_nextExpression) 
936             m_nextExpression->m_prevExpression = m_prevExpression;
937     }
938
939     if (m_context.isT2())
940         m_context.asT2()->_s = 0;
941 }
942
943 QQmlContextData *QQmlAbstractExpression::context() const
944 {
945     if (m_context.isT1()) return m_context.asT1();
946     else return m_context.asT2()->_c;
947 }
948
949 void QQmlAbstractExpression::setContext(QQmlContextData *context)
950 {
951     if (m_prevExpression) {
952         *m_prevExpression = m_nextExpression;
953         if (m_nextExpression) 
954             m_nextExpression->m_prevExpression = m_prevExpression;
955         m_prevExpression = 0;
956         m_nextExpression = 0;
957     }
958
959     if (m_context.isT1()) m_context = context;
960     else m_context.asT2()->_c = context;
961
962     if (context) {
963         m_nextExpression = context->expressions;
964         if (m_nextExpression) 
965             m_nextExpression->m_prevExpression = &m_nextExpression;
966         m_prevExpression = &context->expressions;
967         context->expressions = this;
968     }
969 }
970
971 void QQmlAbstractExpression::refresh()
972 {
973 }
974
975 bool QQmlAbstractExpression::isValid() const
976 {
977     return context() != 0;
978 }
979
980 QT_END_NAMESPACE
981
982 #include <moc_qqmlexpression.cpp>