Coverage Report

Created: 2025-10-10 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsNumber.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
static txSlot* fxCheckNumber(txMachine* the, txSlot* it);
41
42
void fxBuildNumber(txMachine* the)
43
21.8k
{
44
21.8k
  txSlot* slot;
45
  
46
21.8k
  mxPushNumber((txNumber)C_INFINITY);
47
21.8k
  mxPull(mxInfinity);
48
21.8k
  mxPushNumber((txNumber)C_NAN);
49
21.8k
  mxPull(mxNaN);
50
51
21.8k
  mxPush(mxObjectPrototype);
52
21.8k
  slot = fxLastProperty(the, fxNewNumberInstance(the));
53
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toExponential), 1, mxID(_toExponential), XS_DONT_ENUM_FLAG);
54
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toFixed), 1, mxID(_toFixed), XS_DONT_ENUM_FLAG);
55
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toLocaleString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
56
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toPrecision), 1, mxID(_toPrecision), XS_DONT_ENUM_FLAG);
57
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toString), 1, mxID(_toString), XS_DONT_ENUM_FLAG);
58
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
59
21.8k
  mxNumberPrototype = *the->stack;
60
21.8k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Number), 1, mxID(_Number));
61
21.8k
  mxNumberConstructor = *the->stack;
62
21.8k
  slot = fxLastProperty(the, slot);
63
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isFinite), 1, mxID(_isFinite), XS_DONT_ENUM_FLAG);
64
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isInteger), 1, mxID(_isInteger), XS_DONT_ENUM_FLAG);
65
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isNaN), 1, mxID(_isNaN), XS_DONT_ENUM_FLAG);
66
21.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isSafeInteger), 1, mxID(_isSafeInteger), XS_DONT_ENUM_FLAG);
67
21.8k
  slot = fxNextSlotProperty(the, slot, &mxParseFloatFunction, mxID(_parseFloat), XS_DONT_ENUM_FLAG);
68
21.8k
  slot = fxNextSlotProperty(the, slot, &mxParseIntFunction, mxID(_parseInt), XS_DONT_ENUM_FLAG);
