Commit 1cffc0eb authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

jscript: Improve Number_toString implementation.

parent 15b07c2a
......@@ -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;
}
}
hres = to_string(dispex->ctx, &number->num, ei, &str);
if(FAILED(hres))
return hres;
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment