Skip to content

Commit b6c2e6e

Browse files
orkvirerobika
authored andcommitted
toNumber operation should handle binary and octal literals (#3471)
JerryScript-DCO-1.0-Signed-off-by: Virag Orkenyi orkvi@inf.u-szeged.hu
1 parent b3b1dfd commit b6c2e6e

2 files changed

Lines changed: 135 additions & 30 deletions

File tree

jerry-core/ecma/base/ecma-helpers-conversion.c

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -280,13 +280,87 @@ static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0,
280280
*/
281281
#define EPSILON 0.0000001
282282

283+
/**
284+
* ECMA-defined conversion from string to number for different radixes (2, 8, 16).
285+
*
286+
* See also:
287+
* ECMA-262 v5 9.3.1
288+
* ECMA-262 v6 7.1.3.1
289+
*
290+
* @return NaN - if the conversion fails
291+
* converted number - otherwise
292+
*/
293+
static ecma_number_t
294+
ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p, /**< utf-8 string */
295+
const lit_utf8_byte_t *end_p, /**< end of utf-8 string */
296+
uint32_t radix) /**< radix */
297+
{
298+
JERRY_ASSERT (radix == 2 || radix == 8 || radix == 16);
299+
ecma_number_t num = ECMA_NUMBER_ZERO;
300+
301+
#if ENABLED (JERRY_ES2015)
302+
if (radix <= 8)
303+
{
304+
lit_code_point_t upper_limit = LIT_CHAR_0 + radix;
305+
306+
for (const lit_utf8_byte_t * iter_p = str_p; iter_p <= end_p; iter_p++)
307+
{
308+
int32_t digit_value;
309+
310+
if (*iter_p >= LIT_CHAR_0 && *iter_p < upper_limit)
311+
{
312+
digit_value = (*iter_p - LIT_CHAR_0);
313+
}
314+
else
315+
{
316+
return ecma_number_make_nan ();
317+
}
318+
319+
num = num * radix + (ecma_number_t) digit_value;
320+
}
321+
322+
return num;
323+
}
324+
#endif /* ENABLED (JERRY_ES2015) */
325+
326+
for (const lit_utf8_byte_t * iter_p = str_p; iter_p <= end_p; iter_p++)
327+
{
328+
int32_t digit_value;
329+
330+
if (*iter_p >= LIT_CHAR_0
331+
&& *iter_p <= LIT_CHAR_9)
332+
{
333+
digit_value = (*iter_p - LIT_CHAR_0);
334+
}
335+
else if (*iter_p >= LIT_CHAR_LOWERCASE_A
336+
&& *iter_p <= LIT_CHAR_LOWERCASE_F)
337+
{
338+
digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A);
339+
}
340+
else if (*iter_p >= LIT_CHAR_UPPERCASE_A
341+
&& *iter_p <= LIT_CHAR_UPPERCASE_F)
342+
{
343+
digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A);
344+
}
345+
else
346+
{
347+
return ecma_number_make_nan ();
348+
}
349+
350+
num = num * radix + (ecma_number_t) digit_value;
351+
}
352+
353+
return num;
354+
} /* ecma_utf8_string_to_number_by_radix */
355+
283356
/**
284357
* ECMA-defined conversion of string to Number.
285358
*
286359
* See also:
287360
* ECMA-262 v5, 9.3.1
288361
*
289-
* @return ecma-number
362+
* @return NaN - if the conversion fails
363+
* converted number - otherwise
290364
*/
291365
ecma_number_t
292366
ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
@@ -307,46 +381,28 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */
307381
return ECMA_NUMBER_ZERO;
308382
}
309383

310-
if ((end_p >= str_p + 2)
311-
&& str_p[0] == LIT_CHAR_0
312-
&& (str_p[1] == LIT_CHAR_LOWERCASE_X
313-
|| str_p[1] == LIT_CHAR_UPPERCASE_X))
384+
if (end_p >= str_p + 2
385+
&& str_p[0] == LIT_CHAR_0)
314386
{
315-
/* Hex literal handling */
316-
str_p += 2;
317-
318-
ecma_number_t num = ECMA_NUMBER_ZERO;
319-
320-
for (const lit_utf8_byte_t * iter_p = str_p;
321-
iter_p <= end_p;
322-
iter_p++)
387+
switch (LEXER_TO_ASCII_LOWERCASE (str_p[1]))
323388
{
324-
int32_t digit_value;
325-
326-
if (*iter_p >= LIT_CHAR_0
327-
&& *iter_p <= LIT_CHAR_9)
389+
case LIT_CHAR_LOWERCASE_X :
328390
{
329-
digit_value = (*iter_p - LIT_CHAR_0);
391+
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 16);
330392
}
331-
else if (*iter_p >= LIT_CHAR_LOWERCASE_A
332-
&& *iter_p <= LIT_CHAR_LOWERCASE_F)
393+
case LIT_CHAR_LOWERCASE_O :
333394
{
334-
digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A);
395+
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 8);
335396
}
336-
else if (*iter_p >= LIT_CHAR_UPPERCASE_A
337-
&& *iter_p <= LIT_CHAR_UPPERCASE_F)
397+
case LIT_CHAR_LOWERCASE_B :
338398
{
339-
digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A);
399+
return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 2);
340400
}
341-
else
401+
default:
342402
{
343-
return ecma_number_make_nan ();
403+
break;
344404
}
345-
346-
num = num * 16 + (ecma_number_t) digit_value;
347405
}
348-
349-
return num;
350406
}
351407

352408
bool sign = false; /* positive */
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
assert(+"0b1101001" === 105);
17+
assert(+"0B1101001" === 105);
18+
assert(+"0o767" === 503);
19+
assert(+"0O767" === 503);
20+
21+
function assertNaN(str) {
22+
assert(isNaN(+str));
23+
}
24+
25+
assertNaN("0b");
26+
assertNaN("0b12");
27+
assertNaN("0b10101100103");
28+
assertNaN("0b101foo");
29+
assertNaN("0bfoo101");
30+
assertNaN("0b12345");
31+
32+
assertNaN("0B");
33+
assertNaN("0B12");
34+
assertNaN("0B10101100103");
35+
assertNaN("0B101foo");
36+
assertNaN("0Bfoo101");
37+
assertNaN("0B12345");
38+
39+
assertNaN("0o");
40+
assertNaN("0o1289");
41+
assertNaN("0o88888");
42+
assertNaN("0o12345foo");
43+
assertNaN("0ofoo12345");
44+
45+
assertNaN("0O");
46+
assertNaN("0O1289");
47+
assertNaN("0O88888");
48+
assertNaN("0O12345foo");
49+
assertNaN("0Ofoo12345");

0 commit comments

Comments
 (0)