69
21.8k
  slot = fxNextNumberProperty(the, slot, C_EPSILON, mxID(_EPSILON), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
70
21.8k
  slot = fxNextNumberProperty(the, slot, C_MAX_SAFE_INTEGER, mxID(_MAX_SAFE_INTEGER), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
71
21.8k
  slot = fxNextNumberProperty(the, slot, C_DBL_MAX, mxID(_MAX_VALUE), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
72
21.8k
  slot = fxNextNumberProperty(the, slot, C_MIN_SAFE_INTEGER, mxID(_MIN_SAFE_INTEGER), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
73
21.8k
  slot = fxNextNumberProperty(the, slot, C_DBL_MIN, mxID(_MIN_VALUE), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
74
21.8k
  slot = fxNextNumberProperty(the, slot, C_NAN, mxID(_NaN), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
75
21.8k
  slot = fxNextNumberProperty(the, slot, -((txNumber)C_INFINITY), mxID(_NEGATIVE_INFINITY), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
76
21.8k
  slot = fxNextNumberProperty(the, slot, (txNumber)C_INFINITY, mxID(_POSITIVE_INFINITY), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
77
21.8k
  mxPop();
78
21.8k
}
79
80
txSlot* fxNewNumberInstance(txMachine* the)
81
12.7M
{
82
12.7M
  txSlot* instance;
83
12.7M
  instance = fxNewObjectInstance(the);
84
12.7M
  fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
85
12.7M
  return instance;
86
12.7M
}
87
88
void fxNumberCoerce(txMachine* the, txSlot* slot)
89
1.47k
{
90
1.47k
  fxToNumber(the, slot);
91
1.47k
}
92
93
void fx_isFinite(txMachine* the)
94
217
{
95
217
  int fpclass;
96
217
  txNumber number = (mxArgc < 1) ?  C_NAN : fxToNumber(the, mxArgv(0)); 
97
217
  mxResult->kind = XS_BOOLEAN_KIND;
98
217
    mxResult->value.boolean = 0;
99
217
  fpclass = c_fpclassify(number);
100
217
  if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE))
101
188
    mxResult->value.boolean = 1;
102
217
}
103
104
void fx_isNaN(txMachine* the)
105
5.84k
{
106
5.84k
  int fpclass;
107
5.84k
  txNumber number = (mxArgc < 1) ?  C_NAN : fxToNumber(the, mxArgv(0)); 
108
5.84k
  mxResult->kind = XS_BOOLEAN_KIND;
109
5.84k
    mxResult->value.boolean = 0;
110
5.84k
  fpclass = c_fpclassify(number);
111
5.84k
  if (fpclass == C_FP_NAN)
112
4.49k
    mxResult->value.boolean = 1;
113
5.84k
}
114
115
void fx_parseFloat(txMachine* the)
116
41.3k
{
117
41.3k
  if (mxArgc < 1) {
118
132
    mxResult->value.number = C_NAN;
119
132
    mxResult->kind = XS_NUMBER_KIND;
120
132
        return;
121
132
  }
122
41.2k
  fxToString(the, mxArgv(0));
123
41.2k
  mxResult->kind = XS_NUMBER_KIND;
124
41.2k
  mxResult->value.number = fxStringToNumber(the, mxArgv(0)->value.string, 0);
125
41.2k
}
126
127
void fx_parseInt(txMachine* the)
128
489k
{
129
489k
  txInteger aRadix, aDigit;
130
489k
  txNumber aSign, aResult;
131
489k
  txString s, r;
132
489k
  char c;
133
  
134
489k
  if (mxArgc < 1) {
135
34
    mxResult->value.number = C_NAN;
136
34
    mxResult->kind = XS_NUMBER_KIND;
137
34
        return;
138
34
  }
139
489k
  fxToString(the, mxArgv(0));
140
489k
  if (mxArgc > 1) {
141
486k
    aRadix = fxToInteger(the, mxArgv(1));
142
486k
    if (aRadix) {
143
365k
      if ((aRadix < 2) || (36 < aRadix)) {
144
49.6k
        mxResult->kind = XS_NUMBER_KIND;
145
49.6k
        mxResult->value.number = C_NAN;
146
49.6k
        return;
147
49.6k
      }
148
365k
    }
149
486k
  }
150
3.16k
  else
151
3.16k
    aRadix = 0;
152
439k
  s = fxSkipSpaces(mxArgv(0)->value.string);
153
439k
  c = *s;
154
439k
  aSign = 1;
155
439k
  if (c == '+')
156
679
    s++;
157
439k
  else if (c == '-') {
158
1.31k
    s++;
159
1.31k
    aSign = -1;
160
1.31k
  }
161
439k
  if ((*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) {
162
402
    if ((aRadix == 0) || (aRadix == 16)) {
163
399
      aRadix = 16;
164
399
      s += 2;
165
399
    }
166
402
  }
167
  /*if (*s == '0') {
168
    if ((aRadix == 0) || (aRadix == 8)) {
169
      aRadix = 8;
170
    }
171
  }*/
172
439k
  if (aRadix == 0)
173
123k
    aRadix = 10;
174
439k
  aResult = 0;
175
439k
  r = s;
176
518k
  while ((c = *s)) {
177
181k
    if (('0' <= c) && (c <= '9'))
178
47.6k
      aDigit = c - '0';
179
133k
    else if (('a' <= c) && (c <= 'z'))
180
2.70k
      aDigit = 10 + c - 'a';
181
131k
    else if (('A' <= c) && (c <= 'Z'))
182
29.8k
      aDigit = 10 + c - 'A';
183
101k
    else
184
101k
      break;
185
80.1k
    if (aDigit >= aRadix)
186
1.83k
      break;
187
78.3k
    aResult = (aResult * aRadix) + aDigit;
188
78.3k
    s++;
189
78.3k
  }
190
439k
  if (r == s) {
191
408k
    mxResult->kind = XS_NUMBER_KIND;
192
408k
    mxResult->value.number = C_NAN;
193
408k
  }
194
30.8k
  else {
195
30.8k
    aResult *= aSign;
196
30.8k
    aRadix = (txInteger)aResult;
197
30.8k
    aSign = aRadix;
198
30.8k
    if (aSign == aResult) {
199
30.2k
      mxResult->value.integer = aRadix;
200
30.2k
      mxResult->kind = XS_INTEGER_KIND;
201
30.2k
    }
202
638
    else {
203
638
      mxResult->value.number = aResult;
204
638
      mxResult->kind = XS_NUMBER_KIND;
205
638
    }
206
30.8k
  }
207
439k
}
208
209
void fx_Number(txMachine* the)
210
376k
{
211
376k
  txNumber value = 0;
212
376k
  if (mxArgc > 0) {
213
263k
    txSlot* slot = mxArgv(0);
214
263k
    if (slot->kind == XS_REFERENCE_KIND)
215
518
      fxToPrimitive(the, slot, XS_NUMBER_HINT);
216
263k
    if ((slot->kind == XS_BIGINT_KIND) || (slot->kind == XS_BIGINT_X_KIND))
217
415
      value = fxBigIntToNumber(the, slot);
218
262k
    else
219
262k
      value = fxToNumber(the, slot);
220
263k
  }
221
376k
  if (mxIsUndefined(mxTarget)) {
222
376k
        mxResult->kind = XS_NUMBER_KIND;
223
376k
        mxResult->value.number = value;
224
376k
        fx_Math_toInteger(the);
225
376k
  }
226
351
  else {
227
351
    txSlot* instance;
228
351
    mxPushSlot(mxTarget);
229
351
    fxGetPrototypeFromConstructor(the, &mxNumberPrototype);
230
351
    instance = fxNewNumberInstance(the);
231
351
    instance->next->value.number = value;
232
351
    mxPullSlot(mxResult);
233
351
  }
234
376k
}
235
236
void fx_Number_isFinite(txMachine* the)
237
54
{
238
54
  int fpclass;
239
54
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
240
54
  mxResult->kind = XS_BOOLEAN_KIND;
241
54
    mxResult->value.boolean = 0;
242
54
    if (slot) {
243
53
      if (slot->kind == XS_INTEGER_KIND)
244
12
      mxResult->value.boolean = 1;
245
41
      else if (slot->kind == XS_NUMBER_KIND) {
246
23
      fpclass = c_fpclassify(slot->value.number);
247
23
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE))
248
13
        mxResult->value.boolean = 1;
249
23
    }
250
53
  }
251
54
}
252
253
void fx_Number_isInteger(txMachine* the)
254
89
{
255
89
  int fpclass;
256
89
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
257
89
  mxResult->kind = XS_BOOLEAN_KIND;
258
89
    mxResult->value.boolean = 0;
259
89
    if (slot) {
260
88
      if (slot->kind == XS_INTEGER_KIND)
261
49
      mxResult->value.boolean = 1;
262
39
      else if (slot->kind == XS_NUMBER_KIND) {
263
20
      fpclass = c_fpclassify(slot->value.number);
264
20
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) {
265
16
        txNumber check = c_trunc(slot->value.number);
266
16
        if (slot->value.number == check)
267
9
          mxResult->value.boolean = 1;
268
16
      }
269
20
    }
270
88
  }
271
89
}
272
273
void fx_Number_isNaN(txMachine* the)
274
110
{
275
110
  int fpclass;
276
110
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
277
110
  mxResult->kind = XS_BOOLEAN_KIND;
278
110
    mxResult->value.boolean = 0;
279
110
    if (slot) {
280
109
      if (slot->kind == XS_NUMBER_KIND) {
281
26
      fpclass = c_fpclassify(slot->value.number);
282
26
      if (fpclass == C_FP_NAN)
283
7
        mxResult->value.boolean = 1;
284
26
    }
285
109
  }
286
110
}
287
288
void fx_Number_isSafeInteger(txMachine* the)
289
2.32k
{
290
2.32k
  int fpclass;
291
2.32k
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
292
2.32k
  mxResult->kind = XS_BOOLEAN_KIND;
293
2.32k
    mxResult->value.boolean = 0;
294
2.32k
    if (slot) {
295
2.31k
      if (slot->kind == XS_INTEGER_KIND)
296
7
      mxResult->value.boolean = 1;
297
2.31k
      else if (slot->kind == XS_NUMBER_KIND) {
298
21
      fpclass = c_fpclassify(slot->value.number);
299
21
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) {
300
17
        txNumber check = c_trunc(slot->value.number);
301
17
        if (slot->value.number == check) {
302
10
          if ((C_MIN_SAFE_INTEGER <= check) && (check <= C_MAX_SAFE_INTEGER))
303
4
            mxResult->value.boolean = 1;
304
10
        }
305
17
      }
306
21
    }
307
2.31k
  }
308
2.32k
}
309
310
void fx_Number_prototype_toExponential(txMachine* the)
311
357
{
312
357
  char buffer[256];
313
357
  txInteger mode = 0;
314
357
  txNumber precision = 0;
315
357
  txNumber value;
316
357
  txSlot* slot = fxCheckNumber(the, mxThis);
317
357
  if (!slot) mxTypeError("this: not a number");
318
333
  value = slot->value.number;
319
333
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
320
315
    precision = fxToNumber(the, mxArgv(0));
321
315
    if (c_isnan(precision))
322
2
      precision = 0;
323
313
    else if (c_isfinite(precision))
324
308
      precision = c_trunc(precision);
325
315
  }
326
18
  else
327
18
    precision = 0;
328
333
  if (c_isnan(value))
329
5
    precision = 0;
330
328
  else if (c_isfinite(value)) {
331
245
    if ((precision < 0) || (100 < precision))
332
4
      mxRangeError("invalid fractionDigits");
333
241
    if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0)))
