Skip to content

Commit 35840a4

Browse files
committed
Implement parseInt()
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
1 parent de7b72d commit 35840a4

File tree

2 files changed

+221
-2
lines changed

2 files changed

+221
-2
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "ecma-try-catch-macro.h"
2424
#include "jrt.h"
2525
#include "vm.h"
26+
#include "jrt-libc-includes.h"
2627

2728
#define ECMA_BUILTINS_INTERNAL
2829
#include "ecma-builtins-internal.h"
@@ -97,11 +98,160 @@ ecma_builtin_global_object_eval (ecma_value_t this_arg, /**< this argument */
9798
* Returned value must be freed with ecma_free_completion_value.
9899
*/
99100
static ecma_completion_value_t
100-
ecma_builtin_global_object_parse_int (ecma_value_t this_arg, /**< this argument */
101+
ecma_builtin_global_object_parse_int (ecma_value_t this_arg __attr_unused___, /**< this argument */
101102
ecma_value_t string, /**< routine's first argument */
102103
ecma_value_t radix) /**< routine's second argument */
103104
{
104-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, string, radix);
105+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
106+
107+
/* 1. */
108+
ECMA_TRY_CATCH (string_var, ecma_op_to_string (string), ret_value);
109+
110+
ecma_string_t *number_str_p = ecma_get_string_from_value (string_var);
111+
int32_t string_len = ecma_string_get_length (number_str_p);
112+
113+
MEM_DEFINE_LOCAL_ARRAY (zt_string_buff, string_len + 1, ecma_char_t);
114+
115+
size_t string_buf_size = (size_t) (string_len + 1) * sizeof (ecma_char_t);
116+
ssize_t bytes_copied = ecma_string_to_zt_string (number_str_p,
117+
zt_string_buff,
118+
(ssize_t) string_buf_size);
119+
JERRY_ASSERT (bytes_copied > 0);
120+
121+
/* 2. Remove leading whitespace. */
122+
int32_t start = string_len;
123+
int32_t end = string_len;
124+
for (int i = 0; i < end; i++)
125+
{
126+
if (!(isspace (zt_string_buff[i])))
127+
{
128+
start = i;
129+
break;
130+
}
131+
}
132+
133+
/* 3. */
134+
int sign = 1;
135+
136+
/* 4. */
137+
if (zt_string_buff[start] == '-')
138+
{
139+
sign = -1;
140+
}
141+
142+
/* 5. */
143+
if (zt_string_buff[start] == '-' || zt_string_buff[start] == '+')
144+
{
145+
start++;
146+
}
147+
148+
/* 6. */
149+
ECMA_OP_TO_NUMBER_TRY_CATCH (radix_num, radix, ret_value);
150+
int32_t rad = ecma_number_to_int32 (radix_num);
151+
152+
/* 7.*/
153+
bool strip_prefix = true;
154+
155+
/* 8. */
156+
if (rad != 0)
157+
{
158+
/* 8.a */
159+
if (rad < 2 || rad > 36)
160+
{
161+
ecma_number_t *ret_num_p = ecma_alloc_number ();
162+
*ret_num_p = ecma_number_make_nan ();
163+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
164+
}
165+
/* 8.b */
166+
else if (rad != 16)
167+
{
168+
strip_prefix = false;
169+
}
170+
}
171+
/* 9. */
172+
else
173+
{
174+
rad = 10;
175+
}
176+
177+
if (ecma_is_completion_value_empty (ret_value))
178+
{
179+
/* 10. */
180+
if (strip_prefix)
181+
{
182+
if (end - start >= 2
183+
&& zt_string_buff[start] == '0'
184+
&& (zt_string_buff[start + 1] == 'x' || zt_string_buff[start + 1] == 'X'))
185+
{
186+
start += 2;
187+
188+
rad = 16;
189+
}
190+
}
191+
192+
/* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */
193+
for (int i = start; i < end; i++)
194+
{
195+
if ((zt_string_buff[i]) >= 'a' && zt_string_buff[i] <= 'z')
196+
{
197+
zt_string_buff[i] = (ecma_char_t) (zt_string_buff[i] - 'a' + 10);
198+
}
199+
else if (zt_string_buff[i] >= 'A' && zt_string_buff[i] <= 'Z')
200+
{
201+
zt_string_buff[i] = (ecma_char_t) (zt_string_buff[i] - 'A' + 10);
202+
}
203+
else if (isdigit (zt_string_buff[i]))
204+
{
205+
zt_string_buff[i] = (ecma_char_t) (zt_string_buff[i] - '0');
206+
}
207+
else
208+
{
209+
/* Not a valid number char, set value to radix so it fails to pass as a valid character. */
210+
zt_string_buff[i] = (ecma_char_t) rad;
211+
}
212+
213+
if (!(zt_string_buff[i] < rad))
214+
{
215+
end = i;
216+
break;
217+
}
218+
}
219+
220+
/* 12. */
221+
if (end - start == 0)
222+
{
223+
ecma_number_t *ret_num_p = ecma_alloc_number ();
224+
*ret_num_p = ecma_number_make_nan ();
225+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
226+
}
227+
}
228+
229+
if (ecma_is_completion_value_empty (ret_value))
230+
{
231+
ecma_number_t *value_p = ecma_alloc_number ();
232+
*value_p = 0;
233+
ecma_number_t multiplier = 1.0f;
234+
235+
/* 13. and 14. */
236+
for (int i = end - 1; i >= start; i--)
237+
{
238+
*value_p += (ecma_number_t) zt_string_buff[i] * multiplier;
239+
multiplier *= (ecma_number_t) rad;
240+
}
241+
242+
/* 15. */
243+
if (sign < 0)
244+
{
245+
*value_p *= (ecma_number_t) sign;
246+
}
247+
248+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (value_p));
249+
}
250+
251+
ECMA_OP_TO_NUMBER_FINALIZE (radix_num);
252+
MEM_FINALIZE_LOCAL_ARRAY (zt_string_buff);
253+
ECMA_FINALIZE (string_var);
254+
return ret_value;
105255
} /* ecma_builtin_global_object_parse_int */
106256

