jscript: Improve Number_toString implementation.
This commit is contained in:
parent
15b07c2a36
commit
1cffc0eb73
|
@ -16,6 +16,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "jscript.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
@ -39,11 +41,14 @@ static const WCHAR propertyIsEnumerableW[] =
|
|||
{'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
|
||||
static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
|
||||
|
||||
#define NUMBER_TOSTRING_BUF_SIZE 64
|
||||
/* ECMA-262 3rd Edition 15.7.4.2 */
|
||||
static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
||||
VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
|
||||
{
|
||||
NumberInstance *number;
|
||||
INT radix = 10;
|
||||
DOUBLE val;
|
||||
BSTR str;
|
||||
HRESULT hres;
|
||||
|
||||
|
@ -56,14 +61,110 @@ static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPA
|
|||
|
||||
number = (NumberInstance*)dispex;
|
||||
|
||||
if(arg_cnt(dp) != 0) {
|
||||
FIXME("unsupported args\n");
|
||||
return E_NOTIMPL;
|
||||
if(arg_cnt(dp)) {
|
||||
hres = to_int32(dispex->ctx, get_arg(dp, 0), ei, &radix);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(radix<2 || radix>36) {
|
||||
FIXME("throw TypeError\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if(V_VT(&number->num) == VT_I4)
|
||||
val = V_I4(&number->num);
|
||||
else
|
||||
val = V_R8(&number->num);
|
||||
|
||||
if(radix==10 || isnan(val) || isinf(val)) {
|
||||
hres = to_string(dispex->ctx, &number->num, ei, &str);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
else {
|
||||
INT idx = 0;
|
||||
DOUBLE integ, frac, log_radix = 0;
|
||||
WCHAR buf[NUMBER_TOSTRING_BUF_SIZE+16];
|
||||
BOOL exp = FALSE;
|
||||
|
||||
if(val<0) {
|
||||
val = -val;
|
||||
buf[idx++] = '-';
|
||||
}
|
||||
|
||||
while(1) {
|
||||
integ = floor(val);
|
||||
frac = val-integ;
|
||||
|
||||
if(integ == 0)
|
||||
buf[idx++] = '0';
|
||||
while(integ>=1 && idx<NUMBER_TOSTRING_BUF_SIZE) {
|
||||
buf[idx] = fmod(integ, radix);
|
||||
if(buf[idx]<10) buf[idx] += '0';
|
||||
else buf[idx] += 'a'-10;
|
||||
integ /= radix;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if(idx<NUMBER_TOSTRING_BUF_SIZE) {
|
||||
INT beg = buf[0]=='-'?1:0;
|
||||
INT end = idx-1;
|
||||
WCHAR wch;
|
||||
|
||||
while(end > beg) {
|
||||
wch = buf[beg];
|
||||
buf[beg++] = buf[end];
|
||||
buf[end--] = wch;
|
||||
}
|
||||
}
|
||||
|
||||
if(idx != NUMBER_TOSTRING_BUF_SIZE) buf[idx++] = '.';
|
||||
|
||||
while(frac>0 && idx<NUMBER_TOSTRING_BUF_SIZE) {
|
||||
frac *= radix;
|
||||
buf[idx] = fmod(frac, radix);
|
||||
frac -= buf[idx];
|
||||
if(buf[idx]<10) buf[idx] += '0';
|
||||
else buf[idx] += 'a'-10;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if(idx==NUMBER_TOSTRING_BUF_SIZE && !exp) {
|
||||
exp = TRUE;
|
||||
idx = (buf[0]=='-') ? 1 : 0;
|
||||
log_radix = floor(log(val)/log(radix));
|
||||
val *= pow(radix, -log_radix);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
while(buf[idx-1] == '0') idx--;
|
||||
if(buf[idx-1] == '.') idx--;
|
||||
|
||||
if(exp) {
|
||||
if(log_radix==0)
|
||||
buf[idx++] = '\0';
|
||||
else {
|
||||
static const WCHAR formatW[] = {'(','e','%','c','%','d',')',0};
|
||||
WCHAR ch;
|
||||
|
||||
if(log_radix<0) {
|
||||
log_radix = -log_radix;
|
||||
ch = '-';
|
||||
}
|
||||
else ch = '+';
|
||||
sprintfW(&buf[idx], formatW, ch, (int)log_radix);
|
||||
}
|
||||
}
|
||||
else buf[idx] = '\0';
|
||||
|
||||
str = SysAllocString(buf);
|
||||
if(!str)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if(retv) {
|
||||
V_VT(retv) = VT_BSTR;
|
||||
|
|
|
@ -566,12 +566,50 @@ ok(tmp === 0, "(new Number()).valueOf = " + tmp);
|
|||
tmp = Number.prototype.valueOf();
|
||||
ok(tmp === 0, "Number.prototype.valueOf = " + tmp);
|
||||
|
||||
num = new Number(NaN);
|
||||
ok(num.toString() === "NaN", "num.toString() = " + num.toString());
|
||||
num = new Number(-Infinity);
|
||||
ok(num.toString() === "-Infinity", "num.toString() = " + num.toString());
|
||||
num = new Number(Infinity);
|
||||
ok(num.toString() === "Infinity", "num.toString() = " + num.toString());
|
||||
function equals(val, base) {
|
||||
var i;
|
||||
var num = 0;
|
||||
var str = val.toString(base);
|
||||
|
||||
for(i=0; i<str.length; i++) {
|
||||
if(str.substring(i, i+1) == '(') break;
|
||||
if(str.substring(i, i+1) == '.') break;
|
||||
num = num*base + parseInt(str.substring(i, i+1));
|
||||
}
|
||||
|
||||
if(str.substring(i, i+1) == '.') {
|
||||
var mult = base;
|
||||
for(i++; i<str.length; i++) {
|
||||
if(str.substring(i, i+1) == '(') break;
|
||||
num += parseInt(str.substring(i, i+1))/mult;
|
||||
mult *= base;
|
||||
}
|
||||
}
|
||||
|
||||
if(str.substring(i, i+1) == '(') {
|
||||
exp = parseInt(str.substring(i+2));
|
||||
num *= Math.pow(base, exp);
|
||||
}
|
||||
|
||||
ok(num>val-val/1000 && num<val+val/1000, "equals: num = " + num);
|
||||
}
|
||||
|
||||
ok((10).toString(11) === "a", "(10).toString(11) = " + (10).toString(11));
|
||||
ok((213213433).toString(17) === "8e2ddcb", "(213213433).toString(17) = " + (213213433).toString(17));
|
||||
ok((-3254343).toString(33) === "-2oicf", "(-3254343).toString(33) = " + (-3254343).toString(33));
|
||||
ok((NaN).toString(12) === "NaN", "(NaN).toString(11) = " + (NaN).toString(11));
|
||||
ok((Infinity).toString(13) === "Infinity", "(Infinity).toString(11) = " + (Infinity).toString(11));
|
||||
for(i=2; i<10; i++) {
|
||||
equals(1.123, i);
|
||||
equals(2305843009200000000, i);
|
||||
equals(5.123, i);
|
||||
equals(1/(1024*1024*1024*1024*1024*1024*1.9), i);
|
||||
equals(1024*1024*1024*1024*1024*1024*1.9999, i);
|
||||
equals(0.0000000000000000001, i);
|
||||
equals(0.6, i);
|
||||
equals(4.65661287308e-10, i);
|
||||
ok((0).toString(i) === "0", "(0).toString("+i+") = " + (0).toString(i));
|
||||
}
|
||||
|
||||
tmp = Math.min(1);
|
||||
ok(tmp === 1, "Math.min(1) = " + tmp);
|
||||
|
|
Loading…
Reference in New Issue