334
223
      precision++;
335
241
    mode = 'e';
336
241
  }
337
83
  else
338
83
    precision = 0;
339
329
  fxNumberToString(the, slot->value.number, buffer, sizeof(buffer), mode, (int)precision);
340
329
  fxCopyStringC(the, mxResult, buffer);
341
329
}
342
343
void fx_Number_prototype_toFixed(txMachine* the)
344
154k
{
345
154k
  char buffer[256];
346
154k
  txInteger mode = 0;
347
154k
  txNumber precision = 0;
348
154k
  txNumber value;
349
154k
  txSlot* slot = fxCheckNumber(the, mxThis);
350
154k
  if (!slot) mxTypeError("this: not a number");
351
154k
  value = slot->value.number;
352
154k
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
353
121k
    precision = fxToNumber(the, mxArgv(0));
354
121k
    if (c_isnan(precision))
355
2.09k
      precision = 0;
356
119k
    else if (c_isfinite(precision))
357
119k
      precision = c_trunc(precision);
358
121k
  }
359
33.1k
  else
360
33.1k
    precision = 0;
361
154k
  if ((precision < 0) || (100 < precision))
362
9
    mxRangeError("invalid fractionDigits");
363
154k
  if (c_fabs(value) >= 1e21)
364
875
    precision = 0;
