src/script/api/qscriptengine.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/script/api/qscriptengine.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/script/api/qscriptengine.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -64,6 +64,7 @@
 #include "bridge/qscriptqobject_p.h"
 #include "bridge/qscriptglobalobject_p.h"
 #include "bridge/qscriptactivationobject_p.h"
+#include "bridge/qscriptstaticscopeobject_p.h"
 
 #ifndef QT_NO_QOBJECT
 #include <QtCore/qcoreapplication.h>
@@ -437,6 +438,53 @@
 
 #endif
 
+static const qsreal MsPerSecond = 1000.0;
+
+static inline int MsFromTime(qsreal t)
+{
+    int r = int(::fmod(t, MsPerSecond));
+    return (r >= 0) ? r : r + int(MsPerSecond);
+}
+
+/*!
+  \internal
+  Converts a JS date value (milliseconds) to a QDateTime (local time).
+*/
+QDateTime MsToDateTime(JSC::ExecState *exec, qsreal t)
+{
+    if (qIsNaN(t))
+        return QDateTime();
+    JSC::GregorianDateTime tm;
+    JSC::msToGregorianDateTime(exec, t, /*output UTC=*/true, tm);
+    int ms = MsFromTime(t);
+    QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
+                                       QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
+    return convertedUTC.toLocalTime();
+}
+
+/*!
+  \internal
+  Converts a QDateTime to a JS date value (milliseconds).
+*/
+qsreal DateTimeToMs(JSC::ExecState *exec, const QDateTime &dt)
+{
+    if (!dt.isValid())
+        return qSNaN();
+    QDateTime utc = dt.toUTC();
+    QDate date = utc.date();
+    QTime time = utc.time();
+    JSC::GregorianDateTime tm;
+    tm.year = date.year() - 1900;
+    tm.month = date.month() - 1;
+    tm.monthDay = date.day();
+    tm.weekDay = date.dayOfWeek();
+    tm.yearDay = date.dayOfYear();
+    tm.hour = time.hour();
+    tm.minute = time.minute();
+    tm.second = time.second();
+    return JSC::gregorianDateTimeToMS(exec, tm, time.msec(), /*inputIsUTC=*/true);
+}
+
 void GlobalClientData::mark(JSC::MarkStack& markStack)
 {
     engine->mark(markStack);
@@ -905,6 +953,7 @@
     JSC::ExecState* exec = globalObject->globalExec();
 
     scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
+    staticScopeObjectStructure = QScriptStaticScopeObject::createStructure(JSC::jsNull());
 
     qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
     qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
@@ -1011,12 +1060,17 @@
     return arr;
 }
 
-QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSValue arr)
+QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSArray *arr)
 {
+    QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
+    if (eng->visitedConversionObjects.contains(arr))
+        return QVariantList(); // Avoid recursion.
+    eng->visitedConversionObjects.insert(arr);
     QVariantList lst;
     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
     for (uint i = 0; i < len; ++i)
         lst.append(toVariant(exec, property(exec, arr, i)));
+    eng->visitedConversionObjects.remove(arr);
     return lst;
 }
 
@@ -1029,14 +1083,19 @@
     return obj;
 }
 
-QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSValue obj)
+QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSObject *obj)
 {
+    QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
+    if (eng->visitedConversionObjects.contains(obj))
+        return QVariantMap(); // Avoid recursion.
+    eng->visitedConversionObjects.insert(obj);
     JSC::PropertyNameArray propertyNames(exec);
-    JSC::asObject(obj)->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
+    obj->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
     QVariantMap vmap;
     JSC::PropertyNameArray::const_iterator it = propertyNames.begin();
     for( ; it != propertyNames.end(); ++it)
         vmap.insert(it->ustring(), toVariant(exec, property(exec, obj, *it)));
+    eng->visitedConversionObjects.remove(obj);
     return vmap;
 }
 
@@ -1525,7 +1584,7 @@
 
 #ifndef QT_NO_REGEXP
 
-Q_DECL_IMPORT extern QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
 
 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QRegExp &regexp)
 {
@@ -1661,16 +1720,10 @@
             return QVariant(toRegExp(exec, value));
 #endif
         else if (isArray(value))
-            return variantListFromArray(exec, value);
+            return variantListFromArray(exec, JSC::asArray(value));
         else if (QScriptDeclarativeClass *dc = declarativeClass(value))
             return dc->toVariant(declarativeObject(value));
-        // try to convert to primitive
-        JSC::JSValue savedException;
-        saveException(exec, &savedException);
-        JSC::JSValue prim = value.toPrimitive(exec);
-        restoreException(exec, savedException);
-        if (!prim.isObject())
-            return toVariant(exec, prim);
+        return variantMapFromObject(exec, JSC::asObject(value));
     } else if (value.isNumber()) {
         return QVariant(toNumber(exec, value));
     } else if (value.isString()) {
@@ -1766,15 +1819,7 @@
         } else if (flags != QScriptValue::KeepExistingFlags) {
             if (thisObject->hasOwnProperty(exec, id))
                 thisObject->deleteProperty(exec, id); // ### hmmm - can't we just update the attributes?
-            unsigned attribs = 0;
-            if (flags & QScriptValue::ReadOnly)
-                attribs |= JSC::ReadOnly;
-            if (flags & QScriptValue::SkipInEnumeration)
-                attribs |= JSC::DontEnum;
-            if (flags & QScriptValue::Undeletable)
-                attribs |= JSC::DontDelete;
-            attribs |= flags & QScriptValue::UserRange;
-            thisObject->putWithAttributes(exec, id, value, attribs);
+            thisObject->putWithAttributes(exec, id, value, propertyFlagsToJSCAttributes(flags));
         } else {
             JSC::PutPropertySlot slot;
             thisObject->put(exec, id, value, slot);
@@ -2020,8 +2065,6 @@
 
 #ifndef QT_NO_REGEXP
 
-Q_DECL_IMPORT extern QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-
 /*!
   Creates a QtScript object of class RegExp with the given
   \a regexp.
@@ -3131,12 +3174,12 @@
         } break;
     case QMetaType::QVariantList:
         if (isArray(value)) {
-            *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, value);
+            *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, JSC::asArray(value));
             return true;
         } break;
     case QMetaType::QVariantMap:
         if (isObject(value)) {
-            *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, value);
+            *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, JSC::asObject(value));
             return true;
         } break;
     case QMetaType::QVariant: