jerryscript/jerry-core/ecma/builtin-objects/ecma-builtin-json.cpp
2015-07-15 16:17:56 +03:00

1806 lines
52 KiB
C++

/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecma-alloc.h"
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-builtin-helpers.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#include "ecma-try-catch-macro.h"
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "lit-char-helpers.h"
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_JSON_BUILTIN
#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-json.inc.h"
#define BUILTIN_UNDERSCORED_ID json
#include "ecma-builtin-internal-routines-template.inc.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmabuiltins
* @{
*
* \addtogroup json ECMA JSON object built-in
* @{
*/
/**
* JSON token type
*/
typedef enum
{
invalid_token, /**< error token */
end_token, /**< end of stream reached */
number_token, /**< JSON number */
string_token, /**< JSON string */
null_token, /**< JSON null primitive value */
true_token, /**< JSON true primitive value */
false_token, /**< JSON false primitive value */
left_brace_token, /**< JSON left brace */
right_brace_token, /**< JSON right brace */
left_square_token, /**< JSON left square bracket */
comma_token, /**< JSON comma */
colon_token /**< JSON colon */
} ecma_json_token_type_t;
/**
* JSON token
*/
typedef struct
{
ecma_json_token_type_t type; /**< type of the current token */
lit_utf8_byte_t *current_p; /**< current position of the string processed by the parser */
lit_utf8_byte_t *end_p; /**< end of the string processed by the parser */
union
{
struct
{
lit_utf8_byte_t *start_p; /**< when type is string_token, it contains the start of the string */
lit_utf8_size_t size; /**< when type is string_token, it contains the size of the string */
} string;
ecma_number_t number; /**< when type is number_token, it contains the value of the number */
} u;
} ecma_json_token_t;
/**
* Compare the string with an ID.
*
* @return true if the match is successful
*/
static bool
ecma_builtin_json_check_id (lit_utf8_byte_t *string_p, /**< start position */
const char *id_p) /**< string identifier */
{
/*
* String comparison must not depend on lit_utf8_byte_t definition.
*/
JERRY_ASSERT (*string_p == *id_p);
do
{
string_p++;
id_p++;
if (*id_p == '\0')
{
return !isalpha (*string_p) && !isdigit (*string_p) && *string_p != '$' && *string_p != '_';
}
}
while (*string_p == *id_p);
return false;
} /* ecma_builtin_json_check_id */
/**
* Parse and extract string token.
*/
static void
ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument */
{
lit_utf8_byte_t *current_p = token_p->current_p;
lit_utf8_byte_t *write_p = current_p;
token_p->u.string.start_p = current_p;
while (*current_p != '"')
{
if (*current_p <= 0x1f)
{
return;
}
if (*current_p == '\\')
{
current_p++;
switch (*current_p)
{
case '"':
case '/':
case '\\':
{
break;
}
case 'f':
{
*current_p = '\f';
break;
}
case 'n':
{
*current_p = '\n';
break;
}
case 'r':
{
*current_p = '\r';
break;
}
case 't':
{
*current_p = '\t';
break;
}
case 'b':
{
*current_p = '\b';
break;
}
default:
{
return;
}
}
}
*write_p++ = *current_p++;
}
token_p->u.string.size = (lit_utf8_size_t) (write_p - token_p->u.string.start_p);
token_p->current_p = current_p + 1;
token_p->type = string_token;
} /* ecma_builtin_json_parse_string */
/**
* Parse and extract string token.
*/
static void
ecma_builtin_json_parse_number (ecma_json_token_t *token_p) /**< token argument */
{
lit_utf8_byte_t *current_p = token_p->current_p;
lit_utf8_byte_t *start_p = current_p;
if (*current_p == '-')
{
current_p++;
}
if (*current_p == '0')
{
current_p++;
if (isdigit (*current_p))
{
return;
}
}
else if (isdigit (*current_p))
{
do
{
current_p++;
}
while (isdigit (*current_p));
}
if (*current_p == '.')
{
current_p++;
if (!isdigit (*current_p))
{
return;
}
do
{
current_p++;
}
while (isdigit (*current_p));
}
if (*current_p == 'e' || *current_p == 'E')
{
current_p++;
if (*current_p == '+' || *current_p == '-')
{
current_p++;
}
if (!isdigit (*current_p))
{
return;
}
do
{
current_p++;
}
while (isdigit (*current_p));
}
token_p->type = number_token;
token_p->u.number = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (current_p - start_p));
token_p->current_p = current_p;
} /* ecma_builtin_json_parse_number */
/**
* Parse next token.
*
* The function fills the fields of the ecma_json_token_t
* argument and advances the string pointer.
*/
static void
ecma_builtin_json_parse_next_token (ecma_json_token_t *token_p) /**< token argument */
{
lit_utf8_byte_t *current_p = token_p->current_p;
token_p->type = invalid_token;
/*
* No need for end check since the string is zero terminated.
*/
while (*current_p == ' ' || *current_p == '\r'
|| *current_p == '\n' || *current_p == '\t')
{
current_p++;
}
if (current_p == token_p->end_p)
{
token_p->type = end_token;
return;
}
switch (*current_p)
{
case '{':
{
token_p->type = left_brace_token;
token_p->current_p = current_p + 1;
return;
}
case '}':
{
token_p->type = right_brace_token;
token_p->current_p = current_p + 1;
return;
}
case '[':
{
token_p->type = left_square_token;
token_p->current_p = current_p + 1;
return;
}
case ',':
{
token_p->type = comma_token;
token_p->current_p = current_p + 1;
return;
}
case ':':
{
token_p->type = colon_token;
token_p->current_p = current_p + 1;
return;
}
case '"':
{
token_p->current_p = current_p + 1;
ecma_builtin_json_parse_string (token_p);
return;
}
case 'n':
{
if (ecma_builtin_json_check_id (current_p, "null"))
{
token_p->type = null_token;
token_p->current_p = current_p + 4;
return;
}
break;
}
case 't':
{
if (ecma_builtin_json_check_id (current_p, "true"))
{
token_p->type = true_token;
token_p->current_p = current_p + 4;
return;
}
break;
}
case 'f':
{
if (ecma_builtin_json_check_id (current_p, "false"))
{
token_p->type = false_token;
token_p->current_p = current_p + 5;
return;
}
break;
}
default:
{
if (*current_p == '-' || isdigit (*current_p))
{
token_p->current_p = current_p;
ecma_builtin_json_parse_number (token_p);
return;
}
break;
}
}
} /* ecma_builtin_json_parse_next_token */
/**
* Checks whether the next token is right square token.
*
* @return true if it is.
*
* Always skips white spaces regardless the next token.
*/
static bool
ecma_builtin_json_check_right_square_token (ecma_json_token_t *token_p) /**< token argument */
{
lit_utf8_byte_t *current_p = token_p->current_p;
/*
* No need for end check since the string is zero terminated.
*/
while (*current_p == ' ' || *current_p == '\r'
|| *current_p == '\n' || *current_p == '\t')
{
current_p++;
}
token_p->current_p = current_p;
if (*current_p == ']')
{
token_p->current_p = current_p + 1;
return true;
}
return false;
} /* ecma_builtin_json_check_right_square_token */
/**
* Utility for defining properties.
*
* It silently ignores all errors.
*/
static void
ecma_builtin_json_define_value_property (ecma_object_t *obj_p, /**< this object */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t value) /**< value */
{
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
{
prop_desc.is_value_defined = true;
prop_desc.value = value;
prop_desc.is_writable_defined = true;
prop_desc.is_writable = true;
prop_desc.is_enumerable_defined = true;
prop_desc.is_enumerable = true;
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = true;
}
ecma_completion_value_t completion_value = ecma_op_object_define_own_property (obj_p,
property_name_p,
&prop_desc,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_value)
|| ecma_is_completion_value_normal_false (completion_value));
} /* ecma_builtin_json_define_value_property */
/**
* Parse next value.
*
* The function fills the fields of the ecma_json_token_t
* argument and advances the string pointer.
*
* @return ecma_value with the property value
*/
static ecma_value_t
ecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument */
{
ecma_builtin_json_parse_next_token (token_p);
switch (token_p->type)
{
case number_token:
{
ecma_number_t *number_p = ecma_alloc_number ();
*number_p = token_p->u.number;
return ecma_make_number_value (number_p);
}
case string_token:
{
ecma_string_t *string_p = ecma_new_ecma_string_from_utf8 (token_p->u.string.start_p, token_p->u.string.size);
return ecma_make_string_value (string_p);
}
case null_token:
{
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL);
}
case true_token:
{
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
}
case false_token:
{
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
}
case left_brace_token:
{
bool parse_comma = false;
ecma_object_t *object_p = ecma_op_create_object_object_noarg ();
while (true)
{
ecma_builtin_json_parse_next_token (token_p);
if (token_p->type == right_brace_token)
{
return ecma_make_object_value (object_p);
}
if (parse_comma)
{
if (token_p->type != comma_token)
{
break;
}
ecma_builtin_json_parse_next_token (token_p);
}
if (token_p->type != string_token)
{
break;
}
lit_utf8_byte_t *string_start_p = token_p->u.string.start_p;
lit_utf8_size_t string_size = token_p->u.string.size;
ecma_builtin_json_parse_next_token (token_p);
if (token_p->type != colon_token)
{
break;
}
ecma_value_t value = ecma_builtin_json_parse_value (token_p);
if (ecma_is_value_undefined (value))
{
break;
}
ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (string_start_p, string_size);
ecma_builtin_json_define_value_property (object_p, name_p, value);
ecma_deref_ecma_string (name_p);
ecma_free_value (value, true);
parse_comma = true;
}
/*
* Parse error occured.
*/
ecma_deref_object (object_p);
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
case left_square_token:
{
bool parse_comma = false;
uint32_t length = 0;
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN
ecma_object_t *array_prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE);
#else /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */
ecma_object_t *array_prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ARRAY_BUILTIN */
ecma_object_t *array_p = ecma_create_object (array_prototype_p, true, ECMA_OBJECT_TYPE_ARRAY);
ecma_deref_object (array_prototype_p);
ecma_property_t *class_prop_p = ecma_create_internal_property (array_p, ECMA_INTERNAL_PROPERTY_CLASS);
class_prop_p->u.internal_property.value = LIT_MAGIC_STRING_ARRAY_UL;
while (true)
{
if (ecma_builtin_json_check_right_square_token (token_p))
{
ecma_string_t *length_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
ecma_number_t *length_num_p = ecma_alloc_number ();
*length_num_p = ecma_uint32_to_number (length);
ecma_property_t *length_prop_p = ecma_create_named_data_property (array_p,
length_magic_string_p,
true,
false,
false);
ecma_set_named_data_property_value (length_prop_p, ecma_make_number_value (length_num_p));
ecma_deref_ecma_string (length_magic_string_p);
return ecma_make_object_value (array_p);
}
if (parse_comma)
{
ecma_builtin_json_parse_next_token (token_p);
if (token_p->type != comma_token)
{
break;
}
}
ecma_value_t value = ecma_builtin_json_parse_value (token_p);
if (ecma_is_value_undefined (value))
{
break;
}
ecma_string_t *name_p = ecma_new_ecma_string_from_uint32 (length);
ecma_property_t *property_p = ecma_create_named_data_property (array_p, name_p,
true, true, true);
ecma_deref_ecma_string (name_p);
ecma_named_data_property_assign_value (array_p, property_p, value);
ecma_free_value (value, true);
length++;
parse_comma = true;
}
/*
* Parse error occured.
*/
ecma_deref_object (array_p);
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
default:
{
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
}
} /* ecma_builtin_json_parse_value */
/**
* Abstract operation Walk defined in 15.12.2
*
* See also:
* ECMA-262 v5, 15.12.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */
ecma_object_t *holder_p, /**< holder object */
ecma_string_t *name_p) /** < property name */
{
JERRY_ASSERT (reviver_p);
JERRY_ASSERT (holder_p);
JERRY_ASSERT (name_p);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (value_get,
ecma_op_object_get (holder_p, name_p),
ret_value);
if (ecma_is_value_object (value_get))
{
ecma_object_t *object_p = ecma_get_object_from_value (value_get);
uint32_t no_properties = 0;
/*
* The following algorithm works with arrays and objects as well.
*/
for (ecma_property_t *property_p = ecma_get_property_list (object_p);
property_p != NULL;
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
{
/*
* All properties must be named data or internal properties, since we constructed them.
*/
JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA
|| property_p->type == ECMA_PROPERTY_INTERNAL);
if (property_p->type == ECMA_PROPERTY_NAMEDDATA
&& ecma_is_property_enumerable (property_p))
{
no_properties++;
}
}
if (no_properties > 0)
{
MEM_DEFINE_LOCAL_ARRAY (property_names_p, no_properties, ecma_string_t *);
uint32_t property_index = no_properties;
for (ecma_property_t *property_p = ecma_get_property_list (object_p);
property_p != NULL;
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
{
if (property_p->type == ECMA_PROPERTY_NAMEDDATA
&& ecma_is_property_enumerable (property_p))
{
ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_data_property.name_p);
/*
* The property list must be in creation order.
*/
property_index--;
property_names_p[property_index] = ecma_copy_or_ref_ecma_string (property_name_p);
}
}
JERRY_ASSERT (property_index == 0);
for (property_index = 0;
property_index < no_properties && ecma_is_completion_value_empty (ret_value);
property_index++)
{
ECMA_TRY_CATCH (value_walk,
ecma_builtin_json_walk (reviver_p,
object_p,
property_names_p[property_index]),
ret_value);
/*
* We cannot optimize this function since any members
* can be changed (deleted) by the reviver function.
*/
if (ecma_is_value_undefined (value_walk))
{
ecma_completion_value_t delete_val = ecma_op_general_object_delete (object_p,
property_names_p[property_index],
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (delete_val)
|| ecma_is_completion_value_normal_false (delete_val));
}
else
{
ecma_builtin_json_define_value_property (object_p,
property_names_p[property_index],
value_walk);
}
ECMA_FINALIZE (value_walk);
}
for (uint32_t i = 0; i < no_properties; i++)
{
ecma_deref_ecma_string (property_names_p[i]);
}
MEM_FINALIZE_LOCAL_ARRAY (property_names_p);
}
}
if (ecma_is_completion_value_empty (ret_value))
{
ecma_value_t arguments_list[2];
arguments_list[0] = ecma_make_string_value (name_p);
arguments_list[1] = value_get;
/*
* The completion value can be anything including exceptions.
*/
ret_value = ecma_op_function_call (reviver_p,
ecma_make_object_value (holder_p),
arguments_list,
2);
}
else
{
JERRY_ASSERT (ecma_is_completion_value_throw (ret_value));
}
ECMA_FINALIZE (value_get);
return ret_value;
} /* ecma_builtin_json_walk */
/**
* The JSON object's 'parse' routine
*
* See also:
* ECMA-262 v5, 15.12.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_parse (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
ecma_value_t arg1, /**< string argument */
ecma_value_t arg2) /**< reviver argument */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (string,
ecma_op_to_string (arg1),
ret_value);
ecma_string_t *string_p = ecma_get_string_from_value (string);
ecma_length_t length = (uint32_t) ecma_string_get_length (string_p);
size_t buffer_size = sizeof (lit_utf8_byte_t) * (length + 1);
MEM_DEFINE_LOCAL_ARRAY (str_start_p, buffer_size, lit_utf8_byte_t);
ecma_string_to_utf8_string (string_p, str_start_p, (ssize_t) buffer_size);
str_start_p[length] = LIT_BYTE_NULL;
ecma_json_token_t token;
token.current_p = str_start_p;
token.end_p = str_start_p + length;
ecma_value_t final_result = ecma_builtin_json_parse_value (&token);
if (!ecma_is_value_undefined (final_result))
{
ecma_builtin_json_parse_next_token (&token);
if (token.type != end_token)
{
ecma_free_value (final_result, true);
final_result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
}
if (ecma_is_value_undefined (final_result))
{
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_SYNTAX));
}
else
{
if (ecma_op_is_callable (arg2))
{
ecma_object_t *object_p = ecma_op_create_object_object_noarg ();
ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
ecma_property_t *property_p = ecma_create_named_data_property (object_p,
name_p,
true,
true,
true);
ecma_named_data_property_assign_value (object_p, property_p, final_result);
ecma_free_value (final_result, true);
ret_value = ecma_builtin_json_walk (ecma_get_object_from_value (arg2),
object_p,
name_p);
ecma_deref_object (object_p);
ecma_deref_ecma_string (name_p);
}
else
{
ret_value = ecma_make_normal_completion_value (final_result);
}
}
MEM_FINALIZE_LOCAL_ARRAY (str_start_p);
ECMA_FINALIZE (string);
return ret_value;
} /* ecma_builtin_json_parse */
static ecma_completion_value_t
ecma_builtin_json_str (ecma_string_t *key_p, ecma_object_t *holder_p, stringify_context_t *context_p);
static ecma_completion_value_t
ecma_builtin_json_object (ecma_object_t *obj_p, stringify_context_t *context_p);
static ecma_completion_value_t
ecma_builtin_json_array (ecma_object_t *obj_p, stringify_context_t *context_p);
/**
* The JSON object's 'stringify' routine
*
* See also:
* ECMA-262 v5, 15.12.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_stringify (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
ecma_value_t arg1, /**< value */
ecma_value_t arg2, /**< replacer */
ecma_value_t arg3) /**< space */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
stringify_context_t context_p;
/* 1. */
context_p.occurence_stack.block_start_p = NULL;
context_p.occurence_stack.block_end_p = NULL;
context_p.occurence_stack.current_p = NULL;
/* 2. */
context_p.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
/* 3. */
context_p.property_list.block_start_p = NULL;
context_p.property_list.block_end_p = NULL;
context_p.property_list.current_p = NULL;
context_p.replacer_function_p = NULL;
/* 4. */
if (ecma_is_value_object (arg2))
{
ecma_object_t *obj_p = ecma_get_object_from_value (arg2);
/* 4.a */
if (ecma_op_is_callable (arg2))
{
context_p.replacer_function_p = obj_p;
}
/* 4.b */
else if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_ARRAY_UL)
{
ecma_string_t *length_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
ECMA_TRY_CATCH (array_length,
ecma_op_object_get (obj_p, length_str_p),
ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num,
array_length,
ret_value);
uint32_t array_length = ecma_number_to_uint32 (array_length_num);
uint32_t index = 0;
/* 4.b.ii */
while ((index < array_length) && ecma_is_completion_value_empty (ret_value))
{
ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
ECMA_TRY_CATCH (value,
ecma_op_object_get (obj_p, index_str_p),
ret_value);
/* 4.b.ii.1 */
ecma_value_t item = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
/* 4.b.ii.2 */
if (ecma_is_value_string (value))
{
item = ecma_copy_value (value, true);
}
/* 4.b.ii.3 */
else if (ecma_is_value_number (value))
{
ECMA_TRY_CATCH (str_val,
ecma_op_to_string (value),
ret_value);
item = ecma_copy_value (str_val, true);
ECMA_FINALIZE (str_val);
}
/* 4.b.ii.4 */
else if (ecma_is_value_object (value))
{
ecma_object_t *obj_val_p = ecma_get_object_from_value (value);
lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_val_p);
/* 4.b.ii.4.a */
if (class_name == LIT_MAGIC_STRING_NUMBER_UL
|| class_name == LIT_MAGIC_STRING_STRING_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_string (value),
ret_value);
item = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
}
/* 4.b.ii.5 */
if (!ecma_is_value_undefined (item))
{
ecma_string_t *item_str_p = ecma_get_string_from_value (item);
if (!list_has_ecma_string_element (&context_p.property_list, item_str_p))
{
list_append (&context_p.property_list, item_str_p);
}
else
{
ecma_deref_ecma_string (item_str_p);
}
}
ECMA_FINALIZE (value);
ecma_deref_ecma_string (index_str_p);
index++;
}
ECMA_OP_TO_NUMBER_FINALIZE (array_length_num);
ECMA_FINALIZE (array_length);
ecma_deref_ecma_string (length_str_p);
}
}
ecma_value_t space = ecma_copy_value (arg3, true);
/* 5. */
if (ecma_is_value_object (arg3))
{
ecma_object_t *obj_p = ecma_get_object_from_value (arg3);
lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);
/* 5.a */
if (class_name == LIT_MAGIC_STRING_NUMBER_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_number (arg3),
ret_value);
ecma_free_value (space, true);
space = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
/* 5.b */
else if (class_name == LIT_MAGIC_STRING_STRING_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_string (arg3),
ret_value);
ecma_free_value (space, true);
space = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
}
/* 6. */
if (ecma_is_value_number (space))
{
ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num,
arg3,
ret_value);
/* 6.a */
int32_t num_of_spaces = ecma_number_to_int32 (array_length_num);
int32_t space = (num_of_spaces > 10) ? 10 : num_of_spaces;
/* 6.b */
if (space < 1)
{
context_p.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
}
else
{
MEM_DEFINE_LOCAL_ARRAY (space_buff, space, char);
for (int32_t i = 0; i < space; i++)
{
space_buff[i] = ' ';
}
context_p.gap_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) space_buff, (lit_utf8_size_t) space);
MEM_FINALIZE_LOCAL_ARRAY (space_buff);
}
ECMA_OP_TO_NUMBER_FINALIZE (array_length_num);
}
/* 7. */
else if (ecma_is_value_string (space))
{
ecma_string_t *space_str_p = ecma_get_string_from_value (space);
ecma_length_t num_of_chars = ecma_string_get_length (space_str_p);
if (num_of_chars < 10)
{
context_p.gap_str_p = ecma_copy_or_ref_ecma_string (space_str_p);
}
else
{
ecma_length_t string_len = ecma_string_get_length (space_str_p);
MEM_DEFINE_LOCAL_ARRAY (zt_string_buff, string_len, lit_utf8_byte_t);
size_t string_buf_size = (size_t) (string_len) * sizeof (lit_utf8_byte_t);
ssize_t bytes_copied = ecma_string_to_utf8_string (space_str_p,
zt_string_buff,
(ssize_t) string_buf_size);
JERRY_ASSERT (bytes_copied > 0);
/* Buffer for the first 10 characters. */
MEM_DEFINE_LOCAL_ARRAY (space_buff, 10, lit_utf8_byte_t);
for (uint32_t i = 0; i < 10; i++)
{
space_buff[i] = zt_string_buff[i];
}
context_p.gap_str_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) space_buff, 10);
MEM_FINALIZE_LOCAL_ARRAY (space_buff);
MEM_FINALIZE_LOCAL_ARRAY (zt_string_buff);
}
}
/* 8. */
else
{
context_p.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
}
ecma_free_value (space, true);
/* 9. */
ecma_object_t *obj_wrapper_p = ecma_create_object (NULL, true, ECMA_OBJECT_TYPE_GENERAL);
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
/* 10. */
ecma_completion_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
empty_str_p,
arg1,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (put_comp_val));
ecma_free_completion_value (put_comp_val);
/* 11. */
ECMA_TRY_CATCH (str_val,
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context_p),
ret_value);
ret_value = ecma_make_normal_completion_value (ecma_copy_value (str_val, true));
ECMA_FINALIZE (str_val);
ecma_deref_object (obj_wrapper_p);
ecma_deref_ecma_string (empty_str_p);
ecma_deref_ecma_string (context_p.indent_str_p);
ecma_deref_ecma_string (context_p.gap_str_p);
free_list_with_ecma_string_content (&context_p.property_list);
free_list (&context_p.occurence_stack);
return ret_value;
} /* ecma_builtin_json_stringify */
/**
* Abstract operation 'Quote' defined in 15.12.3
*
* See also:
* ECMA-262 v5, 15.12.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_quote (ecma_string_t *string_p) /**< string that should be quoted*/
{
/* 1. */
ecma_string_t *quote_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_DOUBLE_QUOTE_CHAR);
ecma_string_t *product_str_p = ecma_copy_or_ref_ecma_string (quote_str_p);
ecma_string_t *tmp_str_p;
ecma_length_t string_len = ecma_string_get_length (string_p);
MEM_DEFINE_LOCAL_ARRAY (zt_string_buff, string_len, lit_utf8_byte_t);
size_t string_buf_size = (size_t) (string_len) * sizeof (lit_utf8_byte_t);
ssize_t bytes_copied = ecma_string_to_utf8_string (string_p,
zt_string_buff,
(ssize_t) string_buf_size);
JERRY_ASSERT (bytes_copied > 0 || !string_len);
/* 2. */
for (ecma_length_t i = 0; i < string_len; i++)
{
lit_utf8_byte_t c = zt_string_buff[i];
/* 2.a */
if (c == '\\' || c == '\"')
{
ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR);
/* 2.a.i */
tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (backslash_str_p);
product_str_p = tmp_str_p;
/* 2.a.ii */
ecma_string_t *c_str_p = ecma_new_ecma_string_from_utf8 (&c, 1);
tmp_str_p = ecma_concat_ecma_strings (product_str_p, c_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (c_str_p);
product_str_p = tmp_str_p;
}
/* 2.b */
else if (c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t')
{
ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR);
/* 2.b.i */
tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (backslash_str_p);
product_str_p = tmp_str_p;
/* 2.b.ii */
lit_utf8_byte_t abbrev = ' ';
switch (c)
{
case '\b':
{
abbrev = 'b';
break;
}
case '\f':
{
abbrev = 'f';
break;
}
case '\n':
{
abbrev = 'n';
break;
}
case '\r':
{
abbrev = 'r';
break;
}
case '\t':
{
abbrev = 't';
break;
}
}
/* 2.b.iii */
ecma_string_t *abbrev_str_p = ecma_new_ecma_string_from_utf8 (&abbrev, 1);
tmp_str_p = ecma_concat_ecma_strings (product_str_p, abbrev_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (abbrev_str_p);
product_str_p = tmp_str_p;
}
/* 2.c */
else if (c < LIT_CHAR_SP)
{
ecma_string_t *backslash_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BACKSLASH_CHAR);
/* 2.c.i */
tmp_str_p = ecma_concat_ecma_strings (product_str_p, backslash_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (backslash_str_p);
product_str_p = tmp_str_p;
/* 2.c.ii */
lit_utf8_byte_t u_ch = 'u';
ecma_string_t *u_ch_str_p = ecma_new_ecma_string_from_utf8 (&u_ch, 1);
tmp_str_p = ecma_concat_ecma_strings (product_str_p, u_ch_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (u_ch_str_p);
product_str_p = tmp_str_p;
/* 2.c.iii */
ecma_string_t *hex_str_p = ecma_builtin_helper_json_create_hex_digit_ecma_string (c);
/* 2.c.iv */
tmp_str_p = ecma_concat_ecma_strings (product_str_p, hex_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (hex_str_p);
product_str_p = tmp_str_p;
}
/* 2.d */
else
{
ecma_string_t *c_str_p = ecma_new_ecma_string_from_utf8 (&c, 1);
tmp_str_p = ecma_concat_ecma_strings (product_str_p, c_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (c_str_p);
product_str_p = tmp_str_p;
}
}
MEM_FINALIZE_LOCAL_ARRAY (zt_string_buff);
/* 3. */
tmp_str_p = ecma_concat_ecma_strings (product_str_p, quote_str_p);
ecma_deref_ecma_string (product_str_p);
ecma_deref_ecma_string (quote_str_p);
product_str_p = tmp_str_p;
/* 4. */
return ecma_make_normal_completion_value (ecma_make_string_value (product_str_p));
} /* ecma_builtin_json_quote */
/**
* Abstract operation 'Str' defined in 15.12.3
*
* See also:
* ECMA-262 v5, 15.12.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_str (ecma_string_t *key_p, /**< property key*/
ecma_object_t *holder_p, /**< the object*/
stringify_context_t *context_p) /**< context*/
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
/* 1. */
ECMA_TRY_CATCH (value,
ecma_op_object_get (holder_p, key_p),
ret_value);
ecma_value_t my_val = ecma_copy_value (value, true);
/* 2. */
if (ecma_is_value_object (my_val))
{
ecma_object_t *value_obj_p = ecma_get_object_from_value (my_val);
ecma_string_t *to_json_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_TO_JSON_UL);
/* 2.a */
ECMA_TRY_CATCH (toJSON,
ecma_op_object_get (value_obj_p, to_json_str_p),
ret_value);
/* 2.b */
if (ecma_op_is_callable (toJSON))
{
ecma_value_t key_value = ecma_make_string_value (key_p);
ecma_value_t call_args[] = { key_value };
ecma_object_t *toJSON_obj_p = ecma_get_object_from_value (toJSON);
ECMA_TRY_CATCH (func_ret_val,
ecma_op_function_call (toJSON_obj_p, my_val, call_args, 1),
ret_value);
ecma_free_value (my_val, true);
my_val = ecma_copy_value (func_ret_val, true);
ECMA_FINALIZE (func_ret_val);
}
ECMA_FINALIZE (toJSON);
ecma_deref_ecma_string (to_json_str_p);
}
/* 3. */
if (context_p->replacer_function_p && ecma_is_completion_value_empty (ret_value))
{
ecma_value_t holder_value = ecma_make_object_value (holder_p);
ecma_value_t key_value = ecma_make_string_value (key_p);
ecma_value_t call_args[] = { key_value, my_val };
ECMA_TRY_CATCH (func_ret_val,
ecma_op_function_call (context_p->replacer_function_p, holder_value, call_args, 2),
ret_value);
ecma_free_value (my_val, true);
my_val = ecma_copy_value (func_ret_val, true);
ECMA_FINALIZE (func_ret_val);
}
/* 4. */
if (ecma_is_value_object (my_val) && ecma_is_completion_value_empty (ret_value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (my_val);
lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);
/* 4.a */
if (class_name == LIT_MAGIC_STRING_NUMBER_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_number (my_val),
ret_value);
ecma_free_value (my_val, true);
my_val = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
/* 4.b */
else if (class_name == LIT_MAGIC_STRING_STRING_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_string (my_val),
ret_value);
ecma_free_value (my_val, true);
my_val = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
/* 4.c */
else if (class_name == LIT_MAGIC_STRING_BOOLEAN_UL)
{
ECMA_TRY_CATCH (val,
ecma_op_to_primitive (my_val, ECMA_PREFERRED_TYPE_NO),
ret_value);
ecma_free_value (my_val, true);
my_val = ecma_copy_value (val, true);
ECMA_FINALIZE (val);
}
}
if (ecma_is_completion_value_empty (ret_value))
{
/* 5. - 7. */
if (ecma_is_value_null (my_val) || ecma_is_value_boolean (my_val))
{
ret_value = ecma_op_to_string (my_val);
JERRY_ASSERT (ecma_is_completion_value_normal (ret_value));
}
/* 8. */
else if (ecma_is_value_string (my_val))
{
ecma_string_t *value_str_p = ecma_get_string_from_value (my_val);
ret_value = ecma_builtin_json_quote (value_str_p);
}
/* 9. */
else if (ecma_is_value_number (my_val))
{
ecma_number_t num_value_p = *ecma_get_number_from_value (my_val);
/* 9.a */
if (!ecma_number_is_infinity (num_value_p))
{
ret_value = ecma_op_to_string (my_val);
JERRY_ASSERT (ecma_is_completion_value_normal (ret_value));
}
else
{
/* 9.b */
ecma_string_t *null_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL);
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (null_str_p));
}
}
/* 10. */
else if (ecma_is_value_object (my_val) && !ecma_op_is_callable (my_val))
{
ecma_object_t *obj_p = ecma_get_object_from_value (my_val);
lit_magic_string_id_t class_name = ecma_object_get_class_name (obj_p);
/* 10.a */
if (class_name == LIT_MAGIC_STRING_ARRAY_UL)
{
ECMA_TRY_CATCH (val,
ecma_builtin_json_array (obj_p, context_p),
ret_value);
ret_value = ecma_make_normal_completion_value (ecma_copy_value (val, true));
ECMA_FINALIZE (val);
}
/* 10.b */
else
{
ECMA_TRY_CATCH (val,
ecma_builtin_json_object (obj_p, context_p),
ret_value);
ret_value = ecma_make_normal_completion_value (ecma_copy_value (val, true));
ECMA_FINALIZE (val);
}
}
else
{
/* 11. */
ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
}
ecma_free_value (my_val, true);
ECMA_FINALIZE (value);
return ret_value;
} /* ecma_builtin_json_str */
/**
* Abstract operation 'JO' defined in 15.12.3
*
* See also:
* ECMA-262 v5, 15.12.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/
stringify_context_t *context_p) /**< context*/
{
/* 1. */
if (list_has_element (&context_p->occurence_stack, obj_p))
{
return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
}
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
/* 2. */
list_append (&context_p->occurence_stack, obj_p);
/* 3. */
ecma_string_t *stepback_p = context_p->indent_str_p;
/* 4. */
context_p->indent_str_p = ecma_concat_ecma_strings (context_p->indent_str_p, context_p->gap_str_p);
list_ctx_t property_keys;
{
property_keys.block_start_p = NULL;
property_keys.block_end_p = NULL;
property_keys.current_p = NULL;
}
/* 5. */
if (!list_is_empty (&context_p->property_list))
{
property_keys = context_p->property_list;
}
/* 6. */
else
{
for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
property_p != NULL;
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
{
if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_enumerable (property_p))
{
ecma_string_t *prop_key = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_p->u.named_data_property.name_p);
JERRY_ASSERT (prop_key != NULL);
list_append (&property_keys, ecma_copy_or_ref_ecma_string (prop_key));
}
}
}
/* 7. */
list_ctx_t partial;
{
partial.block_start_p = NULL;
partial.block_end_p = NULL;
partial.current_p = NULL;
}
/* 8. */
for (void **key_p = property_keys.block_start_p;
key_p < property_keys.current_p && ecma_is_completion_value_empty (ret_value);
key_p++)
{
/* 8.a */
ECMA_TRY_CATCH (str_val,
ecma_builtin_json_str ((ecma_string_t *) *key_p, obj_p, context_p),
ret_value);
/* 8.b */
if (!ecma_is_value_undefined (str_val))
{
ecma_string_t *colon_p = ecma_get_magic_string (LIT_MAGIC_STRING_COLON_CHAR);
ecma_string_t *value_str_p = ecma_get_string_from_value (str_val);
ecma_string_t *tmp_str_p;
/* 8.b.i */
ecma_completion_value_t str_comp_val = ecma_builtin_json_quote ((ecma_string_t *) *key_p);
JERRY_ASSERT (ecma_is_completion_value_normal (str_comp_val));
ecma_string_t *member_str_p = ecma_get_string_from_value (str_comp_val);
/* 8.b.ii */
tmp_str_p = ecma_concat_ecma_strings (member_str_p, colon_p);
ecma_free_completion_value (str_comp_val);
ecma_deref_ecma_string (colon_p);
member_str_p = tmp_str_p;
/* 8.b.iii */
bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0);
if (!is_gap_empty)
{
ecma_string_t *space_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_SPACE_CHAR);
tmp_str_p = ecma_concat_ecma_strings (member_str_p, space_str_p);
ecma_deref_ecma_string (member_str_p);
ecma_deref_ecma_string (space_str_p);
member_str_p = tmp_str_p;
}
/* 8.b.iv */
tmp_str_p = ecma_concat_ecma_strings (member_str_p, value_str_p);
ecma_deref_ecma_string (member_str_p);
member_str_p = tmp_str_p;
/* 8.b.v */
list_append (&partial, member_str_p);
}
ECMA_FINALIZE (str_val);
}
if (list_is_empty (&context_p->property_list))
{
free_list_with_ecma_string_content (&property_keys);
}
if (!ecma_is_completion_value_empty (ret_value))
{
free_list_with_ecma_string_content (&partial);
ecma_deref_ecma_string (stepback_p);
return ret_value;
}
/* 9. */
if (list_is_empty (&partial))
{
ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);
ecma_string_t *final_str_p = ecma_concat_ecma_strings (left_brace_str_p, right_brace_str_p);
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (final_str_p));
ecma_deref_ecma_string (left_brace_str_p);
ecma_deref_ecma_string (right_brace_str_p);
}
/* 10. */
else
{
bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0);
/* 10.a */
if (is_gap_empty)
{
ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);
ret_value = ecma_builtin_helper_json_create_non_formatted_json (left_brace_str_p,
right_brace_str_p,
&partial);
ecma_deref_ecma_string (left_brace_str_p);
ecma_deref_ecma_string (right_brace_str_p);
}
/* 10.b */
else
{
ecma_string_t *left_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
ecma_string_t *right_brace_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);
ret_value = ecma_builtin_helper_json_create_formatted_json (left_brace_str_p,
right_brace_str_p,
stepback_p,
&partial,
context_p);
ecma_deref_ecma_string (left_brace_str_p);
ecma_deref_ecma_string (right_brace_str_p);
}
}
free_list_with_ecma_string_content (&partial);
/* 11. */
list_remove_last_element (&context_p->occurence_stack);
/* 12. */
ecma_deref_ecma_string (context_p->indent_str_p);
context_p->indent_str_p = stepback_p;
/* 13. */
return ret_value;
} /* ecma_builtin_json_object */
/**
* Abstract operation 'JA' defined in 15.12.3
*
* See also:
* ECMA-262 v5, 15.12.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value.
*/
static ecma_completion_value_t
ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/
stringify_context_t *context_p) /**< context*/
{
/* 1. */
if (list_has_element (&context_p->occurence_stack, obj_p))
{
return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
}
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
/* 2. */
list_append (&context_p->occurence_stack, obj_p);
/* 3. */
ecma_string_t *stepback_p = context_p->indent_str_p;
/* 4. */
context_p->indent_str_p = ecma_concat_ecma_strings (context_p->indent_str_p, context_p->gap_str_p);
/* 5. */
list_ctx_t partial;
{
partial.block_start_p = NULL;
partial.block_end_p = NULL;
partial.current_p = NULL;
}
ecma_string_t *length_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
/* 6. */
ECMA_TRY_CATCH (array_length,
ecma_op_object_get (obj_p, length_str_p),
ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (array_length_num,
array_length,
ret_value);
uint32_t array_length = ecma_number_to_uint32 (array_length_num);
/* 7. - 8. */
for (uint32_t index = 0;
index < array_length && ecma_is_completion_value_empty (ret_value);
index++)
{
/* 8.a */
ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index);
ECMA_TRY_CATCH (str_val,
ecma_builtin_json_str (index_str_p, obj_p, context_p),
ret_value);
/* 8.b */
if (ecma_is_value_undefined (str_val))
{
list_append (&partial, ecma_get_magic_string (LIT_MAGIC_STRING_NULL));
}
/* 8.c */
else
{
ecma_string_t *str_val_p = ecma_get_string_from_value (str_val);
list_append (&partial, ecma_copy_or_ref_ecma_string (str_val_p));
}
ECMA_FINALIZE (str_val);
ecma_deref_ecma_string (index_str_p);
}
if (ecma_is_completion_value_empty (ret_value))
{
/* 9. */
if (list_is_empty (&partial))
{
ecma_string_t *left_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_SQUARE_CHAR);
ecma_string_t *right_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR);
ecma_string_t *final_str_p = ecma_concat_ecma_strings (left_square_str_p, right_square_str_p);
ret_value = ecma_make_normal_completion_value (ecma_make_string_value (final_str_p));
ecma_deref_ecma_string (left_square_str_p);
ecma_deref_ecma_string (right_square_str_p);
}
/* 10. */
else
{
bool is_gap_empty = (ecma_string_get_length (context_p->gap_str_p) == 0);
/* 10.a */
if (is_gap_empty)
{
ecma_string_t *left_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_SQUARE_CHAR);
ecma_string_t *right_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR);
ret_value = ecma_builtin_helper_json_create_non_formatted_json (left_square_str_p,
right_square_str_p,
&partial);
ecma_deref_ecma_string (left_square_str_p);
ecma_deref_ecma_string (right_square_str_p);
}
/* 10.b */
else
{
ecma_string_t *left_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LEFT_SQUARE_CHAR);
ecma_string_t *right_square_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR);
ret_value = ecma_builtin_helper_json_create_formatted_json (left_square_str_p,
right_square_str_p,
stepback_p,
&partial,
context_p);
ecma_deref_ecma_string (left_square_str_p);
ecma_deref_ecma_string (right_square_str_p);
}
}
}
ECMA_OP_TO_NUMBER_FINALIZE (array_length_num);
ECMA_FINALIZE (array_length);
ecma_deref_ecma_string (length_str_p);
free_list_with_ecma_string_content (&partial);
/* 11. */
list_remove_last_element (&context_p->occurence_stack);
/* 12. */
ecma_deref_ecma_string (context_p->indent_str_p);
context_p->indent_str_p = stepback_p;
/* 13. */
return ret_value;
} /* ecma_builtin_json_array */
/**
* @}
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_JSON_BUILTIN */