365
153k
  else
366
153k
    mode = 'f';
367
154k
  fxNumberToString(the, value, buffer, sizeof(buffer), mode, (int)precision);
368
154k
  fxCopyStringC(the, mxResult, buffer);
369
154k
}
370
371
void fx_Number_prototype_toLocaleString(txMachine* the)
372
6
{
373
6
  txSlot* slot = fxCheckNumber(the, mxThis);
374
6
  if (!slot) mxTypeError("this: not a number");
375
6
  mxResult->kind = slot->kind;
376
6
  mxResult->value = slot->value;
377
6
  fxToString(the, mxResult);
378
6
}
379
380
void fx_Number_prototype_toPrecision(txMachine* the)
381
1.30M
{
382
1.30M
  char buffer[256];
383
1.30M
  txInteger mode = 0;
384
1.30M
  txNumber precision = 0;
385
1.30M
  txNumber value;
386
1.30M
  txSlot* slot = fxCheckNumber(the, mxThis);
387
1.30M
  if (!slot) mxTypeError("this: not a number");
388
1.30M
  value = slot->value.number;
389
1.30M
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
390
1.30M
    precision = fxToNumber(the, mxArgv(0));
391
1.30M
    if (c_isnan(precision))
392
6
      precision = 0;
393
1.30M
    else if (c_isfinite(precision))
394
1.30M
      precision = c_trunc(precision);
395
1.30M
    if (c_isnan(value))
396
135k
      precision = 0;
397
1.16M
    else if (c_isfinite(value)) {
398
1.16M
      if ((precision < 1) || (100 < precision))
399
11
        mxRangeError("invalid precision");
400
1.16M
      mode = 'g';
401
1.16M
    }
402
99
    else
403
99
      precision = 0;
404
1.30M
  }
