/** * The Object object's 'isSealed' routine * * See also: * ECMA-262 v5, 15.2.3.11 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_is_sealed (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); bool is_sealed; // 3. if (ecma_get_object_extensible (obj_p)) { is_sealed = false; } else { /* the value can be updated in the loop below */ is_sealed = true; // 2. ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); // 2.a ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2.b if (ecma_is_property_configurable (property_p)) { is_sealed = false; break; } } ecma_free_values_collection (props_p, true); } // 4. ret_value = ecma_make_simple_completion_value (is_sealed ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } return ret_value; } /* ecma_builtin_object_object_is_sealed */
/** * The Object.keys and Object.getOwnPropertyNames routine's common part. * * See also: * ECMA-262 v5, 15.2.3.4 steps 2-5 * ECMA-262 v5, 15.2.3.14 steps 3-6 * * @return ecma value - Array of property names. * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ bool only_enumerable_properties) /**< list enumerable properties? */ { JERRY_ASSERT (obj_p != NULL); ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); uint32_t index = 0; ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, only_enumerable_properties, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter)) { ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_p, index_string_p, *iter.current_value_p, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (index_string_p); index++; } ecma_free_values_collection (props_p, true); return new_array; } /* ecma_builtin_helper_object_get_properties */
/** * 'for-in' opcode handler * * See also: * ECMA-262 v5, 12.6.4 * * @return completion value * Returned value must be freed with ecma_free_value */ ecma_collection_header_t * opfunc_for_in (ecma_value_t left_value, /**< left value */ ecma_value_t *result_obj_p) /**< expression object */ { ecma_value_t compl_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_collection_header_t *prop_names_p = NULL; /* 3. */ if (!ecma_is_value_undefined (left_value) && !ecma_is_value_null (left_value)) { /* 4. */ ECMA_TRY_CATCH (obj_expr_value, ecma_op_to_object (left_value), compl_val); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); prop_names_p = ecma_op_object_get_property_names (obj_p, false, true, true); if (prop_names_p->unit_number != 0) { ecma_ref_object (obj_p); *result_obj_p = ecma_make_object_value (obj_p); } else { ecma_dealloc_collection_header (prop_names_p); prop_names_p = NULL; } ECMA_FINALIZE (obj_expr_value); } JERRY_ASSERT (ecma_is_value_empty (compl_val)); return prop_names_p; } /* opfunc_for_in */
/** * [[DefineOwnProperty]] ecma array object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 15.4.5.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t *property_desc_p, /**< property descriptor */ bool is_throw) /**< flag that controls failure handling */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); // 1. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_property_t *len_prop_p = ecma_op_object_get_own_property (obj_p, magic_string_length_p); JERRY_ASSERT (len_prop_p != NULL && len_prop_p->type == ECMA_PROPERTY_NAMEDDATA); // 2. ecma_value_t old_len_value = ecma_get_named_data_property_value (len_prop_p); ecma_number_t *num_p = ecma_get_number_from_value (old_len_value); uint32_t old_len_uint32 = ecma_number_to_uint32 (*num_p); // 3. bool is_property_name_equal_length = ecma_compare_ecma_strings (property_name_p, magic_string_length_p); ecma_deref_ecma_string (magic_string_length_p); if (is_property_name_equal_length) { // a. if (!property_desc_p->is_value_defined) { // i. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } ecma_number_t new_len_num; // c. ecma_completion_value_t completion = ecma_op_to_number (property_desc_p->value); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_normal (completion) && ecma_is_value_number (ecma_get_completion_value_value (completion))); new_len_num = *ecma_get_number_from_completion_value (completion); ecma_free_completion_value (completion); uint32_t new_len_uint32 = ecma_number_to_uint32 (new_len_num); // d. if (ecma_uint32_to_number (new_len_uint32) != new_len_num) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_RANGE)); } else { // b., e. ecma_number_t *new_len_num_p = ecma_alloc_number (); *new_len_num_p = new_len_num; ecma_property_descriptor_t new_len_property_desc = *property_desc_p; new_len_property_desc.value = ecma_make_number_value (new_len_num_p); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // f. if (new_len_uint32 >= old_len_uint32) { // i. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ret_value = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); } else { // g. if (!ecma_is_property_writable (len_prop_p)) { ret_value = ecma_reject (is_throw); } else { // h. bool new_writable; if (!new_len_property_desc.is_writable_defined || new_len_property_desc.is_writable) { new_writable = true; } else { // ii. new_writable = false; // iii. new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = true; } // j. magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, is_throw); ecma_deref_ecma_string (magic_string_length_p); /* Handling normal false and throw values */ if (!ecma_is_completion_value_normal_true (succeeded)) { JERRY_ASSERT (ecma_is_completion_value_normal_false (succeeded) || ecma_is_completion_value_throw (succeeded)); // k. ret_value = succeeded; } else { // l JERRY_ASSERT (new_len_uint32 < old_len_uint32); /* * Item i. is replaced with faster iteration: only indices that actually exist in the array, are iterated */ bool is_reduce_succeeded = true; ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false); ecma_length_t array_index_props_num = array_index_props_p->unit_number; MEM_DEFINE_LOCAL_ARRAY (array_index_values_p, array_index_props_num, uint32_t); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, array_index_props_p); uint32_t array_index_values_pos = 0; while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; bool is_index = ecma_string_get_array_index (property_name_p, &index); JERRY_ASSERT (is_index); JERRY_ASSERT (index < old_len_uint32); array_index_values_p[array_index_values_pos++] = index; } JERRY_ASSERT (array_index_values_pos == array_index_props_num); while (array_index_values_pos != 0 && array_index_values_p[--array_index_values_pos] >= new_len_uint32) { uint32_t index = array_index_values_p[array_index_values_pos]; // ii. ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_completion_value_t delete_succeeded = ecma_op_object_delete (obj_p, index_string_p, false); ecma_deref_ecma_string (index_string_p); if (ecma_is_completion_value_normal_false (delete_succeeded)) { // iii. new_len_uint32 = (index + 1u); ecma_number_t *new_len_num_p = ecma_get_number_from_value (new_len_property_desc.value); // 1. *new_len_num_p = ecma_uint32_to_number (index + 1u); // 2. if (!new_writable) { new_len_property_desc.is_writable_defined = true; new_len_property_desc.is_writable = false; } // 3. ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_completion_value_t completion = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &new_len_property_desc, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) || ecma_is_completion_value_normal_false (completion)); is_reduce_succeeded = false; break; } } MEM_FINALIZE_LOCAL_ARRAY (array_index_values_p); ecma_free_values_collection (array_index_props_p, true); if (!is_reduce_succeeded) { ret_value = ecma_reject (is_throw); } else { // m. if (!new_writable) { ecma_property_descriptor_t prop_desc_not_writable = ecma_make_empty_property_descriptor (); prop_desc_not_writable.is_writable_defined = true; prop_desc_not_writable.is_writable = false; ecma_completion_value_t completion_set_not_writable; magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); completion_set_not_writable = ecma_op_general_object_define_own_property (obj_p, magic_string_length_p, &prop_desc_not_writable, false); ecma_deref_ecma_string (magic_string_length_p); JERRY_ASSERT (ecma_is_completion_value_normal_true (completion_set_not_writable)); } ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } } } } ecma_dealloc_number (new_len_num_p); return ret_value; } JERRY_UNREACHABLE (); } else { // 4.a. uint32_t index; if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, is_throw); } // 4. // b. if (index >= old_len_uint32 && !ecma_is_property_writable (len_prop_p)) { return ecma_reject (is_throw); } // c. ecma_completion_value_t succeeded = ecma_op_general_object_define_own_property (obj_p, property_name_p, property_desc_p, false); // d. JERRY_ASSERT (ecma_is_completion_value_normal_true (succeeded) || ecma_is_completion_value_normal_false (succeeded)); if (ecma_is_completion_value_normal_false (succeeded)) { return ecma_reject (is_throw); } // e. if (index >= old_len_uint32) { // i., ii. ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_number_add (ecma_uint32_to_number (index), ECMA_NUMBER_ONE); ecma_named_data_property_assign_value (obj_p, len_prop_p, ecma_make_number_value (num_p)); ecma_dealloc_number (num_p); } // f. return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); } JERRY_UNREACHABLE (); } /* ecma_op_array_object_define_own_property */
/** * 'for-in' opcode handler * * See also: * ECMA-262 v5, 12.6.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_for_in (vm_instr_t instr, /**< instruction */ vm_frame_ctx_t *int_data_p) /**< interpreter context */ { const vm_idx_t expr_idx = instr.data.for_in.expr; const vm_idx_t block_end_oc_idx_1 = instr.data.for_in.oc_idx_1; const vm_idx_t block_end_oc_idx_2 = instr.data.for_in.oc_idx_2; const vm_instr_counter_t for_in_end_oc = (vm_instr_counter_t) ( vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + int_data_p->pos); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1., 2. */ ECMA_TRY_CATCH (expr_value, get_variable_value (int_data_p, expr_idx, false), ret_value); int_data_p->pos++; vm_instr_t meta_instr = vm_get_instr (int_data_p->bytecode_header_p->instrs_p, for_in_end_oc); JERRY_ASSERT (meta_instr.op_idx == VM_OP_META); JERRY_ASSERT (meta_instr.data.meta.type == OPCODE_META_TYPE_END_FOR_IN); /* 3. */ if (!ecma_is_value_undefined (expr_value) && !ecma_is_value_null (expr_value)) { /* 4. */ ECMA_TRY_CATCH (obj_expr_value, ecma_op_to_object (expr_value), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); ecma_collection_iterator_t names_iterator; ecma_collection_header_t *names_p = ecma_op_object_get_property_names (obj_p, false, true, true); if (names_p != NULL) { ecma_collection_iterator_init (&names_iterator, names_p); const vm_instr_counter_t for_in_body_begin_oc = int_data_p->pos; const vm_instr_counter_t for_in_body_end_oc = for_in_end_oc; while (ecma_collection_iterator_next (&names_iterator)) { ecma_value_t name_value = *names_iterator.current_value_p; ecma_string_t *name_p = ecma_get_string_from_value (name_value); if (ecma_op_object_get_property (obj_p, name_p) != NULL) { ecma_completion_value_t completion = set_variable_value (int_data_p, int_data_p->pos, VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME, name_value); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); vm_run_scope_t run_scope_for_in = { for_in_body_begin_oc, for_in_body_end_oc }; ecma_completion_value_t for_in_body_completion = vm_loop (int_data_p, &run_scope_for_in); if (ecma_is_completion_value_empty (for_in_body_completion)) { JERRY_ASSERT (int_data_p->pos == for_in_body_end_oc); int_data_p->pos = for_in_body_begin_oc; } else { JERRY_ASSERT (ecma_is_completion_value_throw (for_in_body_completion) || ecma_is_completion_value_return (for_in_body_completion) || ecma_is_completion_value_jump (for_in_body_completion)); JERRY_ASSERT (int_data_p->pos <= for_in_body_end_oc); ret_value = for_in_body_completion; break; } } } ecma_free_values_collection (names_p, true); } ECMA_FINALIZE (obj_expr_value); } int_data_p->pos = (vm_instr_counter_t) (for_in_end_oc + 1u); ECMA_FINALIZE (expr_value); return ret_value; } /* opfunc_for_in */
/** * The Object object's 'defineProperties' routine * * See also: * ECMA-262 v5, 15.2.3.7 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg1, /**< routine's first argument */ ecma_value_t arg2) /**< routine's second argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg1)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg1); // 2. ECMA_TRY_CATCH (props, ecma_op_to_object (arg2), ret_value); ecma_object_t *props_p = ecma_get_object_from_value (props); // 3. ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); uint32_t property_number = prop_names_p->unit_number; ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, prop_names_p); // 4. MEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); uint32_t property_descriptor_number = 0; while (ecma_collection_iterator_next (&iter) && ecma_is_completion_value_empty (ret_value)) { // 5.a ECMA_TRY_CATCH (desc_obj, ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), ret_value); // 5.b ECMA_TRY_CATCH (conv_result, ecma_op_to_property_descriptor (desc_obj, &property_descriptors[property_descriptor_number]), ret_value); property_descriptor_number++; ECMA_FINALIZE (conv_result); ECMA_FINALIZE (desc_obj); } // 6. ecma_collection_iterator_init (&iter, prop_names_p); for (uint32_t index = 0; index < property_number && ecma_is_completion_value_empty (ret_value); index++) { bool is_next = ecma_collection_iterator_next (&iter); JERRY_ASSERT (is_next); ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, ecma_get_string_from_value (*iter.current_value_p), &property_descriptors[index], true), ret_value); ECMA_FINALIZE (define_own_prop_ret); } // Clean up for (uint32_t index = 0; index < property_descriptor_number; index++) { ecma_free_property_descriptor (&property_descriptors[index]); } MEM_FINALIZE_LOCAL_ARRAY (property_descriptors); ecma_free_values_collection (prop_names_p, true); // 7. if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg1, true)); } ECMA_FINALIZE (props); } return ret_value; } /* ecma_builtin_object_object_define_properties */
/** * The Object object's 'isFrozen' routine * * See also: * ECMA-262 v5, 15.2.3.12 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_is_frozen (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); bool is_frozen; // 3. if (ecma_get_object_extensible (obj_p)) { is_frozen = false; } else { is_frozen = true; // 2. ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); // 2.a ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); // 2.b if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) { is_frozen = false; break; } // 2.c if (ecma_is_property_configurable (property_p)) { is_frozen = false; break; } } ecma_free_values_collection (props_p, true); } // 4. ret_value = ecma_make_simple_completion_value (is_frozen ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } return ret_value; } /* ecma_builtin_object_object_is_frozen */
/** * The Object object's 'freeze' routine * * See also: * ECMA-262 v5, 15.2.3.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); // 1. if (!ecma_is_value_object (arg)) { ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { // 2. ecma_object_t *obj_p = ecma_get_object_from_value (arg); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter) && ecma_is_completion_value_empty (ret_value)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2.a ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p); // 2.b if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) { prop_desc.is_writable = false; } // 2.c if (ecma_is_property_configurable (property_p)) { prop_desc.is_configurable = false; } // 2.d ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, property_name_p, &prop_desc, true), ret_value); ECMA_FINALIZE (define_own_prop_ret); ecma_free_property_descriptor (&prop_desc); } ecma_free_values_collection (props_p, true); if (ecma_is_completion_value_empty (ret_value)) { // 3. ecma_set_object_extensible (obj_p, false); // 4. ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true)); } } return ret_value; } /* ecma_builtin_object_object_freeze */
/** * Abstract operation Walk defined in 15.12.2 * * See also: * ECMA-262 v5, 15.12.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_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_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); 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); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, false, true, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter) && ecma_is_value_empty (ret_value)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); ECMA_TRY_CATCH (value_walk, ecma_builtin_json_walk (reviver_p, object_p, property_name_p), 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_value_t delete_val = ecma_op_general_object_delete (object_p, property_name_p, false); JERRY_ASSERT (ecma_is_value_boolean (delete_val)); } else { ecma_builtin_json_define_value_property (object_p, property_name_p, value_walk); } ECMA_FINALIZE (value_walk); } ecma_free_values_collection (props_p, true); } if (ecma_is_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_value_error (ret_value)); } ECMA_FINALIZE (value_get); return ret_value; } /* ecma_builtin_json_walk */
/** * Abstract operation 'JO' defined in 15.12.3 * * See also: * ECMA-262 v5, 15.12.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { ecma_value_t obj_value = ecma_make_object_value (obj_p); /* 1. */ if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) { return ecma_raise_type_error (""); } ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 2. */ ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); /* 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); ecma_collection_header_t *property_keys_p; /* 5. */ if (context_p->property_list_p->unit_number > 0) { property_keys_p = context_p->property_list_p; } /* 6. */ else { property_keys_p = ecma_new_values_collection (NULL, 0, true); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, false); ecma_collection_iterator_t iter; ecma_collection_iterator_init (&iter, props_p); while (ecma_collection_iterator_next (&iter)) { ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); JERRY_ASSERT (ecma_is_property_enumerable (property_p)); if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true); } } ecma_free_values_collection (props_p, true); } /* 7. */ ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true); /* 8. */ ecma_collection_iterator_t iterator; ecma_collection_iterator_init (&iterator, property_keys_p); while (ecma_collection_iterator_next (&iterator) && ecma_is_value_empty (ret_value)) { ecma_value_t value = *iterator.current_value_p; ecma_string_t *key_p = ecma_get_string_from_value (value); /* 8.a */ ECMA_TRY_CATCH (str_val, ecma_builtin_json_str (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_value_t str_comp_val = ecma_builtin_json_quote (key_p); JERRY_ASSERT (!ecma_is_value_error (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_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 */ ecma_value_t member_value = ecma_make_string_value (member_str_p); ecma_append_to_values_collection (partial_p, member_value, true); ecma_deref_ecma_string (member_str_p); } ECMA_FINALIZE (str_val); } if (context_p->property_list_p->unit_number == 0) { ecma_free_values_collection (property_keys_p, true); } if (!ecma_is_value_empty (ret_value)) { ecma_free_values_collection (partial_p, true); ecma_deref_ecma_string (stepback_p); return ret_value; } /* 9. */ if (partial_p->unit_number == 0) { 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_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_p); 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_p, context_p); ecma_deref_ecma_string (left_brace_str_p); ecma_deref_ecma_string (right_brace_str_p); } } ecma_free_values_collection (partial_p, true); /* 11. */ ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); /* 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 */