107257
/**

tests/jerry/global-parseint.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2015 Samsung Electronics Co., Ltd.
2+
// Copyright 2015 University of Szeged.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
assert(parseInt("123") === 123);
17+
assert(parseInt("+123") === 123);
18+
assert(parseInt("-123") === -123);
19+
assert(parseInt("0123") === 123);
20+
assert(parseInt(" 123") === 123);
21+
assert(parseInt(" \n 123") === 123);
22+
assert(parseInt(" \n 123 \t") === 123);
23+
assert(parseInt("0x123") === 291);
24+
assert(parseInt("0X123") === 291);
25+
assert(parseInt("123", 4) === 27);
26+
assert(parseInt("ABC", 16) === 2748);
27+
assert(parseInt("12A3") === 12);
28+
assert(parseInt("12.34") === 12);
29+
assert(isNaN(parseInt("AB")));
30+
31+
var bool = true;
32+
var obj = new Object();
33+
var num = 8;
34+
var arr = [2,3,4];
35+
var undef;
36+
37+
assert(isNaN(parseInt(bool, bool)));
38+
assert(isNaN(parseInt(bool, obj)));
39+
assert(isNaN(parseInt(bool, num)));
40+
assert(isNaN(parseInt(bool, arr)));
41+
42+
assert(isNaN(parseInt(obj, bool)));
43+
assert(isNaN(parseInt(obj, obj)));
44+
assert(isNaN(parseInt(obj, num)));
45+
assert(isNaN(parseInt(obj, arr)));
46+
47+
assert(isNaN(parseInt(num, bool)));
48+
assert(parseInt(num, obj) === 8);
49+
assert(isNaN(parseInt(num, num)));
50+
assert(parseInt(num, arr) === 8);
51+
52+
assert(isNaN(parseInt(arr, bool)));
53+
assert(parseInt(arr, obj) === 2);
54+
assert(parseInt(arr, num) === 2);
55+
assert(parseInt(arr, arr) === 2);
56+
57+
assert(isNaN(parseInt(undef, bool)));
58+
assert(isNaN(parseInt(undef, obj)));
59+
assert(isNaN(parseInt(undef, num)));
60+
assert(isNaN(parseInt(undef, arr)));
61+
62+
var obj = { toString : function () { throw new ReferenceError("foo") } };
63+
try {
64+
parseInt(obj);
65+
assert(false);
66+
} catch (e) {
67+
assert(e instanceof ReferenceError);
68+
assert(e.message === "foo");
69+
}

0 commit comments

Comments
 (0)