1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci#include "ecma-alloc.h"
17425bb815Sopenharmony_ci#include "ecma-array-object.h"
18425bb815Sopenharmony_ci#include "ecma-builtins.h"
19425bb815Sopenharmony_ci#include "ecma-conversion.h"
20425bb815Sopenharmony_ci#include "ecma-exceptions.h"
21425bb815Sopenharmony_ci#include "ecma-function-object.h"
22425bb815Sopenharmony_ci#include "ecma-gc.h"
23425bb815Sopenharmony_ci#include "ecma-globals.h"
24425bb815Sopenharmony_ci#include "ecma-helpers.h"
25425bb815Sopenharmony_ci#include "ecma-builtin-helpers.h"
26425bb815Sopenharmony_ci#include "ecma-objects.h"
27425bb815Sopenharmony_ci#include "ecma-objects-general.h"
28425bb815Sopenharmony_ci#include "jrt.h"
29425bb815Sopenharmony_ci#include "jrt-libc-includes.h"
30425bb815Sopenharmony_ci#include "lit-char-helpers.h"
31425bb815Sopenharmony_ci#include "lit-globals.h"
32425bb815Sopenharmony_ci
33425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_JSON)
34425bb815Sopenharmony_ci
35425bb815Sopenharmony_ci#define ECMA_BUILTINS_INTERNAL
36425bb815Sopenharmony_ci#include "ecma-builtins-internal.h"
37425bb815Sopenharmony_ci
38425bb815Sopenharmony_ci#define BUILTIN_INC_HEADER_NAME "ecma-builtin-json.inc.h"
39425bb815Sopenharmony_ci#define BUILTIN_UNDERSCORED_ID json
40425bb815Sopenharmony_ci#include "ecma-builtin-internal-routines-template.inc.h"
41425bb815Sopenharmony_ci
42425bb815Sopenharmony_ci/**
43425bb815Sopenharmony_ci * The number of expected hexidecimal characters in a hex escape sequence
44425bb815Sopenharmony_ci */
45425bb815Sopenharmony_ci#define ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH (4)
46425bb815Sopenharmony_ci
47425bb815Sopenharmony_ci/** \addtogroup ecma ECMA
48425bb815Sopenharmony_ci * @{
49425bb815Sopenharmony_ci *
50425bb815Sopenharmony_ci * \addtogroup ecmabuiltins
51425bb815Sopenharmony_ci * @{
52425bb815Sopenharmony_ci *
53425bb815Sopenharmony_ci * \addtogroup json ECMA JSON object built-in
54425bb815Sopenharmony_ci * @{
55425bb815Sopenharmony_ci */
56425bb815Sopenharmony_ci
57425bb815Sopenharmony_ci/**
58425bb815Sopenharmony_ci * JSON token type
59425bb815Sopenharmony_ci */
60425bb815Sopenharmony_citypedef enum
61425bb815Sopenharmony_ci{
62425bb815Sopenharmony_ci  TOKEN_INVALID, /**< error token */
63425bb815Sopenharmony_ci  TOKEN_END, /**< end of stream reached */
64425bb815Sopenharmony_ci  TOKEN_NUMBER, /**< JSON number */
65425bb815Sopenharmony_ci  TOKEN_STRING, /**< JSON string */
66425bb815Sopenharmony_ci  TOKEN_NULL, /**< JSON null primitive value */
67425bb815Sopenharmony_ci  TOKEN_TRUE, /**< JSON true primitive value */
68425bb815Sopenharmony_ci  TOKEN_FALSE, /**< JSON false primitive value */
69425bb815Sopenharmony_ci  TOKEN_LEFT_BRACE, /**< JSON left brace */
70425bb815Sopenharmony_ci  TOKEN_RIGHT_BRACE, /**< JSON right brace */
71425bb815Sopenharmony_ci  TOKEN_LEFT_SQUARE, /**< JSON left square bracket */
72425bb815Sopenharmony_ci  TOKEN_RIGHT_SQUARE, /**< JSON right square bracket */
73425bb815Sopenharmony_ci  TOKEN_COMMA, /**< JSON comma */
74425bb815Sopenharmony_ci  TOKEN_COLON /**< JSON colon */
75425bb815Sopenharmony_ci} ecma_json_token_type_t;
76425bb815Sopenharmony_ci
77425bb815Sopenharmony_ci/**
78425bb815Sopenharmony_ci * JSON token
79425bb815Sopenharmony_ci */
80425bb815Sopenharmony_citypedef struct
81425bb815Sopenharmony_ci{
82425bb815Sopenharmony_ci  ecma_json_token_type_t type; /**< type of the current token */
83425bb815Sopenharmony_ci  const lit_utf8_byte_t *current_p; /**< current position of the string processed by the parser */
84425bb815Sopenharmony_ci  const lit_utf8_byte_t *end_p; /**< end of the string processed by the parser */
85425bb815Sopenharmony_ci
86425bb815Sopenharmony_ci  /**
87425bb815Sopenharmony_ci   * Fields depending on type.
88425bb815Sopenharmony_ci   */
89425bb815Sopenharmony_ci  union
90425bb815Sopenharmony_ci  {
91425bb815Sopenharmony_ci    ecma_string_t *string_p; /**< when type is string_token it contains the string */
92425bb815Sopenharmony_ci    ecma_number_t number; /**< when type is number_token, it contains the value of the number */
93425bb815Sopenharmony_ci  } u;
94425bb815Sopenharmony_ci} ecma_json_token_t;
95425bb815Sopenharmony_ci
96425bb815Sopenharmony_ci/**
97425bb815Sopenharmony_ci * Parse and extract string token.
98425bb815Sopenharmony_ci */
99425bb815Sopenharmony_cistatic void
100425bb815Sopenharmony_ciecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument */
101425bb815Sopenharmony_ci{
102425bb815Sopenharmony_ci  const lit_utf8_byte_t *current_p = token_p->current_p;
103425bb815Sopenharmony_ci  const lit_utf8_byte_t *end_p = token_p->end_p;
104425bb815Sopenharmony_ci
105425bb815Sopenharmony_ci  ecma_stringbuilder_t result_builder = ecma_stringbuilder_create ();
106425bb815Sopenharmony_ci  const lit_utf8_byte_t *unappended_p = current_p;
107425bb815Sopenharmony_ci
108425bb815Sopenharmony_ci  while (true)
109425bb815Sopenharmony_ci  {
110425bb815Sopenharmony_ci    if (current_p >= end_p || *current_p <= 0x1f)
111425bb815Sopenharmony_ci    {
112425bb815Sopenharmony_ci      goto invalid_string;
113425bb815Sopenharmony_ci    }
114425bb815Sopenharmony_ci
115425bb815Sopenharmony_ci    if (*current_p == LIT_CHAR_DOUBLE_QUOTE)
116425bb815Sopenharmony_ci    {
117425bb815Sopenharmony_ci      break;
118425bb815Sopenharmony_ci    }
119425bb815Sopenharmony_ci
120425bb815Sopenharmony_ci    if (*current_p == LIT_CHAR_BACKSLASH)
121425bb815Sopenharmony_ci    {
122425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (&result_builder,
123425bb815Sopenharmony_ci                                     unappended_p,
124425bb815Sopenharmony_ci                                     (lit_utf8_size_t) (current_p - unappended_p));
125425bb815Sopenharmony_ci
126425bb815Sopenharmony_ci      current_p++;
127425bb815Sopenharmony_ci
128425bb815Sopenharmony_ci      /* If there is an escape sequence but there's no escapable character just return */
129425bb815Sopenharmony_ci      if (current_p >= end_p)
130425bb815Sopenharmony_ci      {
131425bb815Sopenharmony_ci        goto invalid_string;
132425bb815Sopenharmony_ci      }
133425bb815Sopenharmony_ci
134425bb815Sopenharmony_ci      const lit_utf8_byte_t c = *current_p;
135425bb815Sopenharmony_ci      switch (c)
136425bb815Sopenharmony_ci      {
137425bb815Sopenharmony_ci        case LIT_CHAR_DOUBLE_QUOTE:
138425bb815Sopenharmony_ci        case LIT_CHAR_SLASH:
139425bb815Sopenharmony_ci        case LIT_CHAR_BACKSLASH:
140425bb815Sopenharmony_ci        {
141425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, c);
142425bb815Sopenharmony_ci          current_p++;
143425bb815Sopenharmony_ci          break;
144425bb815Sopenharmony_ci        }
145425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_B:
146425bb815Sopenharmony_ci        {
147425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, LIT_CHAR_BS);
148425bb815Sopenharmony_ci          current_p++;
149425bb815Sopenharmony_ci          break;
150425bb815Sopenharmony_ci        }
151425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_F:
152425bb815Sopenharmony_ci        {
153425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, LIT_CHAR_FF);
154425bb815Sopenharmony_ci          current_p++;
155425bb815Sopenharmony_ci          break;
156425bb815Sopenharmony_ci        }
157425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_N:
158425bb815Sopenharmony_ci        {
159425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, LIT_CHAR_LF);
160425bb815Sopenharmony_ci          current_p++;
161425bb815Sopenharmony_ci          break;
162425bb815Sopenharmony_ci        }
163425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_R:
164425bb815Sopenharmony_ci        {
165425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, LIT_CHAR_CR);
166425bb815Sopenharmony_ci          current_p++;
167425bb815Sopenharmony_ci          break;
168425bb815Sopenharmony_ci        }
169425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_T:
170425bb815Sopenharmony_ci        {
171425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (&result_builder, LIT_CHAR_TAB);
172425bb815Sopenharmony_ci          current_p++;
173425bb815Sopenharmony_ci          break;
174425bb815Sopenharmony_ci        }
175425bb815Sopenharmony_ci        case LIT_CHAR_LOWERCASE_U:
176425bb815Sopenharmony_ci        {
177425bb815Sopenharmony_ci          uint32_t hex_value = lit_char_hex_lookup (current_p + 1, end_p, ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH);
178425bb815Sopenharmony_ci          if (hex_value == UINT32_MAX)
179425bb815Sopenharmony_ci          {
180425bb815Sopenharmony_ci            goto invalid_string;
181425bb815Sopenharmony_ci          }
182425bb815Sopenharmony_ci
183425bb815Sopenharmony_ci          ecma_stringbuilder_append_char (&result_builder, (ecma_char_t) hex_value);
184425bb815Sopenharmony_ci          current_p += ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH + 1;
185425bb815Sopenharmony_ci          break;
186425bb815Sopenharmony_ci        }
187425bb815Sopenharmony_ci        default:
188425bb815Sopenharmony_ci        {
189425bb815Sopenharmony_ci          goto invalid_string;
190425bb815Sopenharmony_ci        }
191425bb815Sopenharmony_ci      }
192425bb815Sopenharmony_ci
193425bb815Sopenharmony_ci      unappended_p = current_p;
194425bb815Sopenharmony_ci      continue;
195425bb815Sopenharmony_ci    }
196425bb815Sopenharmony_ci
197425bb815Sopenharmony_ci    current_p++;
198425bb815Sopenharmony_ci  }
199425bb815Sopenharmony_ci
200425bb815Sopenharmony_ci  ecma_stringbuilder_append_raw (&result_builder,
201425bb815Sopenharmony_ci                                 unappended_p,
202425bb815Sopenharmony_ci                                 (lit_utf8_size_t) (current_p - unappended_p));
203425bb815Sopenharmony_ci  token_p->u.string_p = ecma_stringbuilder_finalize (&result_builder);
204425bb815Sopenharmony_ci  token_p->current_p = current_p + 1;
205425bb815Sopenharmony_ci  token_p->type = TOKEN_STRING;
206425bb815Sopenharmony_ci  return;
207425bb815Sopenharmony_ci
208425bb815Sopenharmony_ciinvalid_string:
209425bb815Sopenharmony_ci  ecma_stringbuilder_destroy (&result_builder);
210425bb815Sopenharmony_ci} /* ecma_builtin_json_parse_string */
211425bb815Sopenharmony_ci
212425bb815Sopenharmony_ci/**
213425bb815Sopenharmony_ci * Parse and extract string token.
214425bb815Sopenharmony_ci */
215425bb815Sopenharmony_cistatic void
216425bb815Sopenharmony_ciecma_builtin_json_parse_number (ecma_json_token_t *token_p) /**< token argument */
217425bb815Sopenharmony_ci{
218425bb815Sopenharmony_ci  const lit_utf8_byte_t *current_p = token_p->current_p;
219425bb815Sopenharmony_ci  const lit_utf8_byte_t *end_p = token_p->end_p;
220425bb815Sopenharmony_ci  const lit_utf8_byte_t *start_p = current_p;
221425bb815Sopenharmony_ci
222425bb815Sopenharmony_ci  JERRY_ASSERT (current_p < end_p);
223425bb815Sopenharmony_ci
224425bb815Sopenharmony_ci  if (*current_p == LIT_CHAR_MINUS)
225425bb815Sopenharmony_ci  {
226425bb815Sopenharmony_ci    current_p++;
227425bb815Sopenharmony_ci  }
228425bb815Sopenharmony_ci
229425bb815Sopenharmony_ci  if (current_p >= end_p)
230425bb815Sopenharmony_ci  {
231425bb815Sopenharmony_ci    return;
232425bb815Sopenharmony_ci  }
233425bb815Sopenharmony_ci
234425bb815Sopenharmony_ci  if (*current_p == LIT_CHAR_0)
235425bb815Sopenharmony_ci  {
236425bb815Sopenharmony_ci    current_p++;
237425bb815Sopenharmony_ci
238425bb815Sopenharmony_ci    if (current_p < end_p && lit_char_is_decimal_digit (*current_p))
239425bb815Sopenharmony_ci    {
240425bb815Sopenharmony_ci      return;
241425bb815Sopenharmony_ci    }
242425bb815Sopenharmony_ci  }
243425bb815Sopenharmony_ci  else if (lit_char_is_decimal_digit (*current_p))
244425bb815Sopenharmony_ci  {
245425bb815Sopenharmony_ci    do
246425bb815Sopenharmony_ci    {
247425bb815Sopenharmony_ci      current_p++;
248425bb815Sopenharmony_ci    }
249425bb815Sopenharmony_ci    while (current_p < end_p && lit_char_is_decimal_digit (*current_p));
250425bb815Sopenharmony_ci  }
251425bb815Sopenharmony_ci
252425bb815Sopenharmony_ci  if (current_p < end_p && *current_p == LIT_CHAR_DOT)
253425bb815Sopenharmony_ci  {
254425bb815Sopenharmony_ci    current_p++;
255425bb815Sopenharmony_ci
256425bb815Sopenharmony_ci    if (current_p >= end_p || !lit_char_is_decimal_digit (*current_p))
257425bb815Sopenharmony_ci    {
258425bb815Sopenharmony_ci      return;
259425bb815Sopenharmony_ci    }
260425bb815Sopenharmony_ci
261425bb815Sopenharmony_ci    do
262425bb815Sopenharmony_ci    {
263425bb815Sopenharmony_ci      current_p++;
264425bb815Sopenharmony_ci    }
265425bb815Sopenharmony_ci    while (current_p < end_p && lit_char_is_decimal_digit (*current_p));
266425bb815Sopenharmony_ci  }
267425bb815Sopenharmony_ci
268425bb815Sopenharmony_ci  if (current_p < end_p && (*current_p == LIT_CHAR_LOWERCASE_E || *current_p == LIT_CHAR_UPPERCASE_E))
269425bb815Sopenharmony_ci  {
270425bb815Sopenharmony_ci    current_p++;
271425bb815Sopenharmony_ci
272425bb815Sopenharmony_ci    if (current_p < end_p && (*current_p == LIT_CHAR_PLUS || *current_p == LIT_CHAR_MINUS))
273425bb815Sopenharmony_ci    {
274425bb815Sopenharmony_ci      current_p++;
275425bb815Sopenharmony_ci    }
276425bb815Sopenharmony_ci
277425bb815Sopenharmony_ci    if (current_p >= end_p || !lit_char_is_decimal_digit (*current_p))
278425bb815Sopenharmony_ci    {
279425bb815Sopenharmony_ci      return;
280425bb815Sopenharmony_ci    }
281425bb815Sopenharmony_ci
282425bb815Sopenharmony_ci    do
283425bb815Sopenharmony_ci    {
284425bb815Sopenharmony_ci      current_p++;
285425bb815Sopenharmony_ci    }
286425bb815Sopenharmony_ci    while (current_p < end_p && lit_char_is_decimal_digit (*current_p));
287425bb815Sopenharmony_ci  }
288425bb815Sopenharmony_ci
289425bb815Sopenharmony_ci  token_p->type = TOKEN_NUMBER;
290425bb815Sopenharmony_ci  token_p->u.number = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (current_p - start_p));
291425bb815Sopenharmony_ci
292425bb815Sopenharmony_ci  token_p->current_p = current_p;
293425bb815Sopenharmony_ci} /* ecma_builtin_json_parse_number */
294425bb815Sopenharmony_ci
295425bb815Sopenharmony_ci/**
296425bb815Sopenharmony_ci * Parse next token.
297425bb815Sopenharmony_ci *
298425bb815Sopenharmony_ci * The function fills the fields of the ecma_json_token_t
299425bb815Sopenharmony_ci * argument and advances the string pointer.
300425bb815Sopenharmony_ci */
301425bb815Sopenharmony_cistatic void
302425bb815Sopenharmony_ciecma_builtin_json_parse_next_token (ecma_json_token_t *token_p, /**< token argument */
303425bb815Sopenharmony_ci                                    bool parse_string) /**< strings are allowed to parse */
304425bb815Sopenharmony_ci{
305425bb815Sopenharmony_ci  const lit_utf8_byte_t *current_p = token_p->current_p;
306425bb815Sopenharmony_ci  const lit_utf8_byte_t *end_p = token_p->end_p;
307425bb815Sopenharmony_ci  token_p->type = TOKEN_INVALID;
308425bb815Sopenharmony_ci
309425bb815Sopenharmony_ci  while (current_p < end_p
310425bb815Sopenharmony_ci         && (*current_p == LIT_CHAR_SP
311425bb815Sopenharmony_ci             || *current_p == LIT_CHAR_CR
312425bb815Sopenharmony_ci             || *current_p == LIT_CHAR_LF
313425bb815Sopenharmony_ci             || *current_p == LIT_CHAR_TAB))
314425bb815Sopenharmony_ci  {
315425bb815Sopenharmony_ci    current_p++;
316425bb815Sopenharmony_ci  }
317425bb815Sopenharmony_ci
318425bb815Sopenharmony_ci  if (current_p == end_p)
319425bb815Sopenharmony_ci  {
320425bb815Sopenharmony_ci    token_p->type = TOKEN_END;
321425bb815Sopenharmony_ci    return;
322425bb815Sopenharmony_ci  }
323425bb815Sopenharmony_ci
324425bb815Sopenharmony_ci  switch (*current_p)
325425bb815Sopenharmony_ci  {
326425bb815Sopenharmony_ci    case LIT_CHAR_LEFT_BRACE:
327425bb815Sopenharmony_ci    {
328425bb815Sopenharmony_ci      token_p->type = TOKEN_LEFT_BRACE;
329425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
330425bb815Sopenharmony_ci      return;
331425bb815Sopenharmony_ci    }
332425bb815Sopenharmony_ci    case LIT_CHAR_RIGHT_BRACE:
333425bb815Sopenharmony_ci    {
334425bb815Sopenharmony_ci      token_p->type = TOKEN_RIGHT_BRACE;
335425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
336425bb815Sopenharmony_ci      return;
337425bb815Sopenharmony_ci    }
338425bb815Sopenharmony_ci    case LIT_CHAR_LEFT_SQUARE:
339425bb815Sopenharmony_ci    {
340425bb815Sopenharmony_ci      token_p->type = TOKEN_LEFT_SQUARE;
341425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
342425bb815Sopenharmony_ci      return;
343425bb815Sopenharmony_ci    }
344425bb815Sopenharmony_ci    case LIT_CHAR_RIGHT_SQUARE:
345425bb815Sopenharmony_ci    {
346425bb815Sopenharmony_ci      token_p->type = TOKEN_RIGHT_SQUARE;
347425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
348425bb815Sopenharmony_ci      return;
349425bb815Sopenharmony_ci    }
350425bb815Sopenharmony_ci    case LIT_CHAR_COMMA:
351425bb815Sopenharmony_ci    {
352425bb815Sopenharmony_ci      token_p->type = TOKEN_COMMA;
353425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
354425bb815Sopenharmony_ci      return;
355425bb815Sopenharmony_ci    }
356425bb815Sopenharmony_ci    case LIT_CHAR_COLON:
357425bb815Sopenharmony_ci    {
358425bb815Sopenharmony_ci      token_p->type = TOKEN_COLON;
359425bb815Sopenharmony_ci      token_p->current_p = current_p + 1;
360425bb815Sopenharmony_ci      return;
361425bb815Sopenharmony_ci    }
362425bb815Sopenharmony_ci    case LIT_CHAR_DOUBLE_QUOTE:
363425bb815Sopenharmony_ci    {
364425bb815Sopenharmony_ci      if (parse_string)
365425bb815Sopenharmony_ci      {
366425bb815Sopenharmony_ci        token_p->current_p = current_p + 1;
367425bb815Sopenharmony_ci        ecma_builtin_json_parse_string (token_p);
368425bb815Sopenharmony_ci      }
369425bb815Sopenharmony_ci      return;
370425bb815Sopenharmony_ci    }
371425bb815Sopenharmony_ci    case LIT_CHAR_LOWERCASE_N:
372425bb815Sopenharmony_ci    {
373425bb815Sopenharmony_ci      lit_utf8_size_t size = lit_get_magic_string_size (LIT_MAGIC_STRING_NULL);
374425bb815Sopenharmony_ci      if (current_p + size <= end_p)
375425bb815Sopenharmony_ci      {
376425bb815Sopenharmony_ci        if (!memcmp (lit_get_magic_string_utf8 (LIT_MAGIC_STRING_NULL),
377425bb815Sopenharmony_ci                     current_p,
378425bb815Sopenharmony_ci                     size))
379425bb815Sopenharmony_ci        {
380425bb815Sopenharmony_ci          token_p->type = TOKEN_NULL;
381425bb815Sopenharmony_ci          token_p->current_p = current_p + size;
382425bb815Sopenharmony_ci          return;
383425bb815Sopenharmony_ci        }
384425bb815Sopenharmony_ci      }
385425bb815Sopenharmony_ci      break;
386425bb815Sopenharmony_ci    }
387425bb815Sopenharmony_ci    case LIT_CHAR_LOWERCASE_T:
388425bb815Sopenharmony_ci    {
389425bb815Sopenharmony_ci      lit_utf8_size_t size = lit_get_magic_string_size (LIT_MAGIC_STRING_TRUE);
390425bb815Sopenharmony_ci      if (current_p + size <= end_p)
391425bb815Sopenharmony_ci      {
392425bb815Sopenharmony_ci        if (!memcmp (lit_get_magic_string_utf8 (LIT_MAGIC_STRING_TRUE),
393425bb815Sopenharmony_ci                     current_p,
394425bb815Sopenharmony_ci                     size))
395425bb815Sopenharmony_ci        {
396425bb815Sopenharmony_ci          token_p->type = TOKEN_TRUE;
397425bb815Sopenharmony_ci          token_p->current_p = current_p + size;
398425bb815Sopenharmony_ci          return;
399425bb815Sopenharmony_ci        }
400425bb815Sopenharmony_ci      }
401425bb815Sopenharmony_ci      break;
402425bb815Sopenharmony_ci    }
403425bb815Sopenharmony_ci    case LIT_CHAR_LOWERCASE_F:
404425bb815Sopenharmony_ci    {
405425bb815Sopenharmony_ci      lit_utf8_size_t size = lit_get_magic_string_size (LIT_MAGIC_STRING_FALSE);
406425bb815Sopenharmony_ci      if (current_p + size <= end_p)
407425bb815Sopenharmony_ci      {
408425bb815Sopenharmony_ci        if (!memcmp (lit_get_magic_string_utf8 (LIT_MAGIC_STRING_FALSE),
409425bb815Sopenharmony_ci                     current_p,
410425bb815Sopenharmony_ci                     size))
411425bb815Sopenharmony_ci        {
412425bb815Sopenharmony_ci          token_p->type = TOKEN_FALSE;
413425bb815Sopenharmony_ci          token_p->current_p = current_p + size;
414425bb815Sopenharmony_ci          return;
415425bb815Sopenharmony_ci        }
416425bb815Sopenharmony_ci      }
417425bb815Sopenharmony_ci      break;
418425bb815Sopenharmony_ci    }
419425bb815Sopenharmony_ci    default:
420425bb815Sopenharmony_ci    {
421425bb815Sopenharmony_ci      if (*current_p == LIT_CHAR_MINUS || lit_char_is_decimal_digit (*current_p))
422425bb815Sopenharmony_ci      {
423425bb815Sopenharmony_ci        token_p->current_p = current_p;
424425bb815Sopenharmony_ci        ecma_builtin_json_parse_number (token_p);
425425bb815Sopenharmony_ci        return;
426425bb815Sopenharmony_ci      }
427425bb815Sopenharmony_ci      break;
428425bb815Sopenharmony_ci    }
429425bb815Sopenharmony_ci  }
430425bb815Sopenharmony_ci} /* ecma_builtin_json_parse_next_token */
431425bb815Sopenharmony_ci
432425bb815Sopenharmony_ci/**
433425bb815Sopenharmony_ci * Utility for defining properties.
434425bb815Sopenharmony_ci *
435425bb815Sopenharmony_ci * It silently ignores all errors.
436425bb815Sopenharmony_ci */
437425bb815Sopenharmony_cistatic void
438425bb815Sopenharmony_ciecma_builtin_json_define_value_property (ecma_object_t *obj_p, /**< this object */
439425bb815Sopenharmony_ci                                         ecma_string_t *property_name_p, /**< property name */
440425bb815Sopenharmony_ci                                         ecma_value_t value) /**< value */
441425bb815Sopenharmony_ci{
442425bb815Sopenharmony_ci  ecma_value_t completion_value = ecma_builtin_helper_def_prop (obj_p,
443425bb815Sopenharmony_ci                                                                property_name_p,
444425bb815Sopenharmony_ci                                                                value,
445425bb815Sopenharmony_ci                                                                ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
446425bb815Sopenharmony_ci
447425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_boolean (completion_value));
448425bb815Sopenharmony_ci} /* ecma_builtin_json_define_value_property */
449425bb815Sopenharmony_ci
450425bb815Sopenharmony_ci/**
451425bb815Sopenharmony_ci * Parse next value.
452425bb815Sopenharmony_ci *
453425bb815Sopenharmony_ci * The function fills the fields of the ecma_json_token_t
454425bb815Sopenharmony_ci * argument and advances the string pointer.
455425bb815Sopenharmony_ci *
456425bb815Sopenharmony_ci * @return ecma_value with the property value
457425bb815Sopenharmony_ci */
458425bb815Sopenharmony_cistatic ecma_value_t
459425bb815Sopenharmony_ciecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument */
460425bb815Sopenharmony_ci{
461425bb815Sopenharmony_ci  switch (token_p->type)
462425bb815Sopenharmony_ci  {
463425bb815Sopenharmony_ci    case TOKEN_NUMBER:
464425bb815Sopenharmony_ci    {
465425bb815Sopenharmony_ci      return ecma_make_number_value (token_p->u.number);
466425bb815Sopenharmony_ci    }
467425bb815Sopenharmony_ci    case TOKEN_STRING:
468425bb815Sopenharmony_ci    {
469425bb815Sopenharmony_ci      return ecma_make_string_value (token_p->u.string_p);
470425bb815Sopenharmony_ci    }
471425bb815Sopenharmony_ci    case TOKEN_NULL:
472425bb815Sopenharmony_ci    {
473425bb815Sopenharmony_ci      return ECMA_VALUE_NULL;
474425bb815Sopenharmony_ci    }
475425bb815Sopenharmony_ci    case TOKEN_TRUE:
476425bb815Sopenharmony_ci    {
477425bb815Sopenharmony_ci      return ECMA_VALUE_TRUE;
478425bb815Sopenharmony_ci    }
479425bb815Sopenharmony_ci    case TOKEN_FALSE:
480425bb815Sopenharmony_ci    {
481425bb815Sopenharmony_ci      return ECMA_VALUE_FALSE;
482425bb815Sopenharmony_ci    }
483425bb815Sopenharmony_ci    case TOKEN_LEFT_BRACE:
484425bb815Sopenharmony_ci    {
485425bb815Sopenharmony_ci      ecma_object_t *object_p = ecma_op_create_object_object_noarg ();
486425bb815Sopenharmony_ci
487425bb815Sopenharmony_ci      ecma_builtin_json_parse_next_token (token_p, true);
488425bb815Sopenharmony_ci
489425bb815Sopenharmony_ci      if (token_p->type == TOKEN_RIGHT_BRACE)
490425bb815Sopenharmony_ci      {
491425bb815Sopenharmony_ci        return ecma_make_object_value (object_p);
492425bb815Sopenharmony_ci      }
493425bb815Sopenharmony_ci
494425bb815Sopenharmony_ci      while (true)
495425bb815Sopenharmony_ci      {
496425bb815Sopenharmony_ci        if (token_p->type != TOKEN_STRING)
497425bb815Sopenharmony_ci        {
498425bb815Sopenharmony_ci          break;
499425bb815Sopenharmony_ci        }
500425bb815Sopenharmony_ci
501425bb815Sopenharmony_ci        ecma_string_t *name_p = token_p->u.string_p;
502425bb815Sopenharmony_ci
503425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, false);
504425bb815Sopenharmony_ci        if (token_p->type != TOKEN_COLON)
505425bb815Sopenharmony_ci        {
506425bb815Sopenharmony_ci          ecma_deref_ecma_string (name_p);
507425bb815Sopenharmony_ci          break;
508425bb815Sopenharmony_ci        }
509425bb815Sopenharmony_ci
510425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, true);
511425bb815Sopenharmony_ci        ecma_value_t value = ecma_builtin_json_parse_value (token_p);
512425bb815Sopenharmony_ci
513425bb815Sopenharmony_ci        if (ecma_is_value_empty (value))
514425bb815Sopenharmony_ci        {
515425bb815Sopenharmony_ci          ecma_deref_ecma_string (name_p);
516425bb815Sopenharmony_ci          break;
517425bb815Sopenharmony_ci        }
518425bb815Sopenharmony_ci
519425bb815Sopenharmony_ci        ecma_builtin_json_define_value_property (object_p, name_p, value);
520425bb815Sopenharmony_ci        ecma_deref_ecma_string (name_p);
521425bb815Sopenharmony_ci        ecma_free_value (value);
522425bb815Sopenharmony_ci
523425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, false);
524425bb815Sopenharmony_ci        if (token_p->type == TOKEN_RIGHT_BRACE)
525425bb815Sopenharmony_ci        {
526425bb815Sopenharmony_ci          return ecma_make_object_value (object_p);
527425bb815Sopenharmony_ci        }
528425bb815Sopenharmony_ci
529425bb815Sopenharmony_ci        if (token_p->type != TOKEN_COMMA)
530425bb815Sopenharmony_ci        {
531425bb815Sopenharmony_ci          break;
532425bb815Sopenharmony_ci        }
533425bb815Sopenharmony_ci
534425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, true);
535425bb815Sopenharmony_ci      }
536425bb815Sopenharmony_ci
537425bb815Sopenharmony_ci      /*
538425bb815Sopenharmony_ci       * Parse error occured.
539425bb815Sopenharmony_ci       */
540425bb815Sopenharmony_ci      ecma_deref_object (object_p);
541425bb815Sopenharmony_ci      return ECMA_VALUE_EMPTY;
542425bb815Sopenharmony_ci    }
543425bb815Sopenharmony_ci    case TOKEN_LEFT_SQUARE:
544425bb815Sopenharmony_ci    {
545425bb815Sopenharmony_ci      uint32_t length = 0;
546425bb815Sopenharmony_ci
547425bb815Sopenharmony_ci      ecma_value_t array_construction = ecma_op_create_array_object (NULL, 0, false);
548425bb815Sopenharmony_ci      JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_construction));
549425bb815Sopenharmony_ci
550425bb815Sopenharmony_ci      ecma_object_t *array_p = ecma_get_object_from_value (array_construction);
551425bb815Sopenharmony_ci
552425bb815Sopenharmony_ci      ecma_builtin_json_parse_next_token (token_p, true);
553425bb815Sopenharmony_ci
554425bb815Sopenharmony_ci      if (token_p->type == TOKEN_RIGHT_SQUARE)
555425bb815Sopenharmony_ci      {
556425bb815Sopenharmony_ci        return ecma_make_object_value (array_p);
557425bb815Sopenharmony_ci      }
558425bb815Sopenharmony_ci
559425bb815Sopenharmony_ci      while (true)
560425bb815Sopenharmony_ci      {
561425bb815Sopenharmony_ci        ecma_value_t value = ecma_builtin_json_parse_value (token_p);
562425bb815Sopenharmony_ci
563425bb815Sopenharmony_ci        if (ecma_is_value_empty (value))
564425bb815Sopenharmony_ci        {
565425bb815Sopenharmony_ci          JERRY_ASSERT (token_p->type != TOKEN_STRING);
566425bb815Sopenharmony_ci          break;
567425bb815Sopenharmony_ci        }
568425bb815Sopenharmony_ci
569425bb815Sopenharmony_ci        ecma_value_t completion;
570425bb815Sopenharmony_ci        completion = ecma_builtin_helper_def_prop_by_index (array_p,
571425bb815Sopenharmony_ci                                                            length,
572425bb815Sopenharmony_ci                                                            value,
573425bb815Sopenharmony_ci                                                            ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
574425bb815Sopenharmony_ci        JERRY_ASSERT (ecma_is_value_true (completion));
575425bb815Sopenharmony_ci        ecma_free_value (value);
576425bb815Sopenharmony_ci
577425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, false);
578425bb815Sopenharmony_ci
579425bb815Sopenharmony_ci        if (token_p->type == TOKEN_RIGHT_SQUARE)
580425bb815Sopenharmony_ci        {
581425bb815Sopenharmony_ci          return ecma_make_object_value (array_p);
582425bb815Sopenharmony_ci        }
583425bb815Sopenharmony_ci
584425bb815Sopenharmony_ci        if (token_p->type != TOKEN_COMMA)
585425bb815Sopenharmony_ci        {
586425bb815Sopenharmony_ci          JERRY_ASSERT (token_p->type != TOKEN_STRING);
587425bb815Sopenharmony_ci          break;
588425bb815Sopenharmony_ci        }
589425bb815Sopenharmony_ci
590425bb815Sopenharmony_ci        ecma_builtin_json_parse_next_token (token_p, true);
591425bb815Sopenharmony_ci        length++;
592425bb815Sopenharmony_ci      }
593425bb815Sopenharmony_ci
594425bb815Sopenharmony_ci      ecma_deref_object (array_p);
595425bb815Sopenharmony_ci      return ECMA_VALUE_EMPTY;
596425bb815Sopenharmony_ci    }
597425bb815Sopenharmony_ci    default:
598425bb815Sopenharmony_ci    {
599425bb815Sopenharmony_ci      return ECMA_VALUE_EMPTY;
600425bb815Sopenharmony_ci    }
601425bb815Sopenharmony_ci  }
602425bb815Sopenharmony_ci} /* ecma_builtin_json_parse_value */
603425bb815Sopenharmony_ci
604425bb815Sopenharmony_ci/**
605425bb815Sopenharmony_ci * Abstract operation InternalizeJSONProperty defined in 24.3.1.1
606425bb815Sopenharmony_ci *
607425bb815Sopenharmony_ci * @return ecma value
608425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
609425bb815Sopenharmony_ci */
610425bb815Sopenharmony_cistatic ecma_value_t
611425bb815Sopenharmony_ciecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver function */
612425bb815Sopenharmony_ci                                        ecma_object_t *holder_p, /**< holder object */
613425bb815Sopenharmony_ci                                        ecma_string_t *name_p) /**< property name */
614425bb815Sopenharmony_ci{
615425bb815Sopenharmony_ci  JERRY_ASSERT (reviver_p);
616425bb815Sopenharmony_ci  JERRY_ASSERT (holder_p);
617425bb815Sopenharmony_ci  JERRY_ASSERT (name_p);
618425bb815Sopenharmony_ci
619425bb815Sopenharmony_ci  /* 1. */
620425bb815Sopenharmony_ci  ecma_value_t value = ecma_op_object_get (holder_p, name_p);
621425bb815Sopenharmony_ci
622425bb815Sopenharmony_ci  /* 2. */
623425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (value))
624425bb815Sopenharmony_ci  {
625425bb815Sopenharmony_ci    return value;
626425bb815Sopenharmony_ci  }
627425bb815Sopenharmony_ci
628425bb815Sopenharmony_ci  /* 3. */
629425bb815Sopenharmony_ci  if (ecma_is_value_object (value))
630425bb815Sopenharmony_ci  {
631425bb815Sopenharmony_ci    ecma_object_t *object_p = ecma_get_object_from_value (value);
632425bb815Sopenharmony_ci
633425bb815Sopenharmony_ci    ecma_collection_t *props_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE);
634425bb815Sopenharmony_ci
635425bb815Sopenharmony_ci    ecma_value_t *buffer_p = props_p->buffer_p;
636425bb815Sopenharmony_ci
637425bb815Sopenharmony_ci    /* 3.d.iii */
638425bb815Sopenharmony_ci    for (uint32_t i = 0; i < props_p->item_count; i++)
639425bb815Sopenharmony_ci    {
640425bb815Sopenharmony_ci      ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]);
641425bb815Sopenharmony_ci
642425bb815Sopenharmony_ci      /* 3.d.iii.1 */
643425bb815Sopenharmony_ci      ecma_value_t result = ecma_builtin_json_internalize_property (reviver_p, object_p, property_name_p);
644425bb815Sopenharmony_ci
645425bb815Sopenharmony_ci      /* 3.d.iii.2 */
646425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (result))
647425bb815Sopenharmony_ci      {
648425bb815Sopenharmony_ci        ecma_collection_free (props_p);
649425bb815Sopenharmony_ci        ecma_deref_object (object_p);
650425bb815Sopenharmony_ci
651425bb815Sopenharmony_ci        return result;
652425bb815Sopenharmony_ci      }
653425bb815Sopenharmony_ci
654425bb815Sopenharmony_ci      /* 3.d.iii.3 */
655425bb815Sopenharmony_ci      if (ecma_is_value_undefined (result))
656425bb815Sopenharmony_ci      {
657425bb815Sopenharmony_ci        ecma_value_t delete_val = ecma_op_general_object_delete (object_p,
658425bb815Sopenharmony_ci                                                                 property_name_p,
659425bb815Sopenharmony_ci                                                                 false);
660425bb815Sopenharmony_ci        JERRY_ASSERT (ecma_is_value_boolean (delete_val));
661425bb815Sopenharmony_ci      }
662425bb815Sopenharmony_ci      /* 3.d.iii.4 */
663425bb815Sopenharmony_ci      else
664425bb815Sopenharmony_ci      {
665425bb815Sopenharmony_ci        ecma_builtin_json_define_value_property (object_p,
666425bb815Sopenharmony_ci                                                 property_name_p,
667425bb815Sopenharmony_ci                                                 result);
668425bb815Sopenharmony_ci        ecma_free_value (result);
669425bb815Sopenharmony_ci      }
670425bb815Sopenharmony_ci    }
671425bb815Sopenharmony_ci
672425bb815Sopenharmony_ci    ecma_collection_free (props_p);
673425bb815Sopenharmony_ci  }
674425bb815Sopenharmony_ci
675425bb815Sopenharmony_ci  ecma_value_t arguments_list[2];
676425bb815Sopenharmony_ci  arguments_list[0] = ecma_make_string_value (name_p);
677425bb815Sopenharmony_ci  arguments_list[1] = value;
678425bb815Sopenharmony_ci
679425bb815Sopenharmony_ci  /* 4. */
680425bb815Sopenharmony_ci  ecma_value_t ret_value =  ecma_op_function_call (reviver_p,
681425bb815Sopenharmony_ci                                                   ecma_make_object_value (holder_p),
682425bb815Sopenharmony_ci                                                   arguments_list,
683425bb815Sopenharmony_ci                                                   2);
684425bb815Sopenharmony_ci  ecma_free_value (value);
685425bb815Sopenharmony_ci  return ret_value;
686425bb815Sopenharmony_ci} /* ecma_builtin_json_internalize_property */
687425bb815Sopenharmony_ci
688425bb815Sopenharmony_ci/**
689425bb815Sopenharmony_ci * Function to set a string token from the given arguments, fills its fields and advances the string pointer.
690425bb815Sopenharmony_ci *
691425bb815Sopenharmony_ci * @return ecma_value_t containing an object or an error massage
692425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
693425bb815Sopenharmony_ci */
694425bb815Sopenharmony_ciecma_value_t
695425bb815Sopenharmony_ciecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p, /**< String to parse */
696425bb815Sopenharmony_ci                                lit_utf8_size_t string_size) /**< size of the string */
697425bb815Sopenharmony_ci{
698425bb815Sopenharmony_ci  ecma_json_token_t token;
699425bb815Sopenharmony_ci  token.current_p = str_start_p;
700425bb815Sopenharmony_ci  token.end_p = str_start_p + string_size;
701425bb815Sopenharmony_ci
702425bb815Sopenharmony_ci  ecma_builtin_json_parse_next_token (&token, true);
703425bb815Sopenharmony_ci  ecma_value_t result = ecma_builtin_json_parse_value (&token);
704425bb815Sopenharmony_ci
705425bb815Sopenharmony_ci  if (!ecma_is_value_empty (result))
706425bb815Sopenharmony_ci  {
707425bb815Sopenharmony_ci    ecma_builtin_json_parse_next_token (&token, false);
708425bb815Sopenharmony_ci    if (token.type == TOKEN_END)
709425bb815Sopenharmony_ci    {
710425bb815Sopenharmony_ci      return result;
711425bb815Sopenharmony_ci    }
712425bb815Sopenharmony_ci
713425bb815Sopenharmony_ci    ecma_free_value (result);
714425bb815Sopenharmony_ci  }
715425bb815Sopenharmony_ci
716425bb815Sopenharmony_ci  return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid JSON format."));
717425bb815Sopenharmony_ci} /*ecma_builtin_json_parse_buffer*/
718425bb815Sopenharmony_ci
719425bb815Sopenharmony_ci/**
720425bb815Sopenharmony_ci * The JSON object's 'parse' routine
721425bb815Sopenharmony_ci *
722425bb815Sopenharmony_ci * See also:
723425bb815Sopenharmony_ci *          ECMA-262 v5, 15.12.2
724425bb815Sopenharmony_ci *
725425bb815Sopenharmony_ci * @return ecma value
726425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
727425bb815Sopenharmony_ci */
728425bb815Sopenharmony_cistatic ecma_value_t
729425bb815Sopenharmony_ciecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */
730425bb815Sopenharmony_ci                         ecma_value_t arg1, /**< string argument */
731425bb815Sopenharmony_ci                         ecma_value_t arg2) /**< reviver argument */
732425bb815Sopenharmony_ci{
733425bb815Sopenharmony_ci  JERRY_UNUSED (this_arg);
734425bb815Sopenharmony_ci
735425bb815Sopenharmony_ci  ecma_string_t *text_string_p = ecma_op_to_string (arg1);
736425bb815Sopenharmony_ci
737425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (text_string_p == NULL))
738425bb815Sopenharmony_ci  {
739425bb815Sopenharmony_ci    return ECMA_VALUE_ERROR;
740425bb815Sopenharmony_ci  }
741425bb815Sopenharmony_ci
742425bb815Sopenharmony_ci  ECMA_STRING_TO_UTF8_STRING (text_string_p, str_start_p, string_size);
743425bb815Sopenharmony_ci  ecma_value_t result = ecma_builtin_json_parse_buffer (str_start_p, string_size);
744425bb815Sopenharmony_ci  ECMA_FINALIZE_UTF8_STRING (str_start_p, string_size);
745425bb815Sopenharmony_ci  ecma_deref_ecma_string (text_string_p);
746425bb815Sopenharmony_ci
747425bb815Sopenharmony_ci  if (!ECMA_IS_VALUE_ERROR (result) && ecma_op_is_callable (arg2))
748425bb815Sopenharmony_ci  {
749425bb815Sopenharmony_ci    ecma_object_t *object_p = ecma_op_create_object_object_noarg ();
750425bb815Sopenharmony_ci
751425bb815Sopenharmony_ci    ecma_property_value_t *prop_value_p;
752425bb815Sopenharmony_ci    prop_value_p = ecma_create_named_data_property (object_p,
753425bb815Sopenharmony_ci                                                    ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY),
754425bb815Sopenharmony_ci                                                    ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
755425bb815Sopenharmony_ci                                                    NULL);
756425bb815Sopenharmony_ci
757425bb815Sopenharmony_ci    ecma_named_data_property_assign_value (object_p, prop_value_p, result);
758425bb815Sopenharmony_ci
759425bb815Sopenharmony_ci    ecma_free_value (result);
760425bb815Sopenharmony_ci    result = ecma_builtin_json_internalize_property (ecma_get_object_from_value (arg2),
761425bb815Sopenharmony_ci                                                     object_p,
762425bb815Sopenharmony_ci                                                     ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY));
763425bb815Sopenharmony_ci    ecma_deref_object (object_p);
764425bb815Sopenharmony_ci  }
765425bb815Sopenharmony_ci
766425bb815Sopenharmony_ci  return result;
767425bb815Sopenharmony_ci} /* ecma_builtin_json_parse */
768425bb815Sopenharmony_ci
769425bb815Sopenharmony_ci/**
770425bb815Sopenharmony_ci * Abstract operation 'QuoteJSONString' defined in 24.3.2.2
771425bb815Sopenharmony_ci */
772425bb815Sopenharmony_cistatic void
773425bb815Sopenharmony_ciecma_builtin_json_quote (ecma_stringbuilder_t *builder_p, /**< builder for the result */
774425bb815Sopenharmony_ci                         ecma_string_t *string_p) /**< string that should be quoted */
775425bb815Sopenharmony_ci{
776425bb815Sopenharmony_ci  ECMA_STRING_TO_UTF8_STRING (string_p, string_buff, string_buff_size);
777425bb815Sopenharmony_ci  const lit_utf8_byte_t *str_p = string_buff;
778425bb815Sopenharmony_ci  const lit_utf8_byte_t *regular_str_start_p = string_buff;
779425bb815Sopenharmony_ci  const lit_utf8_byte_t *str_end_p = str_p + string_buff_size;
780425bb815Sopenharmony_ci
781425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_DOUBLE_QUOTE);
782425bb815Sopenharmony_ci
783425bb815Sopenharmony_ci  while (str_p < str_end_p)
784425bb815Sopenharmony_ci  {
785425bb815Sopenharmony_ci    lit_utf8_byte_t c = *str_p++;
786425bb815Sopenharmony_ci
787425bb815Sopenharmony_ci    if (c == LIT_CHAR_BACKSLASH || c == LIT_CHAR_DOUBLE_QUOTE)
788425bb815Sopenharmony_ci    {
789425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (builder_p,
790425bb815Sopenharmony_ci                                     regular_str_start_p,
791425bb815Sopenharmony_ci                                     (lit_utf8_size_t) (str_p - regular_str_start_p - 1));
792425bb815Sopenharmony_ci      regular_str_start_p = str_p;
793425bb815Sopenharmony_ci      ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_BACKSLASH);
794425bb815Sopenharmony_ci      ecma_stringbuilder_append_byte (builder_p, c);
795425bb815Sopenharmony_ci    }
796425bb815Sopenharmony_ci    else if (c < LIT_CHAR_SP)
797425bb815Sopenharmony_ci    {
798425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (builder_p,
799425bb815Sopenharmony_ci                                     regular_str_start_p,
800425bb815Sopenharmony_ci                                     (lit_utf8_size_t) (str_p - regular_str_start_p - 1));
801425bb815Sopenharmony_ci      regular_str_start_p = str_p;
802425bb815Sopenharmony_ci      ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_BACKSLASH);
803425bb815Sopenharmony_ci      switch (c)
804425bb815Sopenharmony_ci      {
805425bb815Sopenharmony_ci        case LIT_CHAR_BS:
806425bb815Sopenharmony_ci        {
807425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_B);
808425bb815Sopenharmony_ci          break;
809425bb815Sopenharmony_ci        }
810425bb815Sopenharmony_ci        case LIT_CHAR_FF:
811425bb815Sopenharmony_ci        {
812425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_F);
813425bb815Sopenharmony_ci          break;
814425bb815Sopenharmony_ci        }
815425bb815Sopenharmony_ci        case LIT_CHAR_LF:
816425bb815Sopenharmony_ci        {
817425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_N);
818425bb815Sopenharmony_ci          break;
819425bb815Sopenharmony_ci        }
820425bb815Sopenharmony_ci        case LIT_CHAR_CR:
821425bb815Sopenharmony_ci        {
822425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_R);
823425bb815Sopenharmony_ci          break;
824425bb815Sopenharmony_ci        }
825425bb815Sopenharmony_ci        case LIT_CHAR_TAB:
826425bb815Sopenharmony_ci        {
827425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_T);
828425bb815Sopenharmony_ci          break;
829425bb815Sopenharmony_ci        }
830425bb815Sopenharmony_ci        default: /* Hexadecimal. */
831425bb815Sopenharmony_ci        {
832425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_LOWERCASE_U);
833425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_0);
834425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_0);
835425bb815Sopenharmony_ci
836425bb815Sopenharmony_ci          /* Max range 0-9, hex digits unnecessary. */
837425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p, (lit_utf8_byte_t) (LIT_CHAR_0 + (c >> 4)));
838425bb815Sopenharmony_ci
839425bb815Sopenharmony_ci          lit_utf8_byte_t c2 = (c & 0xf);
840425bb815Sopenharmony_ci          ecma_stringbuilder_append_byte (builder_p,
841425bb815Sopenharmony_ci                                          (lit_utf8_byte_t) (c2 + ((c2 <= 9)
842425bb815Sopenharmony_ci                                                                   ? LIT_CHAR_0
843425bb815Sopenharmony_ci                                                                   : (LIT_CHAR_LOWERCASE_A - 10))));
844425bb815Sopenharmony_ci          break;
845425bb815Sopenharmony_ci        }
846425bb815Sopenharmony_ci      }
847425bb815Sopenharmony_ci    }
848425bb815Sopenharmony_ci  }
849425bb815Sopenharmony_ci
850425bb815Sopenharmony_ci  ecma_stringbuilder_append_raw (builder_p,
851425bb815Sopenharmony_ci                                 regular_str_start_p,
852425bb815Sopenharmony_ci                                 (lit_utf8_size_t) (str_end_p - regular_str_start_p));
853425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (builder_p, LIT_CHAR_DOUBLE_QUOTE);
854425bb815Sopenharmony_ci
855425bb815Sopenharmony_ci  ECMA_FINALIZE_UTF8_STRING (string_buff, string_buff_size);
856425bb815Sopenharmony_ci} /* ecma_builtin_json_quote */
857425bb815Sopenharmony_ci
858425bb815Sopenharmony_cistatic ecma_value_t
859425bb815Sopenharmony_ciecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p,
860425bb815Sopenharmony_ci                                      ecma_object_t *holder_p,
861425bb815Sopenharmony_ci                                      ecma_string_t *key_p);
862425bb815Sopenharmony_ci
863425bb815Sopenharmony_ci/**
864425bb815Sopenharmony_ci * Abstract operation 'SerializeJSONObject' defined in 24.3.2.3
865425bb815Sopenharmony_ci *
866425bb815Sopenharmony_ci * @return ecma value
867425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
868425bb815Sopenharmony_ci */
869425bb815Sopenharmony_cistatic ecma_value_t
870425bb815Sopenharmony_ciecma_builtin_json_serialize_object (ecma_json_stringify_context_t *context_p, /**< context*/
871425bb815Sopenharmony_ci                                    ecma_object_t *obj_p) /**< the object*/
872425bb815Sopenharmony_ci{
873425bb815Sopenharmony_ci  /* 1. */
874425bb815Sopenharmony_ci  if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p))
875425bb815Sopenharmony_ci  {
876425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical."));
877425bb815Sopenharmony_ci  }
878425bb815Sopenharmony_ci
879425bb815Sopenharmony_ci  /* 2. */
880425bb815Sopenharmony_ci  ecma_json_occurence_stack_item_t stack_item;
881425bb815Sopenharmony_ci  stack_item.next_p = context_p->occurence_stack_last_p;
882425bb815Sopenharmony_ci  stack_item.object_p = obj_p;
883425bb815Sopenharmony_ci  context_p->occurence_stack_last_p = &stack_item;
884425bb815Sopenharmony_ci
885425bb815Sopenharmony_ci  /* 3. - 4.*/
886425bb815Sopenharmony_ci  const lit_utf8_size_t stepback_size = ecma_stringbuilder_get_size (&context_p->indent_builder);
887425bb815Sopenharmony_ci  ecma_stringbuilder_append (&context_p->indent_builder, context_p->gap_str_p);
888425bb815Sopenharmony_ci
889425bb815Sopenharmony_ci  const bool has_gap = !ecma_compare_ecma_string_to_magic_id (context_p->gap_str_p, LIT_MAGIC_STRING__EMPTY);
890425bb815Sopenharmony_ci  const lit_utf8_size_t separator_size = ecma_stringbuilder_get_size (&context_p->indent_builder);
891425bb815Sopenharmony_ci
892425bb815Sopenharmony_ci  ecma_collection_t *property_keys_p;
893425bb815Sopenharmony_ci  /* 5. */
894425bb815Sopenharmony_ci  if (context_p->property_list_p->item_count > 0)
895425bb815Sopenharmony_ci  {
896425bb815Sopenharmony_ci    property_keys_p = context_p->property_list_p;
897425bb815Sopenharmony_ci  }
898425bb815Sopenharmony_ci  /* 6. */
899425bb815Sopenharmony_ci  else
900425bb815Sopenharmony_ci  {
901425bb815Sopenharmony_ci    property_keys_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE);
902425bb815Sopenharmony_ci
903425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
904425bb815Sopenharmony_ci    if (property_keys_p == NULL)
905425bb815Sopenharmony_ci    {
906425bb815Sopenharmony_ci      return ECMA_VALUE_ERROR;
907425bb815Sopenharmony_ci    }
908425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
909425bb815Sopenharmony_ci  }
910425bb815Sopenharmony_ci
911425bb815Sopenharmony_ci  /* 8. */
912425bb815Sopenharmony_ci  ecma_value_t *buffer_p = property_keys_p->buffer_p;
913425bb815Sopenharmony_ci
914425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_LEFT_BRACE);
915425bb815Sopenharmony_ci  const lit_utf8_size_t left_brace = ecma_stringbuilder_get_size (&context_p->result_builder);
916425bb815Sopenharmony_ci  lit_utf8_size_t last_prop = left_brace;
917425bb815Sopenharmony_ci  ecma_value_t result = ECMA_VALUE_EMPTY;
918425bb815Sopenharmony_ci
919425bb815Sopenharmony_ci  for (uint32_t i = 0; i < property_keys_p->item_count; i++)
920425bb815Sopenharmony_ci  {
921425bb815Sopenharmony_ci    if (has_gap)
922425bb815Sopenharmony_ci    {
923425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (&context_p->result_builder,
924425bb815Sopenharmony_ci                                     ecma_stringbuilder_get_data (&context_p->indent_builder),
925425bb815Sopenharmony_ci                                     separator_size);
926425bb815Sopenharmony_ci    }
927425bb815Sopenharmony_ci
928425bb815Sopenharmony_ci    ecma_string_t *key_p = ecma_get_string_from_value (buffer_p[i]);
929425bb815Sopenharmony_ci    ecma_builtin_json_quote (&context_p->result_builder, key_p);
930425bb815Sopenharmony_ci    ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_COLON);
931425bb815Sopenharmony_ci
932425bb815Sopenharmony_ci    /* 8.c.iii */
933425bb815Sopenharmony_ci    if (has_gap)
934425bb815Sopenharmony_ci    {
935425bb815Sopenharmony_ci      ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_SP);
936425bb815Sopenharmony_ci    }
937425bb815Sopenharmony_ci
938425bb815Sopenharmony_ci    result = ecma_builtin_json_serialize_property (context_p, obj_p, key_p);
939425bb815Sopenharmony_ci
940425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
941425bb815Sopenharmony_ci    {
942425bb815Sopenharmony_ci      goto cleanup;
943425bb815Sopenharmony_ci    }
944425bb815Sopenharmony_ci
945425bb815Sopenharmony_ci    /* 8.b */
946425bb815Sopenharmony_ci    if (!ecma_is_value_undefined (result))
947425bb815Sopenharmony_ci    {
948425bb815Sopenharmony_ci      /* ecma_builtin_json_serialize_property already appended the result. */
949425bb815Sopenharmony_ci      JERRY_ASSERT (ecma_is_value_empty (result));
950425bb815Sopenharmony_ci
951425bb815Sopenharmony_ci      ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_COMMA);
952425bb815Sopenharmony_ci      last_prop = ecma_stringbuilder_get_size (&context_p->result_builder);
953425bb815Sopenharmony_ci    }
954425bb815Sopenharmony_ci    else
955425bb815Sopenharmony_ci    {
956425bb815Sopenharmony_ci      /* The property should not be appended, we must backtrack. */
957425bb815Sopenharmony_ci      ecma_stringbuilder_revert (&context_p->result_builder, last_prop);
958425bb815Sopenharmony_ci    }
959425bb815Sopenharmony_ci  }
960425bb815Sopenharmony_ci
961425bb815Sopenharmony_ci  if (last_prop != left_brace)
962425bb815Sopenharmony_ci  {
963425bb815Sopenharmony_ci    /* Remove the last comma. */
964425bb815Sopenharmony_ci    ecma_stringbuilder_revert (&context_p->result_builder, last_prop - 1);
965425bb815Sopenharmony_ci
966425bb815Sopenharmony_ci    if (has_gap)
967425bb815Sopenharmony_ci    {
968425bb815Sopenharmony_ci      /* We appended at least one element, and have a separator, so must append the stepback. */
969425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (&context_p->result_builder,
970425bb815Sopenharmony_ci                                     ecma_stringbuilder_get_data (&context_p->indent_builder),
971425bb815Sopenharmony_ci                                     stepback_size);
972425bb815Sopenharmony_ci    }
973425bb815Sopenharmony_ci  }
974425bb815Sopenharmony_ci
975425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_RIGHT_BRACE);
976425bb815Sopenharmony_ci  result = ECMA_VALUE_EMPTY;
977425bb815Sopenharmony_ci
978425bb815Sopenharmony_ci  /* 11. */
979425bb815Sopenharmony_ci  context_p->occurence_stack_last_p = stack_item.next_p;
980425bb815Sopenharmony_ci
981425bb815Sopenharmony_ci  /* 12. */
982425bb815Sopenharmony_ci  ecma_stringbuilder_revert (&context_p->indent_builder, stepback_size);
983425bb815Sopenharmony_ci
984425bb815Sopenharmony_cicleanup:
985425bb815Sopenharmony_ci  if (context_p->property_list_p->item_count == 0)
986425bb815Sopenharmony_ci  {
987425bb815Sopenharmony_ci    ecma_collection_free (property_keys_p);
988425bb815Sopenharmony_ci  }
989425bb815Sopenharmony_ci
990425bb815Sopenharmony_ci  return result;
991425bb815Sopenharmony_ci} /* ecma_builtin_json_serialize_object */
992425bb815Sopenharmony_ci
993425bb815Sopenharmony_ci/**
994425bb815Sopenharmony_ci * Abstract operation 'SerializeJSONArray' defined in 24.3.2.4
995425bb815Sopenharmony_ci *
996425bb815Sopenharmony_ci * @return ecma value
997425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
998425bb815Sopenharmony_ci */
999425bb815Sopenharmony_cistatic ecma_value_t
1000425bb815Sopenharmony_ciecma_builtin_json_serialize_array (ecma_json_stringify_context_t *context_p, /**< context*/
1001425bb815Sopenharmony_ci                                   ecma_object_t *obj_p) /**< the array object*/
1002425bb815Sopenharmony_ci{
1003425bb815Sopenharmony_ci#ifndef JERRY_NDEBUG
1004425bb815Sopenharmony_ci  ecma_value_t obj_value = ecma_make_object_value (obj_p);
1005425bb815Sopenharmony_ci  ecma_value_t is_array = ecma_is_value_array (obj_value);
1006425bb815Sopenharmony_ci
1007425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_true (is_array));
1008425bb815Sopenharmony_ci#endif /* !JERRY_NDEBUG */
1009425bb815Sopenharmony_ci
1010425bb815Sopenharmony_ci  /* 1. */
1011425bb815Sopenharmony_ci  if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p))
1012425bb815Sopenharmony_ci  {
1013425bb815Sopenharmony_ci    return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical."));
1014425bb815Sopenharmony_ci  }
1015425bb815Sopenharmony_ci
1016425bb815Sopenharmony_ci  /* 2. */
1017425bb815Sopenharmony_ci  ecma_json_occurence_stack_item_t stack_item;
1018425bb815Sopenharmony_ci  stack_item.next_p = context_p->occurence_stack_last_p;
1019425bb815Sopenharmony_ci  stack_item.object_p = obj_p;
1020425bb815Sopenharmony_ci  context_p->occurence_stack_last_p = &stack_item;
1021425bb815Sopenharmony_ci
1022425bb815Sopenharmony_ci  /* 3. - 4.*/
1023425bb815Sopenharmony_ci  const lit_utf8_size_t stepback_size = ecma_stringbuilder_get_size (&context_p->indent_builder);
1024425bb815Sopenharmony_ci  ecma_stringbuilder_append (&context_p->indent_builder, context_p->gap_str_p);
1025425bb815Sopenharmony_ci  const lit_utf8_size_t separator_size = ecma_stringbuilder_get_size (&context_p->indent_builder);
1026425bb815Sopenharmony_ci
1027425bb815Sopenharmony_ci  const bool has_gap = !ecma_compare_ecma_string_to_magic_id (context_p->gap_str_p, LIT_MAGIC_STRING__EMPTY);
1028425bb815Sopenharmony_ci
1029425bb815Sopenharmony_ci  /* 6. */
1030425bb815Sopenharmony_ci  uint32_t array_length;
1031425bb815Sopenharmony_ci
1032425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
1033425bb815Sopenharmony_ci  if (ECMA_OBJECT_IS_PROXY (obj_p))
1034425bb815Sopenharmony_ci  {
1035425bb815Sopenharmony_ci    ecma_value_t length_value = ecma_op_object_get_length (obj_p, &array_length);
1036425bb815Sopenharmony_ci
1037425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (length_value))
1038425bb815Sopenharmony_ci    {
1039425bb815Sopenharmony_ci      return length_value;
1040425bb815Sopenharmony_ci    }
1041425bb815Sopenharmony_ci  }
1042425bb815Sopenharmony_ci  else
1043425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
1044425bb815Sopenharmony_ci  {
1045425bb815Sopenharmony_ci    array_length = ((ecma_extended_object_t *) obj_p)->u.array.length;
1046425bb815Sopenharmony_ci  }
1047425bb815Sopenharmony_ci
1048425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_LEFT_SQUARE);
1049425bb815Sopenharmony_ci
1050425bb815Sopenharmony_ci  const lit_utf8_size_t left_square = ecma_stringbuilder_get_size (&context_p->result_builder);
1051425bb815Sopenharmony_ci  lit_utf8_size_t last_prop = left_square;
1052425bb815Sopenharmony_ci
1053425bb815Sopenharmony_ci  /* 8. - 9. */
1054425bb815Sopenharmony_ci  for (uint32_t index = 0; index < array_length; index++)
1055425bb815Sopenharmony_ci  {
1056425bb815Sopenharmony_ci    /* 9.a */
1057425bb815Sopenharmony_ci    ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
1058425bb815Sopenharmony_ci
1059425bb815Sopenharmony_ci    if (has_gap)
1060425bb815Sopenharmony_ci    {
1061425bb815Sopenharmony_ci      ecma_stringbuilder_append_raw (&context_p->result_builder,
1062425bb815Sopenharmony_ci                                     ecma_stringbuilder_get_data (&context_p->indent_builder),
1063425bb815Sopenharmony_ci                                     separator_size);
1064425bb815Sopenharmony_ci    }
1065425bb815Sopenharmony_ci
1066425bb815Sopenharmony_ci    ecma_value_t result = ecma_builtin_json_serialize_property (context_p, obj_p, index_str_p);
1067425bb815Sopenharmony_ci    ecma_deref_ecma_string (index_str_p);
1068425bb815Sopenharmony_ci
1069425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
1070425bb815Sopenharmony_ci    {
1071425bb815Sopenharmony_ci      return result;
1072425bb815Sopenharmony_ci    }
1073425bb815Sopenharmony_ci
1074425bb815Sopenharmony_ci    if (ecma_is_value_undefined (result))
1075425bb815Sopenharmony_ci    {
1076425bb815Sopenharmony_ci      /* 9.c */
1077425bb815Sopenharmony_ci      ecma_stringbuilder_append_magic (&context_p->result_builder, LIT_MAGIC_STRING_NULL);
1078425bb815Sopenharmony_ci    }
1079425bb815Sopenharmony_ci    else
1080425bb815Sopenharmony_ci    {
1081425bb815Sopenharmony_ci      JERRY_ASSERT (ecma_is_value_empty (result));
1082425bb815Sopenharmony_ci    }
1083425bb815Sopenharmony_ci
1084425bb815Sopenharmony_ci    last_prop = ecma_stringbuilder_get_size (&context_p->result_builder);
1085425bb815Sopenharmony_ci    ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_COMMA);
1086425bb815Sopenharmony_ci  }
1087425bb815Sopenharmony_ci
1088425bb815Sopenharmony_ci  /* Remove the last comma. */
1089425bb815Sopenharmony_ci  ecma_stringbuilder_revert (&context_p->result_builder, last_prop);
1090425bb815Sopenharmony_ci
1091425bb815Sopenharmony_ci  /* 11.b.iii */
1092425bb815Sopenharmony_ci  if (last_prop != left_square && has_gap)
1093425bb815Sopenharmony_ci  {
1094425bb815Sopenharmony_ci    /* We appended at least one element, and have a separator, so must append the stepback. */
1095425bb815Sopenharmony_ci    ecma_stringbuilder_append_raw (&context_p->result_builder,
1096425bb815Sopenharmony_ci                                   ecma_stringbuilder_get_data (&context_p->indent_builder),
1097425bb815Sopenharmony_ci                                   stepback_size);
1098425bb815Sopenharmony_ci  }
1099425bb815Sopenharmony_ci
1100425bb815Sopenharmony_ci  ecma_stringbuilder_append_byte (&context_p->result_builder, LIT_CHAR_RIGHT_SQUARE);
1101425bb815Sopenharmony_ci
1102425bb815Sopenharmony_ci  /* 12. */
1103425bb815Sopenharmony_ci  context_p->occurence_stack_last_p = stack_item.next_p;
1104425bb815Sopenharmony_ci
1105425bb815Sopenharmony_ci  /* 13. */
1106425bb815Sopenharmony_ci  ecma_stringbuilder_revert (&context_p->indent_builder, stepback_size);
1107425bb815Sopenharmony_ci
1108425bb815Sopenharmony_ci  return ECMA_VALUE_EMPTY;
1109425bb815Sopenharmony_ci} /* ecma_builtin_json_serialize_array */
1110425bb815Sopenharmony_ci
1111425bb815Sopenharmony_ci/**
1112425bb815Sopenharmony_ci * Abstract operation 'SerializeJSONProperty' defined in 24.3.2.1
1113425bb815Sopenharmony_ci *
1114425bb815Sopenharmony_ci * @return ecma value
1115425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
1116425bb815Sopenharmony_ci */
1117425bb815Sopenharmony_cistatic ecma_value_t
1118425bb815Sopenharmony_ciecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p, /**< context*/
1119425bb815Sopenharmony_ci                                      ecma_object_t *holder_p, /**< the object*/
1120425bb815Sopenharmony_ci                                      ecma_string_t *key_p) /**< property key*/
1121425bb815Sopenharmony_ci{
1122425bb815Sopenharmony_ci  /* 1. */
1123425bb815Sopenharmony_ci  ecma_value_t value = ecma_op_object_get (holder_p, key_p);
1124425bb815Sopenharmony_ci
1125425bb815Sopenharmony_ci  /* 2. */
1126425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (value))
1127425bb815Sopenharmony_ci  {
1128425bb815Sopenharmony_ci    return value;
1129425bb815Sopenharmony_ci  }
1130425bb815Sopenharmony_ci
1131425bb815Sopenharmony_ci  /* 3. */
1132425bb815Sopenharmony_ci  if (ecma_is_value_object (value))
1133425bb815Sopenharmony_ci  {
1134425bb815Sopenharmony_ci    ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
1135425bb815Sopenharmony_ci
1136425bb815Sopenharmony_ci    ecma_value_t to_json = ecma_op_object_get_by_magic_id (value_obj_p, LIT_MAGIC_STRING_TO_JSON_UL);
1137425bb815Sopenharmony_ci
1138425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (to_json))
1139425bb815Sopenharmony_ci    {
1140425bb815Sopenharmony_ci      ecma_deref_object (value_obj_p);
1141425bb815Sopenharmony_ci      return to_json;
1142425bb815Sopenharmony_ci    }
1143425bb815Sopenharmony_ci
1144425bb815Sopenharmony_ci    /* 3.c */
1145425bb815Sopenharmony_ci    if (ecma_op_is_callable (to_json))
1146425bb815Sopenharmony_ci    {
1147425bb815Sopenharmony_ci      ecma_value_t key_value = ecma_make_string_value (key_p);
1148425bb815Sopenharmony_ci      ecma_value_t call_args[] = { key_value };
1149425bb815Sopenharmony_ci      ecma_object_t *to_json_obj_p = ecma_get_object_from_value (to_json);
1150425bb815Sopenharmony_ci
1151425bb815Sopenharmony_ci      ecma_value_t result = ecma_op_function_call (to_json_obj_p, value, call_args, 1);
1152425bb815Sopenharmony_ci      ecma_deref_object (value_obj_p);
1153425bb815Sopenharmony_ci
1154425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (result))
1155425bb815Sopenharmony_ci      {
1156425bb815Sopenharmony_ci        ecma_deref_object (to_json_obj_p);
1157425bb815Sopenharmony_ci        return result;
1158425bb815Sopenharmony_ci      }
1159425bb815Sopenharmony_ci
1160425bb815Sopenharmony_ci      value = result;
1161425bb815Sopenharmony_ci    }
1162425bb815Sopenharmony_ci    ecma_free_value (to_json);
1163425bb815Sopenharmony_ci  }
1164425bb815Sopenharmony_ci
1165425bb815Sopenharmony_ci  /* 4. */
1166425bb815Sopenharmony_ci  if (context_p->replacer_function_p)
1167425bb815Sopenharmony_ci  {
1168425bb815Sopenharmony_ci    ecma_value_t holder_value = ecma_make_object_value (holder_p);
1169425bb815Sopenharmony_ci    ecma_value_t key_value = ecma_make_string_value (key_p);
1170425bb815Sopenharmony_ci    ecma_value_t call_args[] = { key_value, value };
1171425bb815Sopenharmony_ci
1172425bb815Sopenharmony_ci    ecma_value_t result = ecma_op_function_call (context_p->replacer_function_p, holder_value, call_args, 2);
1173425bb815Sopenharmony_ci    ecma_free_value (value);
1174425bb815Sopenharmony_ci
1175425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (result))
1176425bb815Sopenharmony_ci    {
1177425bb815Sopenharmony_ci      return result;
1178425bb815Sopenharmony_ci    }
1179425bb815Sopenharmony_ci
1180425bb815Sopenharmony_ci    value = result;
1181425bb815Sopenharmony_ci  }
1182425bb815Sopenharmony_ci
1183425bb815Sopenharmony_ci  /* 5. */
1184425bb815Sopenharmony_ci  if (ecma_is_value_object (value))
1185425bb815Sopenharmony_ci  {
1186425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (value);
1187425bb815Sopenharmony_ci    lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);
1188425bb815Sopenharmony_ci
1189425bb815Sopenharmony_ci    /* 5.a */
1190425bb815Sopenharmony_ci    if (class_name == LIT_MAGIC_STRING_NUMBER_UL)
1191425bb815Sopenharmony_ci    {
1192425bb815Sopenharmony_ci      value = ecma_op_to_number (value);
1193425bb815Sopenharmony_ci      ecma_deref_object (obj_p);
1194425bb815Sopenharmony_ci
1195425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (value))
1196425bb815Sopenharmony_ci      {
1197425bb815Sopenharmony_ci        return value;
1198425bb815Sopenharmony_ci      }
1199425bb815Sopenharmony_ci    }
1200425bb815Sopenharmony_ci    /* 5.b */
1201425bb815Sopenharmony_ci    else if (class_name == LIT_MAGIC_STRING_STRING_UL)
1202425bb815Sopenharmony_ci    {
1203425bb815Sopenharmony_ci      ecma_string_t *str_p = ecma_op_to_string (value);
1204425bb815Sopenharmony_ci      ecma_deref_object (obj_p);
1205425bb815Sopenharmony_ci
1206425bb815Sopenharmony_ci      if (JERRY_UNLIKELY (str_p == NULL))
1207425bb815Sopenharmony_ci      {
1208425bb815Sopenharmony_ci        return ECMA_VALUE_ERROR;
1209425bb815Sopenharmony_ci      }
1210425bb815Sopenharmony_ci
1211425bb815Sopenharmony_ci      value = ecma_make_string_value (str_p);
1212425bb815Sopenharmony_ci    }
1213425bb815Sopenharmony_ci    /* 5.c */
1214425bb815Sopenharmony_ci    else if (class_name == LIT_MAGIC_STRING_BOOLEAN_UL)
1215425bb815Sopenharmony_ci    {
1216425bb815Sopenharmony_ci      ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
1217425bb815Sopenharmony_ci      value = ext_object_p->u.class_prop.u.value;
1218425bb815Sopenharmony_ci      ecma_deref_object (obj_p);
1219425bb815Sopenharmony_ci    }
1220425bb815Sopenharmony_ci  }
1221425bb815Sopenharmony_ci
1222425bb815Sopenharmony_ci  /* 6. - 8. */
1223425bb815Sopenharmony_ci  if (ecma_is_value_null (value))
1224425bb815Sopenharmony_ci  {
1225425bb815Sopenharmony_ci    ecma_stringbuilder_append_magic (&context_p->result_builder, LIT_MAGIC_STRING_NULL);
1226425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
1227425bb815Sopenharmony_ci  }
1228425bb815Sopenharmony_ci
1229425bb815Sopenharmony_ci  if (ecma_is_value_true (value))
1230425bb815Sopenharmony_ci  {
1231425bb815Sopenharmony_ci    ecma_stringbuilder_append_magic (&context_p->result_builder, LIT_MAGIC_STRING_TRUE);
1232425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
1233425bb815Sopenharmony_ci  }
1234425bb815Sopenharmony_ci
1235425bb815Sopenharmony_ci  if (ecma_is_value_false (value))
1236425bb815Sopenharmony_ci  {
1237425bb815Sopenharmony_ci    ecma_stringbuilder_append_magic (&context_p->result_builder, LIT_MAGIC_STRING_FALSE);
1238425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
1239425bb815Sopenharmony_ci  }
1240425bb815Sopenharmony_ci
1241425bb815Sopenharmony_ci  /* 9. */
1242425bb815Sopenharmony_ci  if (ecma_is_value_string (value))
1243425bb815Sopenharmony_ci  {
1244425bb815Sopenharmony_ci    ecma_string_t *value_str_p = ecma_get_string_from_value (value);
1245425bb815Sopenharmony_ci    /* Quote will append the result. */
1246425bb815Sopenharmony_ci    ecma_builtin_json_quote (&context_p->result_builder, value_str_p);
1247425bb815Sopenharmony_ci    ecma_deref_ecma_string (value_str_p);
1248425bb815Sopenharmony_ci
1249425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
1250425bb815Sopenharmony_ci  }
1251425bb815Sopenharmony_ci
1252425bb815Sopenharmony_ci  /* 10. */
1253425bb815Sopenharmony_ci  if (ecma_is_value_number (value))
1254425bb815Sopenharmony_ci  {
1255425bb815Sopenharmony_ci    ecma_number_t num_value = ecma_get_number_from_value (value);
1256425bb815Sopenharmony_ci
1257425bb815Sopenharmony_ci    /* 10.a */
1258425bb815Sopenharmony_ci    if (!ecma_number_is_nan (num_value) && !ecma_number_is_infinity (num_value))
1259425bb815Sopenharmony_ci    {
1260425bb815Sopenharmony_ci      ecma_string_t *result_string_p = ecma_op_to_string (value);
1261425bb815Sopenharmony_ci      JERRY_ASSERT (result_string_p != NULL);
1262425bb815Sopenharmony_ci
1263425bb815Sopenharmony_ci      ecma_stringbuilder_append (&context_p->result_builder, result_string_p);
1264425bb815Sopenharmony_ci      ecma_deref_ecma_string (result_string_p);
1265425bb815Sopenharmony_ci    }
1266425bb815Sopenharmony_ci    else
1267425bb815Sopenharmony_ci    {
1268425bb815Sopenharmony_ci      /* 10.b */
1269425bb815Sopenharmony_ci      ecma_stringbuilder_append_magic (&context_p->result_builder, LIT_MAGIC_STRING_NULL);
1270425bb815Sopenharmony_ci    }
1271425bb815Sopenharmony_ci
1272425bb815Sopenharmony_ci    ecma_free_value (value);
1273425bb815Sopenharmony_ci    return ECMA_VALUE_EMPTY;
1274425bb815Sopenharmony_ci  }
1275425bb815Sopenharmony_ci
1276425bb815Sopenharmony_ci  /* 11. */
1277425bb815Sopenharmony_ci  if (ecma_is_value_object (value) && !ecma_op_is_callable (value))
1278425bb815Sopenharmony_ci  {
1279425bb815Sopenharmony_ci    ecma_value_t is_array = ecma_is_value_array (value);
1280425bb815Sopenharmony_ci
1281425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
1282425bb815Sopenharmony_ci    if (ECMA_IS_VALUE_ERROR (is_array))
1283425bb815Sopenharmony_ci    {
1284425bb815Sopenharmony_ci      ecma_free_value (value);
1285425bb815Sopenharmony_ci      return is_array;
1286425bb815Sopenharmony_ci    }
1287425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
1288425bb815Sopenharmony_ci
1289425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (value);
1290425bb815Sopenharmony_ci
1291425bb815Sopenharmony_ci    ecma_value_t ret_value;
1292425bb815Sopenharmony_ci    /* 10.a */
1293425bb815Sopenharmony_ci    if (ecma_is_value_true (is_array))
1294425bb815Sopenharmony_ci    {
1295425bb815Sopenharmony_ci      ret_value = ecma_builtin_json_serialize_array (context_p, obj_p);
1296425bb815Sopenharmony_ci    }
1297425bb815Sopenharmony_ci    /* 10.b */
1298425bb815Sopenharmony_ci    else
1299425bb815Sopenharmony_ci    {
1300425bb815Sopenharmony_ci      ret_value = ecma_builtin_json_serialize_object (context_p, obj_p);
1301425bb815Sopenharmony_ci    }
1302425bb815Sopenharmony_ci
1303425bb815Sopenharmony_ci    ecma_deref_object (obj_p);
1304425bb815Sopenharmony_ci    return ret_value;
1305425bb815Sopenharmony_ci  }
1306425bb815Sopenharmony_ci
1307425bb815Sopenharmony_ci  /* 12. */
1308425bb815Sopenharmony_ci  ecma_free_value (value);
1309425bb815Sopenharmony_ci  return ECMA_VALUE_UNDEFINED;
1310425bb815Sopenharmony_ci} /* ecma_builtin_json_serialize_property */
1311425bb815Sopenharmony_ci
1312425bb815Sopenharmony_ci/**
1313425bb815Sopenharmony_ci * Helper function to stringify an object in JSON format representing an ecma_value.
1314425bb815Sopenharmony_ci *
1315425bb815Sopenharmony_ci *  @return ecma_value_t string created from an abject formating by a given context
1316425bb815Sopenharmony_ci *          Returned value must be freed with ecma_free_value.
1317425bb815Sopenharmony_ci *
1318425bb815Sopenharmony_ci */
1319425bb815Sopenharmony_cistatic ecma_value_t ecma_builtin_json_str_helper (ecma_json_stringify_context_t *context_p, /**< context argument */
1320425bb815Sopenharmony_ci                                                  const ecma_value_t arg1) /**< object argument */
1321425bb815Sopenharmony_ci{
1322425bb815Sopenharmony_ci  ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1323425bb815Sopenharmony_ci  ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
1324425bb815Sopenharmony_ci  ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
1325425bb815Sopenharmony_ci  ecma_value_t put_comp_val = ecma_builtin_helper_def_prop (obj_wrapper_p,
1326425bb815Sopenharmony_ci                                                            empty_str_p,
1327425bb815Sopenharmony_ci                                                            arg1,
1328425bb815Sopenharmony_ci                                                            ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
1329425bb815Sopenharmony_ci
1330425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_true (put_comp_val));
1331425bb815Sopenharmony_ci
1332425bb815Sopenharmony_ci  context_p->result_builder = ecma_stringbuilder_create ();
1333425bb815Sopenharmony_ci
1334425bb815Sopenharmony_ci  if (!ecma_compare_ecma_string_to_magic_id (context_p->gap_str_p, LIT_MAGIC_STRING__EMPTY))
1335425bb815Sopenharmony_ci  {
1336425bb815Sopenharmony_ci    ecma_stringbuilder_append_byte (&context_p->indent_builder, LIT_CHAR_LF);
1337425bb815Sopenharmony_ci  }
1338425bb815Sopenharmony_ci
1339425bb815Sopenharmony_ci  ret_value = ecma_builtin_json_serialize_property (context_p, obj_wrapper_p, empty_str_p);
1340425bb815Sopenharmony_ci  ecma_deref_object (obj_wrapper_p);
1341425bb815Sopenharmony_ci
1342425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_undefined (ret_value))
1343425bb815Sopenharmony_ci  {
1344425bb815Sopenharmony_ci    ecma_stringbuilder_destroy (&context_p->result_builder);
1345425bb815Sopenharmony_ci    return ret_value;
1346425bb815Sopenharmony_ci  }
1347425bb815Sopenharmony_ci
1348425bb815Sopenharmony_ci  return ecma_make_string_value (ecma_stringbuilder_finalize (&context_p->result_builder));
1349425bb815Sopenharmony_ci} /* ecma_builtin_json_str_helper */
1350425bb815Sopenharmony_ci
1351425bb815Sopenharmony_ci/**
1352425bb815Sopenharmony_ci * Function to create a json formated string from an object
1353425bb815Sopenharmony_ci *
1354425bb815Sopenharmony_ci * @return ecma_value_t containing a json string
1355425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
1356425bb815Sopenharmony_ci */
1357425bb815Sopenharmony_ciecma_value_t
1358425bb815Sopenharmony_ciecma_builtin_json_string_from_object (const ecma_value_t arg1) /**< object argument */
1359425bb815Sopenharmony_ci{
1360425bb815Sopenharmony_ci  ecma_json_stringify_context_t context;
1361425bb815Sopenharmony_ci  context.occurence_stack_last_p = NULL;
1362425bb815Sopenharmony_ci  context.indent_builder = ecma_stringbuilder_create ();
1363425bb815Sopenharmony_ci  context.property_list_p = ecma_new_collection ();
1364425bb815Sopenharmony_ci  context.replacer_function_p = NULL;
1365425bb815Sopenharmony_ci  context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
1366425bb815Sopenharmony_ci
1367425bb815Sopenharmony_ci  ecma_value_t ret_value = ecma_builtin_json_str_helper (&context, arg1);
1368425bb815Sopenharmony_ci
1369425bb815Sopenharmony_ci  ecma_deref_ecma_string (context.gap_str_p);
1370425bb815Sopenharmony_ci  ecma_stringbuilder_destroy (&context.indent_builder);
1371425bb815Sopenharmony_ci  ecma_collection_free (context.property_list_p);
1372425bb815Sopenharmony_ci  return ret_value;
1373425bb815Sopenharmony_ci} /*ecma_builtin_json_string_from_object*/
1374425bb815Sopenharmony_ci
1375425bb815Sopenharmony_ci/**
1376425bb815Sopenharmony_ci * The JSON object's 'stringify' routine
1377425bb815Sopenharmony_ci *
1378425bb815Sopenharmony_ci * See also:
1379425bb815Sopenharmony_ci *          ECMA-262 v5, 15.12.3
1380425bb815Sopenharmony_ci *
1381425bb815Sopenharmony_ci * @return ecma value
1382425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
1383425bb815Sopenharmony_ci */
1384425bb815Sopenharmony_cistatic ecma_value_t
1385425bb815Sopenharmony_ciecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */
1386425bb815Sopenharmony_ci                             ecma_value_t arg1,  /**< value */
1387425bb815Sopenharmony_ci                             ecma_value_t arg2,  /**< replacer */
1388425bb815Sopenharmony_ci                             ecma_value_t arg3)  /**< space */
1389425bb815Sopenharmony_ci{
1390425bb815Sopenharmony_ci  JERRY_UNUSED (this_arg);
1391425bb815Sopenharmony_ci
1392425bb815Sopenharmony_ci  ecma_json_stringify_context_t context;
1393425bb815Sopenharmony_ci  context.replacer_function_p = NULL;
1394425bb815Sopenharmony_ci  context.property_list_p = ecma_new_collection ();
1395425bb815Sopenharmony_ci
1396425bb815Sopenharmony_ci  /* 4. */
1397425bb815Sopenharmony_ci  if (ecma_is_value_object (arg2))
1398425bb815Sopenharmony_ci  {
1399425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (arg2);
1400425bb815Sopenharmony_ci
1401425bb815Sopenharmony_ci    /* 4.a */
1402425bb815Sopenharmony_ci    if (ecma_op_is_callable (arg2))
1403425bb815Sopenharmony_ci    {
1404425bb815Sopenharmony_ci      context.replacer_function_p = obj_p;
1405425bb815Sopenharmony_ci    }
1406425bb815Sopenharmony_ci    /* 4.b */
1407425bb815Sopenharmony_ci    else if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY)
1408425bb815Sopenharmony_ci    {
1409425bb815Sopenharmony_ci      ecma_extended_object_t *array_object_p = (ecma_extended_object_t *) obj_p;
1410425bb815Sopenharmony_ci      uint32_t array_length = array_object_p->u.array.length;
1411425bb815Sopenharmony_ci      uint32_t index = 0;
1412425bb815Sopenharmony_ci
1413425bb815Sopenharmony_ci      /* 4.b.iii.5 */
1414425bb815Sopenharmony_ci      while (index < array_length)
1415425bb815Sopenharmony_ci      {
1416425bb815Sopenharmony_ci        ecma_value_t value = ecma_op_object_get_by_uint32_index (obj_p, index);
1417425bb815Sopenharmony_ci
1418425bb815Sopenharmony_ci        if (ECMA_IS_VALUE_ERROR (value))
1419425bb815Sopenharmony_ci        {
1420425bb815Sopenharmony_ci          ecma_collection_free (context.property_list_p);
1421425bb815Sopenharmony_ci          return value;
1422425bb815Sopenharmony_ci        }
1423425bb815Sopenharmony_ci
1424425bb815Sopenharmony_ci        /* 4.b.iii.5.c */
1425425bb815Sopenharmony_ci        ecma_value_t item = ECMA_VALUE_UNDEFINED;
1426425bb815Sopenharmony_ci
1427425bb815Sopenharmony_ci        /* 4.b.iii.5.d */
1428425bb815Sopenharmony_ci        if (ecma_is_value_string (value))
1429425bb815Sopenharmony_ci        {
1430425bb815Sopenharmony_ci          ecma_ref_ecma_string (ecma_get_string_from_value (value));
1431425bb815Sopenharmony_ci          item = value;
1432425bb815Sopenharmony_ci        }
1433425bb815Sopenharmony_ci        /* 4.b.iii.5.e */
1434425bb815Sopenharmony_ci        else if (ecma_is_value_number (value))
1435425bb815Sopenharmony_ci        {
1436425bb815Sopenharmony_ci          ecma_string_t *number_str_p = ecma_op_to_string (value);
1437425bb815Sopenharmony_ci          JERRY_ASSERT (number_str_p != NULL);
1438425bb815Sopenharmony_ci          item = ecma_make_string_value (number_str_p);
1439425bb815Sopenharmony_ci        }
1440425bb815Sopenharmony_ci        /* 4.b.iii.5.f */
1441425bb815Sopenharmony_ci        else if (ecma_is_value_object (value))
1442425bb815Sopenharmony_ci        {
1443425bb815Sopenharmony_ci          ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
1444425bb815Sopenharmony_ci          lit_magic_string_id_t class_id = ecma_object_get_class_name (value_obj_p);
1445425bb815Sopenharmony_ci
1446425bb815Sopenharmony_ci          if (class_id == LIT_MAGIC_STRING_NUMBER_UL || class_id == LIT_MAGIC_STRING_STRING_UL)
1447425bb815Sopenharmony_ci          {
1448425bb815Sopenharmony_ci            ecma_string_t *str_p = ecma_op_to_string (value);
1449425bb815Sopenharmony_ci
1450425bb815Sopenharmony_ci            if (JERRY_UNLIKELY (str_p == NULL))
1451425bb815Sopenharmony_ci            {
1452425bb815Sopenharmony_ci              ecma_collection_free (context.property_list_p);
1453425bb815Sopenharmony_ci              ecma_free_value (value);
1454425bb815Sopenharmony_ci              return ECMA_VALUE_ERROR;
1455425bb815Sopenharmony_ci            }
1456425bb815Sopenharmony_ci
1457425bb815Sopenharmony_ci            item = ecma_make_string_value (str_p);
1458425bb815Sopenharmony_ci          }
1459425bb815Sopenharmony_ci        }
1460425bb815Sopenharmony_ci
1461425bb815Sopenharmony_ci        ecma_free_value (value);
1462425bb815Sopenharmony_ci
1463425bb815Sopenharmony_ci        /* 4.b.iii.5.g */
1464425bb815Sopenharmony_ci        if (!ecma_is_value_undefined (item))
1465425bb815Sopenharmony_ci        {
1466425bb815Sopenharmony_ci          JERRY_ASSERT (ecma_is_value_string (item));
1467425bb815Sopenharmony_ci          ecma_string_t *string_p = ecma_get_string_from_value (item);
1468425bb815Sopenharmony_ci
1469425bb815Sopenharmony_ci          if (!ecma_has_string_value_in_collection (context.property_list_p, string_p))
1470425bb815Sopenharmony_ci          {
1471425bb815Sopenharmony_ci            ecma_collection_push_back (context.property_list_p, item);
1472425bb815Sopenharmony_ci          }
1473425bb815Sopenharmony_ci          else
1474425bb815Sopenharmony_ci          {
1475425bb815Sopenharmony_ci            ecma_deref_ecma_string (string_p);
1476425bb815Sopenharmony_ci          }
1477425bb815Sopenharmony_ci        }
1478425bb815Sopenharmony_ci
1479425bb815Sopenharmony_ci        index++;
1480425bb815Sopenharmony_ci      }
1481425bb815Sopenharmony_ci    }
1482425bb815Sopenharmony_ci  }
1483425bb815Sopenharmony_ci
1484425bb815Sopenharmony_ci  ecma_value_t space;
1485425bb815Sopenharmony_ci
1486425bb815Sopenharmony_ci  /* 5. */
1487425bb815Sopenharmony_ci  if (ecma_is_value_object (arg3))
1488425bb815Sopenharmony_ci  {
1489425bb815Sopenharmony_ci    ecma_object_t *obj_p = ecma_get_object_from_value (arg3);
1490425bb815Sopenharmony_ci    lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);
1491425bb815Sopenharmony_ci
1492425bb815Sopenharmony_ci    /* 5.a */
1493425bb815Sopenharmony_ci    if (class_name == LIT_MAGIC_STRING_NUMBER_UL)
1494425bb815Sopenharmony_ci    {
1495425bb815Sopenharmony_ci      ecma_value_t value = ecma_op_to_number (arg3);
1496425bb815Sopenharmony_ci
1497425bb815Sopenharmony_ci      if (ECMA_IS_VALUE_ERROR (value))
1498425bb815Sopenharmony_ci      {
1499425bb815Sopenharmony_ci        ecma_collection_free (context.property_list_p);
1500425bb815Sopenharmony_ci        return value;
1501425bb815Sopenharmony_ci      }
1502425bb815Sopenharmony_ci
1503425bb815Sopenharmony_ci      space = value;
1504425bb815Sopenharmony_ci    }
1505425bb815Sopenharmony_ci    /* 5.b */
1506425bb815Sopenharmony_ci    else if (class_name == LIT_MAGIC_STRING_STRING_UL)
1507425bb815Sopenharmony_ci    {
1508425bb815Sopenharmony_ci      ecma_string_t *value_str_p = ecma_op_to_string (arg3);
1509425bb815Sopenharmony_ci
1510425bb815Sopenharmony_ci      if (JERRY_UNLIKELY (value_str_p == NULL))
1511425bb815Sopenharmony_ci      {
1512425bb815Sopenharmony_ci        ecma_collection_free (context.property_list_p);
1513425bb815Sopenharmony_ci        return ECMA_VALUE_ERROR;
1514425bb815Sopenharmony_ci      }
1515425bb815Sopenharmony_ci
1516425bb815Sopenharmony_ci      space = ecma_make_string_value (value_str_p);
1517425bb815Sopenharmony_ci    }
1518425bb815Sopenharmony_ci    else
1519425bb815Sopenharmony_ci    {
1520425bb815Sopenharmony_ci      space = ecma_copy_value (arg3);
1521425bb815Sopenharmony_ci    }
1522425bb815Sopenharmony_ci  }
1523425bb815Sopenharmony_ci  else
1524425bb815Sopenharmony_ci  {
1525425bb815Sopenharmony_ci    space = ecma_copy_value (arg3);
1526425bb815Sopenharmony_ci  }
1527425bb815Sopenharmony_ci
1528425bb815Sopenharmony_ci  /* 6. */
1529425bb815Sopenharmony_ci  if (ecma_is_value_number (space))
1530425bb815Sopenharmony_ci  {
1531425bb815Sopenharmony_ci    /* 6.a */
1532425bb815Sopenharmony_ci    ecma_number_t num_of_spaces;
1533425bb815Sopenharmony_ci    ecma_op_to_integer (space, &num_of_spaces);
1534425bb815Sopenharmony_ci
1535425bb815Sopenharmony_ci    num_of_spaces = JERRY_MIN (10, num_of_spaces);
1536425bb815Sopenharmony_ci
1537425bb815Sopenharmony_ci    /* 6.b */
1538425bb815Sopenharmony_ci    if (num_of_spaces < 1)
1539425bb815Sopenharmony_ci    {
1540425bb815Sopenharmony_ci      context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
1541425bb815Sopenharmony_ci    }
1542425bb815Sopenharmony_ci    else
1543425bb815Sopenharmony_ci    {
1544425bb815Sopenharmony_ci      JMEM_DEFINE_LOCAL_ARRAY (space_buff, num_of_spaces, char);
1545425bb815Sopenharmony_ci
1546425bb815Sopenharmony_ci      memset (space_buff, LIT_CHAR_SP, (size_t) num_of_spaces);
1547425bb815Sopenharmony_ci      context.gap_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) space_buff,
1548425bb815Sopenharmony_ci                                                          (lit_utf8_size_t) num_of_spaces);
1549425bb815Sopenharmony_ci
1550425bb815Sopenharmony_ci      JMEM_FINALIZE_LOCAL_ARRAY (space_buff);
1551425bb815Sopenharmony_ci    }
1552425bb815Sopenharmony_ci  }
1553425bb815Sopenharmony_ci  /* 7. */
1554425bb815Sopenharmony_ci  else if (ecma_is_value_string (space))
1555425bb815Sopenharmony_ci  {
1556425bb815Sopenharmony_ci    ecma_string_t *space_str_p = ecma_get_string_from_value (space);
1557425bb815Sopenharmony_ci    ecma_length_t num_of_chars = ecma_string_get_length (space_str_p);
1558425bb815Sopenharmony_ci
1559425bb815Sopenharmony_ci    if (num_of_chars < 10)
1560425bb815Sopenharmony_ci    {
1561425bb815Sopenharmony_ci      ecma_ref_ecma_string (space_str_p);
1562425bb815Sopenharmony_ci      context.gap_str_p = space_str_p;
1563425bb815Sopenharmony_ci    }
1564425bb815Sopenharmony_ci    else
1565425bb815Sopenharmony_ci    {
1566425bb815Sopenharmony_ci      context.gap_str_p = ecma_string_substr (space_str_p, 0, 10);
1567425bb815Sopenharmony_ci    }
1568425bb815Sopenharmony_ci  }
1569425bb815Sopenharmony_ci  /* 8. */
1570425bb815Sopenharmony_ci  else
1571425bb815Sopenharmony_ci  {
1572425bb815Sopenharmony_ci    context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
1573425bb815Sopenharmony_ci  }
1574425bb815Sopenharmony_ci
1575425bb815Sopenharmony_ci  ecma_free_value (space);
1576425bb815Sopenharmony_ci
1577425bb815Sopenharmony_ci  /* 1., 2., 3. */
1578425bb815Sopenharmony_ci  context.occurence_stack_last_p = NULL;
1579425bb815Sopenharmony_ci  context.indent_builder = ecma_stringbuilder_create ();
1580425bb815Sopenharmony_ci
1581425bb815Sopenharmony_ci  /* 9. */
1582425bb815Sopenharmony_ci  ecma_value_t ret_value = ecma_builtin_json_str_helper (&context, arg1);
1583425bb815Sopenharmony_ci
1584425bb815Sopenharmony_ci  ecma_deref_ecma_string (context.gap_str_p);
1585425bb815Sopenharmony_ci  ecma_stringbuilder_destroy (&context.indent_builder);
1586425bb815Sopenharmony_ci  ecma_collection_free (context.property_list_p);
1587425bb815Sopenharmony_ci
1588425bb815Sopenharmony_ci  return ret_value;
1589425bb815Sopenharmony_ci} /* ecma_builtin_json_stringify */
1590425bb815Sopenharmony_ci
1591425bb815Sopenharmony_ci/**
1592425bb815Sopenharmony_ci * @}
1593425bb815Sopenharmony_ci * @}
1594425bb815Sopenharmony_ci * @}
1595425bb815Sopenharmony_ci */
1596425bb815Sopenharmony_ci
1597425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_JSON) */
1598