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
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "jscript.h"
|
#include "jscript.h"
|
||||||
|
|
||||||
#include "wine/debug.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};
|
{'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};
|
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 */
|
/* ECMA-262 3rd Edition 15.7.4.2 */
|
||||||
static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
|
||||||
VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
|
VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
|
||||||
{
|
{
|
||||||
NumberInstance *number;
|
NumberInstance *number;
|
||||||
|
INT radix = 10;
|
||||||
|
DOUBLE val;
|
||||||
BSTR str;
|
BSTR str;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
|
@ -56,14 +61,110 @@ static HRESULT Number_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPA
|
||||||
|
|
||||||
number = (NumberInstance*)dispex;
|
number = (NumberInstance*)dispex;
|
||||||
|
|
||||||
if(arg_cnt(dp) != 0) {
|
if(arg_cnt(dp)) {
|
||||||
FIXME("unsupported args\n");
|
hres = to_int32(dispex->ctx, get_arg(dp, 0), ei, &radix);
|
||||||
return E_NOTIMPL;
|
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);
|
hres = to_string(dispex->ctx, &number->num, ei, &str);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return 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) {
|
if(retv) {
|
||||||
V_VT(retv) = VT_BSTR;
|
V_VT(retv) = VT_BSTR;
|
||||||
|
|
|
@ -566,12 +566,50 @@ ok(tmp === 0, "(new Number()).valueOf = " + tmp);
|
||||||
tmp = Number.prototype.valueOf();
|
tmp = Number.prototype.valueOf();
|
||||||
ok(tmp === 0, "Number.prototype.valueOf = " + tmp);
|
ok(tmp === 0, "Number.prototype.valueOf = " + tmp);
|
||||||
|
|
||||||
num = new Number(NaN);
|
function equals(val, base) {
|
||||||
ok(num.toString() === "NaN", "num.toString() = " + num.toString());
|
var i;
|
||||||
num = new Number(-Infinity);
|
var num = 0;
|
||||||
ok(num.toString() === "-Infinity", "num.toString() = " + num.toString());
|
var str = val.toString(base);
|
||||||
num = new Number(Infinity);
|
|
||||||
ok(num.toString() === "Infinity", "num.toString() = " + num.toString());
|
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);
|
tmp = Math.min(1);
|
||||||
ok(tmp === 1, "Math.min(1) = " + tmp);
|
ok(tmp === 1, "Math.min(1) = " + tmp);
|
||||||
|
|
Loading…
Reference in New Issue