Implemented the ecma Date object.
authorRoberto Raggi <roberto.raggi@nokia.com>
Fri, 18 May 2012 12:10:02 +0000 (14:10 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Fri, 18 May 2012 12:10:02 +0000 (14:10 +0200)
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4ecmaobjects.cpp
qv4ecmaobjects_p.h

index 0fdf99b..cf5560e 100644 (file)
@@ -323,7 +323,7 @@ Object *ExecutionEngine::newBooleanPrototype(Context *ctx, FunctionObject *proto
 
 Object *ExecutionEngine::newDateObject(const Value &value)
 {
-    return new Object(); // ### FIXME
+    return new DateObject(value);
 }
 
 FunctionObject *ExecutionEngine::newDateCtor(Context *ctx)
index b2b2ea3..cbbea40 100644 (file)
@@ -21,8 +21,10 @@ struct BooleanObject;
 struct NumberObject;
 struct StringObject;
 struct ArrayObject;
+struct DateObject;
 struct FunctionObject;
 struct ErrorObject;
+struct ArgumentsObject;
 struct Context;
 struct ExecutionEngine;
 
@@ -194,7 +196,14 @@ struct Object {
 
     virtual ~Object();
 
+    virtual BooleanObject *asBooleanObject() { return 0; }
+    virtual NumberObject *asNumberObject() { return 0; }
+    virtual StringObject *asStringObject() { return 0; }
+    virtual DateObject *asDateObject() { return 0; }
+    virtual ArrayObject *asArrayObject() { return 0; }
     virtual FunctionObject *asFunctionObject() { return 0; }
+    virtual ErrorObject *asErrorObject() { return 0; }
+    virtual ArgumentsObject *asArgumentsObject() { return 0; }
 
     bool get(String *name, Value *result);
 
@@ -217,22 +226,33 @@ struct Object {
 struct BooleanObject: Object {
     Value value;
     BooleanObject(const Value &value): value(value) {}
+    virtual BooleanObject *asBooleanObject() { return this; }
     virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
 };
 
 struct NumberObject: Object {
     Value value;
     NumberObject(const Value &value): value(value) {}
+    virtual NumberObject *asNumberObject() { return this; }
     virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
 };
 
 struct StringObject: Object {
     Value value;
     StringObject(const Value &value): value(value) {}
+    virtual StringObject *asStringObject() { return this; }
+    virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
+};
+
+struct DateObject: Object {
+    Value value;
+    DateObject(const Value &value): value(value) {}
+    virtual DateObject *asDateObject() { return this; }
     virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
 };
 
 struct ArrayObject: Object {
+    virtual ArrayObject *asArrayObject() { return this; }
 };
 
 struct FunctionObject: Object {
@@ -250,8 +270,8 @@ struct FunctionObject: Object {
         , varList(0)
         , varCount(0)
         , needsActivation(true) {}
-    virtual FunctionObject *asFunctionObject() { return this; }
 
+    virtual FunctionObject *asFunctionObject() { return this; }
     virtual bool hasInstance(const Value &value) const;
     virtual void call(Context *ctx);
     virtual void construct(Context *ctx);
@@ -278,11 +298,13 @@ struct ScriptFunction: FunctionObject {
 struct ErrorObject: Object {
     Value message;
     ErrorObject(const Value &message): message(message) {}
+    virtual ErrorObject *asErrorObject() { return this; }
 };
 
 struct ArgumentsObject: Object {
     Context *context;
     ArgumentsObject(Context *context): context(context) {}
+    virtual ArgumentsObject *asArgumentsObject() { return this; }
     virtual Value *getProperty(String *name, PropertyAttributes *attributes);
 };
 
index 337f2f7..6cb2a93 100644 (file)
@@ -69,6 +69,85 @@ String *Value::toString(Context *ctx) const
     return v.stringValue;
 }
 
+bool Value::isFunctionObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asFunctionObject() != 0 : false;
+}
+
+bool Value::isBooleanObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asBooleanObject() != 0 : false;
+}
+
+bool Value::isNumberObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asNumberObject() != 0 : false;
+}
+
+bool Value::isStringObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asStringObject() != 0 : false;
+}
+
+bool Value::isDateObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asDateObject() != 0 : false;
+}
+
+bool Value::isArrayObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asArrayObject() != 0 : false;
+}
+
+bool Value::isErrorObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asErrorObject() != 0 : false;
+}
+
+bool Value::isArgumentsObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asArgumentsObject() != 0 : false;
+}
+
+FunctionObject *Value::asFunctionObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asFunctionObject() : 0;
+}
+
+BooleanObject *Value::asBooleanObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asBooleanObject() : 0;
+}
+
+NumberObject *Value::asNumberObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asNumberObject() : 0;
+}
+
+StringObject *Value::asStringObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asStringObject() : 0;
+}
+
+DateObject *Value::asDateObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asDateObject() : 0;
+}
+
+ArrayObject *Value::asArrayObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asArrayObject() : 0;
+}
+
+ErrorObject *Value::asErrorObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asErrorObject() : 0;
+}
+
+ArgumentsObject *Value::asArgumentsObject() const
+{
+    return type == OBJECT_TYPE ? objectValue->asArgumentsObject() : 0;
+}
 
 extern "C" {
 
index 223a219..a02ceec 100644 (file)
@@ -40,6 +40,14 @@ struct Value;
 struct Object;
 struct String;
 struct Context;
+struct FunctionObject;
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct DateObject;
+struct ArrayObject;
+struct ErrorObject;
+struct ArgumentsObject;
 
 extern "C" {
 
@@ -228,6 +236,24 @@ struct Value {
     inline bool isBoolean() const { return is(BOOLEAN_TYPE); }
     inline bool isNumber() const { return is(NUMBER_TYPE); }
     inline bool isObject() const { return is(OBJECT_TYPE); }
+
+    bool isFunctionObject() const;
+    bool isBooleanObject() const;
+    bool isNumberObject() const;
+    bool isStringObject() const;
+    bool isDateObject() const;
+    bool isArrayObject() const;
+    bool isErrorObject() const;
+    bool isArgumentsObject() const;
+
+    FunctionObject *asFunctionObject() const;
+    BooleanObject *asBooleanObject() const;
+    NumberObject *asNumberObject() const;
+    StringObject *asStringObject() const;
+    DateObject *asDateObject() const;
+    ArrayObject *asArrayObject() const;
+    ErrorObject *asErrorObject() const;
+    ArgumentsObject *asArgumentsObject() const;
 };
 
 extern "C" {
index 4630502..0131cbf 100644 (file)
@@ -936,7 +936,7 @@ void NumberPrototype::method_toLocaleString(Context *ctx)
     assert(self.isObject());
     //    if (self.classInfo() != classInfo) {
     //        return throwThisObjectTypeError(
-    //            context, QLatin1String("Number.prototype.toLocaleString"));
+    //            ctx, QLatin1String("Number.prototype.toLocaleString"));
     //    }
     Value internalValue;
     self.objectValue->defaultValue(ctx, &internalValue, STRING_HINT);
@@ -950,7 +950,7 @@ void NumberPrototype::method_valueOf(Context *ctx)
     assert(self.isObject());
     //    if (self.classInfo() != classInfo) {
     //        return throwThisObjectTypeError(
-    //            context, QLatin1String("Number.prototype.toLocaleString"));
+    //            ctx, QLatin1String("Number.prototype.toLocaleString"));
     //    }
     Value internalValue;
     self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
@@ -1068,7 +1068,7 @@ void BooleanPrototype::method_toString(Context *ctx)
     Value self = ctx->thisObject;
 //    if (self.classInfo() != classInfo) {
 //        return throwThisObjectTypeError(
-//            context, QLatin1String("Boolean.prototype.toString"));
+//            ctx, QLatin1String("Boolean.prototype.toString"));
 //    }
     assert(self.isObject());
     Value internalValue;
@@ -1083,7 +1083,7 @@ void BooleanPrototype::method_valueOf(Context *ctx)
     Value self = ctx->thisObject;
 //    if (self.classInfo() != classInfo) {
 //        return throwThisObjectTypeError(
-//            context, QLatin1String("Boolean.prototype.valueOf"));
+//            ctx, QLatin1String("Boolean.prototype.valueOf"));
 //    }
     assert(self.isObject());
     Value internalValue;
@@ -1099,7 +1099,7 @@ Value DateCtor::create(ExecutionEngine *engine)
 {
     Context *ctx = engine->rootContext;
     FunctionObject *ctor = ctx->engine->newDateCtor(ctx);
-    ctor->setProperty(ctx, QLatin1String("prototype"), Value::fromObject(ctx->engine->newNumberPrototype(ctx, ctor)));
+    ctor->setProperty(ctx, QLatin1String("prototype"), Value::fromObject(ctx->engine->newDatePrototype(ctx, ctor)));
     return Value::fromObject(ctor);
 }
 
@@ -1110,18 +1110,17 @@ DateCtor::DateCtor(Context *scope)
 
 void DateCtor::construct(Context *ctx)
 {
-    // called as constructor
-    double t;
+    double t = 0;
 
     if (ctx->argumentCount == 0)
         t = currentTime();
 
     else if (ctx->argumentCount == 1) {
         Value arg = ctx->argument(0);
-//        if (arg.isDate())
-//            arg = arg.internalValue();
-//        else
-//          __qmljs_to_primitive(ctx, &arg, &arg, PREFERREDTYPE_HINT);
+        if (DateObject *d = arg.asDateObject())
+            arg = d->value;
+        else
+            __qmljs_to_primitive(ctx, &arg, &arg, PREFERREDTYPE_HINT);
 
         if (arg.isString())
             t = ParseString(arg.toString(ctx)->toQString());
@@ -1129,7 +1128,7 @@ void DateCtor::construct(Context *ctx)
             t = TimeClip(arg.toNumber(ctx));
     }
 
-    else { // context->argumentCount() > 1
+    else { // ctx->argumentCount() > 1
         double year  = ctx->argument(0).toNumber(ctx);
         double month = ctx->argument(1).toNumber(ctx);
         double day  = ctx->argumentCount >= 3 ? ctx->argument(2).toNumber(ctx) : 1;
@@ -1143,11 +1142,8 @@ void DateCtor::construct(Context *ctx)
         t = TimeClip(UTC(t));
     }
 
-//    Value &obj = ctx->m_thisObject;
-//    obj.setClassInfo(classInfo());
-//    obj.setInternalValue(Value(t));
-//    obj.setPrototype(publicPrototype);
-//    ctx->setReturnValue(obj);
+    Object *d = ctx->engine->newDateObject(Value::fromNumber(t));
+    ctx->thisObject = Value::fromObject(d);
 }
 
 void DateCtor::call(Context *ctx)
@@ -1157,6 +1153,7 @@ void DateCtor::call(Context *ctx)
 }
 
 DatePrototype::DatePrototype(Context *ctx, FunctionObject *ctor)
+    : DateObject(Value::fromNumber(qSNaN()))
 {
     LocalTZA = getLocalTZA();
 
@@ -1210,11 +1207,19 @@ DatePrototype::DatePrototype(Context *ctx, FunctionObject *ctor)
     setProperty(ctx, QLatin1String("toGMTString"), method_toUTCString, 0);
 }
 
+DateObject *DatePrototype::getThisDateObject(Context *ctx)
+{
+    assert(ctx->thisObject.isObject());
+    DateObject *date = ctx->thisObject.objectValue->asDateObject();
+    return date;
+}
+
 double DatePrototype::getThisDate(Context *ctx)
 {
     assert(ctx->thisObject.isObject());
-    Value internalValue;
-    ctx->thisObject.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
+    DateObject *date = ctx->thisObject.objectValue->asDateObject();
+    assert(date);
+    Value internalValue = date->value;
     assert(internalValue.isNumber());
     return internalValue.numberValue;
 }
@@ -1449,70 +1454,244 @@ void DatePrototype::method_getTimezoneOffset(Context *ctx)
 
 void DatePrototype::method_setTime(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        self->value.numberValue = TimeClip(ctx->argument(0).toNumber(ctx));
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setMilliseconds(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double ms = ctx->argument(0).toNumber(ctx);
+        self->value.numberValue = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCMilliseconds(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double ms = ctx->argument(0).toNumber(ctx);
+        self->value.numberValue = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setSeconds(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double sec = ctx->argument(0).toNumber(ctx);
+        double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCSeconds(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double sec = ctx->argument(0).toNumber(ctx);
+        double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setMinutes(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double min = ctx->argument(0).toNumber(ctx);
+        double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCMinutes(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double min = ctx->argument(0).toNumber(ctx);
+        double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setHours(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double hour = ctx->argument(0).toNumber(ctx);
+        double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx);
+        double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCHours(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double hour = ctx->argument(0).toNumber(ctx);
+        double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber(ctx);
+        double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setDate(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double date = ctx->argument(0).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCDate(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double date = ctx->argument(0).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setMonth(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double month = ctx->argument(0).toNumber(ctx);
+        double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setUTCMonth(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double month = ctx->argument(0).toNumber(ctx);
+        double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_setYear(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        if (qIsNaN(t))
+            t = 0;
+        else
+            t = LocalTime(t);
+        double year = ctx->argument(0).toNumber(ctx);
+        double r;
+        if (qIsNaN(year)) {
+            r = qSNaN();
+        } else {
+            if ((Value::toInteger(year) >= 0) && (Value::toInteger(year) <= 99))
+                year += 1900;
+            r = MakeDay(year, MonthFromTime(t), DateFromTime(t));
+            r = UTC(MakeDate(r, TimeWithinDay(t)));
+            r = TimeClip(r);
+        }
+        self->value.numberValue = r;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
-void DatePrototype::method_setFullYear(Context *ctx)
+void DatePrototype::method_setUTCFullYear(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        double year = ctx->argument(0).toNumber(ctx);
+        double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
-void DatePrototype::method_setUTCFullYear(Context *ctx)
+void DatePrototype::method_setFullYear(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = LocalTime(self->value.numberValue);
+        double year = ctx->argument(0).toNumber(ctx);
+        double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber(ctx);
+        double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber(ctx);
+        t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+        self->value.numberValue = t;
+        ctx->result = self->value;
+    } else {
+        assert(!"type error");
+    }
 }
 
 void DatePrototype::method_toUTCString(Context *ctx)
 {
+    if (DateObject *self = getThisDateObject(ctx)) {
+        double t = self->value.numberValue;
+        ctx->result = Value::fromString(ctx, ToUTCString(t));
+    }
 }
 
 //
index 68c1522..d4cbf61 100644 (file)
@@ -112,11 +112,12 @@ struct DateCtor: FunctionObject
     virtual void call(Context *ctx);
 };
 
-struct DatePrototype: Object
+struct DatePrototype: DateObject
 {
     DatePrototype(Context *ctx, FunctionObject *ctor);
 
 protected:
+    static DateObject *getThisDateObject(Context *ctx);
     static double getThisDate(Context *ctx);
 
     static void method_MakeTime(Context *ctx);