diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/ecmascript/date.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/ecmascript/date.b')
| -rw-r--r-- | appl/lib/ecmascript/date.b | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/appl/lib/ecmascript/date.b b/appl/lib/ecmascript/date.b new file mode 100644 index 00000000..e84d00b6 --- /dev/null +++ b/appl/lib/ecmascript/date.b @@ -0,0 +1,495 @@ +# the Date object is founded on the Daytime module + +UTC: con 1; +msPerSec: con big 1000; + +# based on Daytime->Tm with big fields +bigTm: adt { + ms: big; + sec: big; + min: big; + hour: big; + mday: big; + mon: big; + year: big; + tzoff: int; +}; + +isfinite(r: real): int +{ + if(math->isnan(r) || r == +Infinity || r == -Infinity) + return 0; + return 1; +} + +time2Tm(t: real, utc: int): ref Daytime->Tm +{ + secs := int(big t / msPerSec); + if(big t % msPerSec < big 0) # t<0? + secs -= 1; + if(utc) + tm := daytime->gmt(secs); + else + tm = daytime->local(secs); + return tm; +} + +time2bigTm(t: real, utc: int): ref bigTm +{ + tm := time2Tm(t, utc); + btm := ref bigTm; + btm.ms = big t % msPerSec; + if(btm.ms < big 0) + btm.ms += msPerSec; + btm.sec = big tm.sec; + btm.min = big tm.min; + btm.hour = big tm.hour; + btm.mday = big tm.mday; + btm.mon = big tm.mon; + btm.year = big tm.year; + btm.tzoff = tm.tzoff; + return btm; +} + +bigTm2time(btm: ref bigTm): real +{ + # normalize + if(btm.mon / big 12 != big 0){ + btm.year += btm.mon / big 12; + btm.mon %= big 12; + } + if(btm.ms / msPerSec != big 0){ + btm.sec += btm.ms / msPerSec; + btm.ms %= msPerSec; + } + if(btm.sec / big 60 != big 0){ + btm.min += btm.sec / big 60; + btm.sec %= big 60; + } + if(btm.min / big 60 != big 0){ + btm.hour += btm.hour / big 60; + btm.min %= big 60; + } + if(btm.hour / big 24 != big 0){ + btm.mday += btm.mday / big 24; + btm.hour %= big 24; + } + + tm := ref Tm; + tm.sec = int btm.sec; + tm.min = int btm.min; + tm.hour = int btm.hour; + tm.mday = int btm.mday; + tm.mon = int btm.mon; + tm.year = int btm.year; + tm.tzoff = btm.tzoff; + secs := daytime->tm2epoch(tm); + # check for out-of-band times + if(secs == daytime->tm2epoch(daytime->gmt(secs))) + r := real(big secs * msPerSec + btm.ms); + else + r = Math->NaN; + return r; +} + +str2time(s: string): real +{ + tm := daytime->string2tm(s); + if(tm == nil) + r := Math->NaN; + else + r = real (big daytime->tm2epoch(tm) * msPerSec); + return r; +} + +cdate(nil: ref Exec, nil, nil: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + return strval(daytime->time()); +} + +# process arguments of Date() [called as constructor] and Date.UTC() +datectorargs(ex: ref Exec, args: array of ref Val): (int, ref bigTm) +{ + x := array[7] of { * => big 0 }; + ok := 1; + for(i := 0; i < 7 && i < len args; i++){ + if(!isfinite(toNumber(ex, biarg(args, i)))) + ok = 0; + else + x[i] = big toInteger(ex, biarg(args, i)); + } + btm := ref bigTm; + yr := x[0]; + if(yr >= big 0 && yr <= big 99) + btm.year = yr; + else + btm.year = yr - big 1900; + btm.mon = x[1]; + btm.mday = x[2]; + btm.hour = x[3]; + btm.min = x[4]; + btm.sec = x[5]; + btm.ms = x[6]; + return (ok, btm); +} + +ndate(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj +{ + o := mkobj(ex.dateproto, "Date"); + r := Math->NaN; + case len args{ + 0 => + r = real(big daytime->now() * msPerSec); + 1 => + v := toPrimitive(ex, biarg(args, 0), NoHint); + if(isstr(v)) + r = str2time(v.str); + else if(isfinite(toNumber(ex, v))){ + t := big toInteger(ex, v); + secs := t / msPerSec; + if(big t % msPerSec < big 0) + secs -= big 1; + if(secs == big int secs) + r = real t; + } + * => + (ok, btm) := datectorargs(ex, args); + if(ok){ + tm := daytime->local(daytime->now()); + btm.tzoff = tm.tzoff; + r = bigTm2time(btm); + } + } + o.val = numval(r); + return o; +} + +cdateparse(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val +{ + s := toString(ex, biarg(args, 0)); + return numval(str2time(s)); +} + +cdateUTC(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val +{ + r := Math->NaN; + if(len args == 0) + r = real(big daytime->now() * msPerSec); + else{ + (ok, btm) := datectorargs(ex, args); + if(ok){ + btm.tzoff = 0; + r = bigTm2time(btm); + } + } + return numval(r); +} + +datecheck(ex: ref Exec, o: ref Ecmascript->Obj, f: string) +{ + if(!isdateobj(o)) + runtime(ex, TypeError, "Date.prototype." + f + " called on non-Date object"); +} + +cdateprototoString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + secs := 0; + t := this.val.num; + if(!math->isnan(t)){ + secs = int(big t / msPerSec); + if(big t % msPerSec < big 0) + secs -= 1; + } + return strval(daytime->text(daytime->local(secs))); +} + +cdateprototoDateString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + secs := 0; + t := this.val.num; + if(!math->isnan(t)){ + secs = int(big t / msPerSec); + if(big t % msPerSec < big 0) + secs -= 1; + } + s := daytime->text(daytime->local(secs)); + (n, ls) := sys->tokenize(s, " "); + if(n < 3) + return strval(""); + return strval(hd ls + " " + hd tl ls + " " + hd tl tl ls); +} + +cdateprototoTimeString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + secs := 0; + t := this.val.num; + if(!math->isnan(t)){ + secs = int(big t / msPerSec); + if(big t % msPerSec < big 0) + secs -= 1; + } + s := daytime->text(daytime->local(secs)); + (n, ls) := sys->tokenize(s, " "); + if(n < 4) + return strval(""); + return strval(hd tl tl tl ls); +} + +cdateprotovalueOf(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + return this.val; +} + +cdateprotoget(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + t := this.val.num; + if(!math->isnan(t)){ + tm := time2Tm(t, utc); + case f.val.str{ + "Date.prototype.getYear" => + if (tm.year < 0 || tm.year > 99) + t = real(tm.year + 1900); + else + t = real tm.year; + "Date.prototype.getFullYear" or + "Date.prototype.getUTCFullYear" => + t = real(tm.year + 1900); + "Date.prototype.getMonth" or + "Date.prototype.getUTCMonth" => + t = real tm.mon; + "Date.prototype.getDate" or + "Date.prototype.getUTCDate" => + t = real tm.mday; + "Date.prototype.getDay" or + "Date.prototype.getUTCDay" => + t = real tm.wday; + "Date.prototype.getHours" or + "Date.prototype.getUTCHours" => + t = real tm.hour; + "Date.prototype.getMinutes" or + "Date.prototype.getUTCMinutes" => + t = real tm.min; + "Date.prototype.getSeconds" or + "Date.prototype.getUTCSeconds" => + t = real tm.sec; + } + } + return numval(t); +} + +cdateprotogetMilliseconds(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + t := this.val.num; + if(!math->isnan(t)){ + ms := big t % msPerSec; + if(ms < big 0) + ms += msPerSec; + t = real ms; + } + return numval(t); +} + +cdateprotogetTimezoneOffset(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + t := this.val.num; + if(!math->isnan(t)){ + tm := time2Tm(t, !UTC); + t = real(tm.tzoff / 60); + } + return numval(t); +} + +# process arguments of Date.prototype.set*() functions +dateprotosetargs(ex: ref Exec, this: ref Ecmascript->Obj, args: array of ref Val, n: int): (int, big, big, big, big) +{ + x := array[4] of { * => big 0 }; + ok := 1; + if(this != nil && !isfinite(this.val.num)) + ok = 0; + for(i := 0; i < n && i < len args; i++){ + if(!isfinite(toNumber(ex, biarg(args, i)))) + ok = 0; + else + x[i] = big toInteger(ex, biarg(args, i)); + } + return (ok, x[0], x[1], x[2], x[3]); +} + +cdateprotosetTime(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, t, nil, nil, nil) := dateprotosetargs(ex, nil, args, 1); + if(ok){ + secs := t / msPerSec; + if(big t % msPerSec < big 0) + secs -= big 1; + if(secs == big int secs) + r = real t; + } + this.val.num = r; + return numval(r); +} + +cdateprotosetMilliseconds(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, ms, nil, nil, nil) := dateprotosetargs(ex, this, args, 1); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.ms = ms; + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetSeconds(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, sec, ms, nil, nil) := dateprotosetargs(ex, this, args, 2); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.sec = sec; + if(len args > 1) + btm.ms = ms; + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetMinutes(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, min, sec, ms, nil) := dateprotosetargs(ex, this, args, 3); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.min = min; + if(len args > 1){ + btm.sec = sec; + if(len args > 2) + btm.ms = ms; + } + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetHours(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, hour, min, sec, ms) := dateprotosetargs(ex, this, args, 4); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.hour = hour; + if(len args > 1){ + btm.min = min; + if(len args > 2){ + btm.sec = sec; + if(len args > 3) + btm.ms = ms; + } + } + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetDate(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, day, nil, nil, nil) := dateprotosetargs(ex, this, args, 1); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.mday = day; + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetMonth(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, mon, day, nil, nil) := dateprotosetargs(ex, this, args, 2); + if(ok){ + btm := time2bigTm(this.val.num, utc); + btm.mon = mon; + if(len args > 1) + btm.mday = day; + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetFullYear(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val, utc: int): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, year, mon, day, nil) := dateprotosetargs(ex, nil, args, 3); + if(ok){ + t := this.val.num; + if(!isfinite(t)) + t = 0.; + btm := time2bigTm(t, utc); + btm.year = (year - big 1900); + if(len args > 1){ + btm.mon = mon; + if(len args > 2) + btm.mday = day; + } + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprotosetYear(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + r := Math->NaN; + (ok, year, nil, nil, nil) := dateprotosetargs(ex, nil, args, 1); + if(ok){ + t := this.val.num; + if(!isfinite(t)) + t = 0.; + btm := time2bigTm(t, !UTC); + if(year >= big 0 && year <= big 99) + btm.year = year; + else + btm.year = year - big 1900; + r = bigTm2time(btm); + } + this.val.num = r; + return numval(r); +} + +cdateprototoUTCString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val +{ + datecheck(ex, this, f.val.str); + secs := 0; + t := this.val.num; + if(!math->isnan(t)){ + secs = int(big t / msPerSec); + if(big t % msPerSec < big 0) + secs -= 1; + } + return strval(daytime->text(daytime->gmt(secs))); +} |
