Bug 771742 - Reimplement the Date.prototype.set<date component> functions in terms of their spec steps, and remove the hard-to-understand date_makeDate. r=luke

This commit is contained in:
Jeff Walden
2012-07-06 13:53:11 -07:00
parent 4dae381de5
commit 74271f2d37

View File

@@ -2109,125 +2109,253 @@ date_setUTCHours(JSContext *cx, unsigned argc, Value *vp)
return SetUTCTime(cx, thisObj, v, &args.rval());
}
/* ES5 15.9.5.36. */
static JSBool
date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsigned argc, Value *vp)
date_setDate(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject thisObj(cx);
if (!NonGenericMethodGuard(cx, args, native, &DateClass, thisObj.address()))
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setDate, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
double result = thisObj->getDateUTCTime().toNumber();
/* Step 1. */
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
/* See complaint about ECMA in date_makeTime. */
if (args.length() == 0) {
SetDateToNaN(cx, thisObj, &args.rval());
return true;
}
/* Step 2. */
double dt;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt))
return false;
unsigned numNums = Min(args.length(), maxargs);
JS_ASSERT(1 <= numNums && numNums <= 3);
double nums[3];
bool argIsNotFinite = false;
for (unsigned i = 0; i < numNums; i++) {
if (!ToNumber(cx, args[i], &nums[i]))
return JS_FALSE;
if (!MOZ_DOUBLE_IS_FINITE(nums[i])) {
argIsNotFinite = true;
} else {
nums[i] = ToInteger(nums[i]);
}
}
/* Step 3. */
double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
/* If we found a non-finite argument, set the date to NaN and return. */
if (argIsNotFinite) {
SetDateToNaN(cx, thisObj, &args.rval());
return true;
}
/* Step 4. */
double u = TimeClip(UTC(newDate, cx));
/*
* Return NaN if date is NaN and we're not setting the year. If we are,
* use 0 as the time.
*/
double lorutime; /* local or UTC version of *date */
if (!MOZ_DOUBLE_IS_FINITE(result)) {
if (maxargs < 3) {
args.rval().setDouble(result);
return true;
}
lorutime = +0.;
} else {
lorutime = local ? LocalTime(result, cx) : result;
}
double *argp = nums;
double *stop = argp + numNums;
double year;
if (maxargs >= 3 && argp < stop)
year = *argp++;
else
year = YearFromTime(lorutime);
double month;
if (maxargs >= 2 && argp < stop)
month = *argp++;
else
month = MonthFromTime(lorutime);
double day;
if (maxargs >= 1 && argp < stop)
day = *argp++;
else
day = DateFromTime(lorutime);
day = MakeDay(year, month, day); /* day within year */
result = MakeDate(day, TimeWithinDay(lorutime));
if (local)
result = UTC(result, cx);
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
}
static JSBool
date_setDate(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setDate, 1, JS_TRUE, argc, vp);
/* Steps 5-6. */
return SetUTCTime(cx, thisObj, u, &args.rval());
}
/* ES5 15.9.5.37. */
static JSBool
date_setUTCDate(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setUTCDate, 1, JS_FALSE, argc, vp);
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setUTCDate, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
/* Step 1. */
double t = thisObj->getDateUTCTime().toNumber();
/* Step 2. */
double dt;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt))
return false;
/* Step 3. */
double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
/* Step 4. */
double v = TimeClip(newDate);
/* Steps 5-6. */
return SetUTCTime(cx, thisObj, v, &args.rval());
}
static bool
GetDateOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *date)
{
if (args.length() <= i) {
*date = DateFromTime(t);
return true;
}
return ToNumber(cx, args[i], date);
}
static bool
GetMonthOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *month)
{
if (args.length() <= i) {
*month = MonthFromTime(t);
return true;
}
return ToNumber(cx, args[i], month);
}
/* ES5 15.9.5.38. */
static JSBool
date_setMonth(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setMonth, 2, JS_TRUE, argc, vp);
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setMonth, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
/* Step 1. */
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
/* Step 2. */
double m;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
return false;
/* Step 3. */
double dt;
if (!GetDateOrDefault(cx, args, 1, t, &dt))
return false;
/* Step 4. */
double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
/* Step 5. */
double u = TimeClip(UTC(newDate, cx));
/* Steps 6-7. */
return SetUTCTime(cx, thisObj, u, &args.rval());
}
/* ES5 15.9.5.39. */
static JSBool
date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setUTCMonth, 2, JS_FALSE, argc, vp);
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setUTCMonth, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
/* Step 1. */
double t = thisObj->getDateUTCTime().toNumber();
/* Step 2. */
double m;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
return false;
/* Step 3. */
double dt;
if (!GetDateOrDefault(cx, args, 1, t, &dt))
return false;
/* Step 4. */
double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
/* Step 5. */
double v = TimeClip(newDate);
/* Steps 6-7. */
return SetUTCTime(cx, thisObj, v, &args.rval());
}
static double
ThisLocalTimeOrZero(Handle<JSObject*> date, JSContext *cx)
{
double t = date->getDateUTCTime().toNumber();
if (MOZ_DOUBLE_IS_NaN(t))
return +0;
return LocalTime(t, cx);
}
static double
ThisUTCTimeOrZero(Handle<JSObject*> date)
{
double t = date->getDateUTCTime().toNumber();
return MOZ_DOUBLE_IS_NaN(t) ? +0 : t;
}
/* ES5 15.9.5.40. */
static JSBool
date_setFullYear(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setFullYear, 3, JS_TRUE, argc, vp);
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setFullYear, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
/* Step 1. */
double t = ThisLocalTimeOrZero(thisObj, cx);
/* Step 2. */
double y;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
return false;
/* Step 3. */
double m;
if (!GetMonthOrDefault(cx, args, 1, t, &m))
return false;
/* Step 4. */
double dt;
if (!GetDateOrDefault(cx, args, 2, t, &dt))
return false;
/* Step 5. */
double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
/* Step 6. */
double u = TimeClip(UTC(newDate, cx));
/* Steps 7-8. */
return SetUTCTime(cx, thisObj, u, &args.rval());
}
/* ES5 15.9.5.41. */
static JSBool
date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
{
return date_makeDate(cx, date_setUTCFullYear, 3, JS_FALSE, argc, vp);
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<JSObject*> thisObj(cx);
if (!NonGenericMethodGuard(cx, args, date_setFullYear, &DateClass, thisObj.address()))
return false;
if (!thisObj)
return true;
/* Step 1. */
double t = ThisUTCTimeOrZero(thisObj);
/* Step 2. */
double y;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
return false;
/* Step 3. */
double m;
if (!GetMonthOrDefault(cx, args, 1, t, &m))
return false;
/* Step 4. */
double dt;
if (!GetDateOrDefault(cx, args, 2, t, &dt))
return false;
/* Step 5. */
double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
/* Step 6. */
double v = TimeClip(newDate);
/* Steps 7-8. */
return SetUTCTime(cx, thisObj, v, &args.rval());
}
/* ES5 Annex B.2.5. */
static JSBool
date_setYear(JSContext *cx, unsigned argc, Value *vp)
{
@@ -2239,31 +2367,33 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
if (!thisObj)
return true;
if (args.length() == 0) {
/* Call this only after verifying that obj.[[Class]] = "Date". */
SetDateToNaN(cx, thisObj, &args.rval());
return true;
}
/* Step 1. */
double t = ThisLocalTimeOrZero(thisObj, cx);
double result = thisObj->getDateUTCTime().toNumber();
double year;
if (!ToNumber(cx, args[0], &year))
/* Step 2. */
double y;
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
return false;
if (!MOZ_DOUBLE_IS_FINITE(year)) {
/* Step 3. */
if (MOZ_DOUBLE_IS_NaN(y)) {
SetDateToNaN(cx, thisObj, &args.rval());
return true;
}
year = ToInteger(year);
if (year >= 0 && year <= 99)
year += 1900;
double t = MOZ_DOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
result = MakeDate(day, TimeWithinDay(t));
result = UTC(result, cx);
/* Step 4. */
double yint = ToInteger(y);
if (0 <= yint && yint <= 99)
yint += 1900;
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
/* Step 5. */
double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t));
/* Step 6. */
double u = UTC(MakeDate(day, TimeWithinDay(t)), cx);
/* Steps 7-8. */
return SetUTCTime(cx, thisObj, TimeClip(u), &args.rval());
}
/* constants for toString, toUTCString */