405
1.30M
  fxNumberToString(the, value, buffer, sizeof(buffer), mode, (int)precision);
406
1.30M
  fxCopyStringC(the, mxResult, buffer);
407
1.30M
}
408
409
void fx_Number_prototype_toString(txMachine* the)
410
673k
{
411
673k
  txInteger radix;
412
673k
  txSlot* slot = fxCheckNumber(the, mxThis);
413
673k
  if (!slot) mxTypeError("this: not a number");
414
673k
  if ((mxArgc > 0) && (!mxIsUndefined(mxArgv(0)))) {
415
673k
    radix = fxToInteger(the, mxArgv(0));
416
673k
    if ((radix < 2) || (36 < radix))
417
760
      mxRangeError("invalid radix");
418
673k
  }
419
624
  else  
420
624
    radix = 10;
421
673k
  mxResult->kind = slot->kind;
422
673k
  mxResult->value = slot->value;
423
673k
  if (radix == 10)
424
624
    fxToString(the, mxResult);
425
672k
  else {
426
672k
    txNumber value = mxResult->value.number;
427
672k
    switch (c_fpclassify(value)) {
428
391k
    case C_FP_INFINITE:
429
391k
      if (value < 0)
430
391k
        fxStringX(the, mxResult, "-Infinity");
431
222
      else
432
222
        fxStringX(the, mxResult, "Infinity");
433
391k
      break;
434
45
    case C_FP_NAN:
435
45
      fxStringX(the, mxResult, "NaN");
436
45
      break;
437
126k
    case C_FP_ZERO:
438
126k
      fxStringX(the, mxResult, "0");
439
126k
      break;
440
154k
    default: {
441
      // Thanks Google V8 for the fraction part
442
154k
      static const char gxDigits[] ICACHE_FLASH_ATTR = "0123456789abcdefghijklmnopqrstuvwxyz";
443
154k
      txInteger minus;
444
154k
      txNumber integer;
445
154k
      txNumber fraction;
446
154k
      txNumber next;
447
154k
      txU8* nextCast = (txU8*)&next;
448
154k
      txNumber delta;
449
154k
      txSize length;
450
154k
      txString string;
451
154k
      txNumber modulo;
452
154k
      if (value < 0) {
453
2.11k
        minus = 1;
454
2.11k
        value = -value;
455
2.11k
      } 
456
151k
      else
457
151k
        minus = 0;
458
154k
      integer = c_floor(value);
459
154k
      fraction = value - integer;
460
154k
      next = value;
461
154k
      *nextCast = *nextCast + 1;
462
154k
      delta = 0.5 * (next - value);
463
154k
      next = 0;
464
154k
      *nextCast = *nextCast + 1;
465
154k
      if (delta < next)
466
1
        delta = next;
467
154k
      length = minus + ((integer)? (txSize)c_round(c_log1p(integer) / c_log(radix)) : 0) + 1;
468
154k
      if (fraction >= delta) {
469
115k
        #define mxFractionPartLength 2048
470
3.46k
        txString dot;
471
3.46k
        txInteger i = 0;
472
3.46k
        txInteger digit;
473
3.46k
        string = mxResult->value.string = fxNewChunk(the, length + 1 + mxFractionPartLength + 1);
474
3.46k
        dot = string + length;
475
3.46k
        dot[i++] = '.';
476
115k
        do {
477
115k
          fraction *= radix;
478
115k
          delta *= radix;
479
115k
          digit = (txInteger)fraction;
480
115k
          dot[i++] = c_read8(gxDigits + digit);
481
115k
          fraction -= digit;
482
115k
          if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
483
52.5k
            if (fraction + delta > 1) {
484
1.01k
              for (;;) {
485
1.01k
                char c;
486
1.01k
                i--;
487
1.01k
                if (i == 0) {
488
0
                  integer += 1;
489
0
                  break;
490
0
                }
491
1.01k
                c = dot[i];
492
1.01k
                digit = c > '9' ? (c - 'a' + 10) : (c - '0');
493
1.01k
                if (digit + 1 < radix) {
494
956
                  dot[i++] = c_read8(gxDigits + digit + 1);
495
956
                  break;
496
956
                }
497
1.01k
              }
498
956
              break;
499
956
            }
500
52.5k
          }
501
115k
        } while ((fraction >= delta) && (i < mxFractionPartLength));
502
3.46k
        dot[i++] = 0;
503
3.46k
        length += i;
504
3.46k
        string = dot;
505
3.46k
      }
506
150k
      else {
507
150k
        length += 1;
508
150k
        string = mxResult->value.string = fxNewChunk(the, length);
509
150k
        string += length;
510
150k
        *(--string) = 0;
511
150k
      }
512
154k
      modulo = C_MAX_SAFE_INTEGER * radix;
513
51.0M
      while (integer > modulo) {
514
50.9M
        *(--string) = '0';
515
50.9M
        integer = integer / radix;
516
50.9M
      }
517
5.25M
      do {
518
5.25M
        modulo = c_fmod(integer, radix);
519
5.25M
        *(--string) = c_read8(gxDigits + (txInteger)modulo);
520
5.25M
        integer = (integer - modulo) / radix;
521
5.25M
      } while (integer >= 1);
522
154k
      if (minus) {
523
2.11k
        *(--string) = '-';
524
2.11k
      }
525
154k
      minus = (txInteger)(string - mxResult->value.string);
526
154k
      if (minus > 0) {
527
2.16k
        length -= minus;
528
2.16k
        c_memmove(mxResult->value.string, string, length);
529
2.16k
      }
530
154k
      mxResult->value.string = fxRenewChunk(the, mxResult->value.string, length);
531
154k
      mxResult->kind = XS_STRING_KIND;
532
154k
    }}
533
672k
  }
534
673k
}
535
536
void fx_Number_prototype_valueOf(txMachine* the)
537
102k
{
538
102k
  txSlot* slot = fxCheckNumber(the, mxThis);
539
102k
  if (!slot) mxTypeError("this: not a number");
540
102k
  mxResult->kind = slot->kind;
541
102k
  mxResult->value = slot->value;
542
102k
}
543
544
txSlot* fxCheckNumber(txMachine* the, txSlot* it)
545
2.23M
{
546
2.23M
  txSlot* result = C_NULL;
547
2.23M
  if (it->kind == XS_INTEGER_KIND) {
548
226k
    fxToNumber(the, it);
549
226k
    result = it;
550
226k
  }
551
2.00M
  else if (it->kind == XS_NUMBER_KIND)
552
1.90M
    result = it;
553
102k
  else if (it->kind == XS_REFERENCE_KIND) {
554
102k
    txSlot* instance = it->value.reference;
555
102k
    it = instance->next;
556
102k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_NUMBER_KIND))
557
102k
      result = it;
558
102k
  }
559
2.23M
  return result;
560
2.23M
}