/** * Relation opcode handler. * * See also: ECMA-262 v5, 11.8.1, 11.8.2, 11.8.3, 11.8.4 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t opfunc_relation (ecma_value_t left_value, /**< left value */ ecma_value_t right_value, /**< right value */ bool left_first, /**< 'LeftFirst' flag */ bool is_invert) /**< is invert */ { JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value)); ecma_value_t ret_value = ecma_op_abstract_relational_compare (left_value, right_value, left_first); if (ECMA_IS_VALUE_ERROR (ret_value)) { return ret_value; } if (ecma_is_value_undefined (ret_value)) { ret_value = ECMA_VALUE_FALSE; } else { JERRY_ASSERT (ecma_is_value_boolean (ret_value)); if (is_invert) { ret_value = ecma_invert_boolean_value (ret_value); } } return ret_value; } /* opfunc_relation */
/** * ToObject operation. * * See also: * ECMA-262 v5, 9.9 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_to_object (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_op_create_number_object (value); } else if (ecma_is_value_string (value)) { return ecma_op_create_string_object (&value, 1); } else if (ecma_is_value_object (value)) { return ecma_copy_value (value); } else { if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { return ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); return ecma_op_create_boolean_object (value); } } } /* ecma_op_to_object */
/** * CreateIterResultObject operation * * See also: * ECMA-262 v6, 7.4.7. * * Note: * Returned value must be freed with ecma_free_value. * * @return iterator result object */ ecma_value_t ecma_create_iter_result_object (ecma_value_t value, /**< value */ ecma_value_t done) /**< ECMA_VALUE_{TRUE,FALSE} based * on the iterator index */ { /* 1. */ JERRY_ASSERT (ecma_is_value_boolean (done)); /* 2. */ ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), 0, ECMA_OBJECT_TYPE_GENERAL); /* 3. */ ecma_property_value_t *prop_value_p; prop_value_p = ecma_create_named_data_property (object_p, ecma_get_magic_string (LIT_MAGIC_STRING_VALUE), ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); prop_value_p->value = ecma_copy_value_if_not_object (value); /* 4. */ prop_value_p = ecma_create_named_data_property (object_p, ecma_get_magic_string (LIT_MAGIC_STRING_DONE), ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); prop_value_p->value = done; /* 5. */ return ecma_make_object_value (object_p); } /* ecma_create_iter_result_object */
/** * 'Greater-than' opcode handler. * * See also: ECMA-262 v5, 11.8.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t opfunc_greater_than (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value)); ecma_value_t ret_value = ecma_op_abstract_relational_compare (left_value, right_value, false); if (ECMA_IS_VALUE_ERROR (ret_value)) { return ret_value; } if (ecma_is_value_undefined (ret_value)) { ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); } else { JERRY_ASSERT (ecma_is_value_boolean (ret_value)); } return ret_value; } /* opfunc_greater_than */
/** * The Boolean.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.6.4.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_boolean_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (value_of_ret, ecma_builtin_boolean_prototype_object_value_of (this_arg), ret_value); ecma_string_t *ret_str_p; if (ecma_is_value_true (value_of_ret)) { ret_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_TRUE); } else { JERRY_ASSERT (ecma_is_value_boolean (value_of_ret)); ret_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_FALSE); } ret_value = ecma_make_string_value (ret_str_p); ECMA_FINALIZE (value_of_ret); return ret_value; } /* ecma_builtin_boolean_prototype_object_to_string */
/** * ToObject operation. * * See also: * ECMA-262 v5, 9.9 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_object (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_op_create_number_object (value); } else if (ecma_is_value_string (value)) { return ecma_op_create_string_object (&value, 1); } else if (ecma_is_value_object (value)) { return ecma_make_normal_completion_value (ecma_copy_value (value, true)); } else { if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE)); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); return ecma_op_create_boolean_object (value); } } } /* ecma_op_to_object */
/** * 'Does-not-equals' opcode handler. * * See also: ECMA-262 v5, 11.9.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_not_equal_value (vm_instr_t instr, /**< instruction */ vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */ { const idx_t dst_var_idx = instr.data.not_equal_value.dst; const idx_t left_var_idx = instr.data.not_equal_value.var_left; const idx_t right_var_idx = instr.data.not_equal_value.var_right; //ilyushin printf("not_equal_value,"); //ilyushin ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value); ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value); ECMA_TRY_CATCH (compare_result, ecma_op_abstract_equality_compare (left_value, right_value), ret_value); JERRY_ASSERT (ecma_is_value_boolean (compare_result)); bool is_equal = ecma_is_value_true (compare_result); ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE : ECMA_SIMPLE_VALUE_TRUE)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); frame_ctx_p->pos++; return ret_value; } /* opfunc_not_equal_value */
/** * ToString operation. * * See also: * ECMA-262 v5, 9.8 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_string (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (unlikely (ecma_is_value_object (value))) { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (prim_value, ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_STRING), ret_value); ret_value = ecma_op_to_string (prim_value); ECMA_FINALIZE (prim_value); return ret_value; } else { ecma_string_t *res_p = NULL; if (ecma_is_value_string (value)) { res_p = ecma_get_string_from_value (value); res_p = ecma_copy_or_ref_ecma_string (res_p); } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); res_p = ecma_new_ecma_string_from_number (*num_p); } else if (ecma_is_value_undefined (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED); } else if (ecma_is_value_null (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL); } else { JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_TRUE); } else { res_p = ecma_get_magic_string (LIT_MAGIC_STRING_FALSE); } } return ecma_make_normal_completion_value (ecma_make_string_value (res_p)); } } /* ecma_op_to_string */
/** * Debug assertion that specified value's type is one of ECMA-defined * script-visible types, i.e.: undefined, null, boolean, number, string, object. */ void ecma_check_value_type_is_spec_defined (ecma_value_t value) /**< ecma value */ { JERRY_ASSERT (ecma_is_value_undefined (value) || ecma_is_value_null (value) || ecma_is_value_boolean (value) || ecma_is_value_number (value) || ecma_is_value_string (value) || ecma_is_value_object (value)); } /* ecma_check_value_type_is_spec_defined */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; if (is_deletable) { prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_CONFIGURABLE); } ecma_create_named_data_property (lex_env_p, name_p, prop_attributes, NULL); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion; if (!ecma_get_object_extensible (binding_obj_p)) { return ECMA_VALUE_EMPTY; } completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ECMA_VALUE_UNDEFINED, is_deletable ? ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE : ECMA_PROPERTY_ENUMERABLE_WRITABLE, true); /* Failure handling */ if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ECMA_VALUE_EMPTY; } /* ecma_op_create_mutable_binding */
/** * ToBoolean operation. * * See also: * ECMA-262 v5, 9.2 * * @return completion value * Returned value is simple and so need not be freed. * However, ecma_free_completion_value may be called for it, but it is a no-op. */ ecma_completion_value_t ecma_op_to_boolean (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); ecma_simple_value_t ret_value; if (ecma_is_value_boolean (value)) { ret_value = (ecma_is_value_true (value) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } else if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); if (ecma_number_is_nan (*num_p) || ecma_number_is_zero (*num_p)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); if (ecma_string_get_length (str_p) == 0) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else { JERRY_ASSERT (ecma_is_value_object (value)); ret_value = ECMA_SIMPLE_VALUE_TRUE; } return ecma_make_simple_completion_value (ret_value); } /* ecma_op_to_boolean */
/** * Equality opcode handler. * * See also: ECMA-262 v5, 11.9.1, 11.9.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t opfunc_equality (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (left_value) && !ECMA_IS_VALUE_ERROR (right_value)); ecma_value_t compare_result = ecma_op_abstract_equality_compare (left_value, right_value); JERRY_ASSERT (ecma_is_value_boolean (compare_result) || ECMA_IS_VALUE_ERROR (compare_result)); return compare_result; } /* opfunc_equality */
/** * The Boolean.prototype object's 'valueOf' routine * * See also: * ECMA-262 v5, 15.6.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_boolean_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */ { if (ecma_is_value_boolean (this_arg)) { return this_arg; } else if (ecma_is_value_object (this_arg)) { ecma_object_t *obj_p = ecma_get_object_from_value (this_arg); if (ecma_object_get_class_name (obj_p) == LIT_MAGIC_STRING_BOOLEAN_UL) { ecma_property_t *prim_value_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); JERRY_ASSERT (ecma_is_value_boolean (ecma_get_internal_property_value (prim_value_prop_p))); return ecma_get_internal_property_value (prim_value_prop_p); } } return ecma_raise_type_error (ECMA_ERR_MSG ("")); } /* ecma_builtin_boolean_prototype_object_value_of */
/** * 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_value_t completion_value = ecma_builtin_helper_def_prop (obj_p, property_name_p, value, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_boolean (completion_value)); } /* ecma_builtin_json_define_value_property */
/** * 'Greater-than-or-equal' opcode handler. * * See also: ECMA-262 v5, 11.8.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */ vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */ { const idx_t dst_var_idx = instr.data.greater_or_equal_than.dst; const idx_t left_var_idx = instr.data.greater_or_equal_than.var_left; const idx_t right_var_idx = instr.data.greater_or_equal_than.var_right; //ilyushin printf("greater_or_equal_than,"); //ilyushin ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value); ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value); ECMA_TRY_CATCH (compare_result, ecma_op_abstract_relational_compare (left_value, right_value, true), ret_value); ecma_simple_value_t res; if (ecma_is_value_undefined (compare_result)) { res = ECMA_SIMPLE_VALUE_FALSE; } else { JERRY_ASSERT (ecma_is_value_boolean (compare_result)); if (ecma_is_value_true (compare_result)) { res = ECMA_SIMPLE_VALUE_FALSE; } else { res = ECMA_SIMPLE_VALUE_TRUE; } } ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); frame_ctx_p->pos++; return ret_value; } /* opfunc_greater_or_equal_than */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); if (ecma_is_property_writable (*property_p)) { ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value); } else if (is_strict) { return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set.")); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ECMA_IS_VALUE_ERROR (completion)) { return completion; } JERRY_ASSERT (ecma_is_value_boolean (completion)); } return ECMA_VALUE_EMPTY; } /* ecma_op_set_mutable_binding */
/** * SetMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ ecma_value_t value, /**< argument V */ bool is_strict) /**< argument S */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_property_t *property_p = ecma_get_named_data_property (lex_env_p, name_p); if (ecma_is_property_writable (property_p)) { ecma_named_data_property_assign_value (lex_env_p, property_p, value); } else if (is_strict) { return ecma_raise_type_error (""); } } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, value, is_strict); if (ecma_is_value_error (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } /* ecma_op_set_mutable_binding */
/** * 'Greater-than-or-equal' opcode handler. * * See also: ECMA-262 v5, 11.8.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_greater_or_equal_than (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { const idx_t dst_var_idx = opdata.data.greater_or_equal_than.dst; const idx_t left_var_idx = opdata.data.greater_or_equal_than.var_left; const idx_t right_var_idx = opdata.data.greater_or_equal_than.var_right; ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (left_value, get_variable_value (int_data, left_var_idx, false), ret_value); ECMA_TRY_CATCH (right_value, get_variable_value (int_data, right_var_idx, false), ret_value); ECMA_TRY_CATCH (compare_result, ecma_op_abstract_relational_compare (left_value, right_value, true), ret_value); ecma_simple_value_t res; if (ecma_is_value_undefined (compare_result)) { res = ECMA_SIMPLE_VALUE_FALSE; } else { JERRY_ASSERT (ecma_is_value_boolean (compare_result)); if (ecma_is_value_true (compare_result)) { res = ECMA_SIMPLE_VALUE_FALSE; } else { res = ECMA_SIMPLE_VALUE_TRUE; } } ret_value = set_variable_value (int_data, int_data->pos, dst_var_idx, ecma_make_simple_value (res)); ECMA_FINALIZE (compare_result); ECMA_FINALIZE (right_value); ECMA_FINALIZE (left_value); int_data->pos++; return ret_value; } /* opfunc_greater_or_equal_than */
/** * 'typeof' opcode handler. * * See also: ECMA-262 v5, 11.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t opfunc_typeof (ecma_value_t left_value) /**< left value */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_string_t *type_str_p = NULL; if (ecma_is_value_undefined (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED); } else if (ecma_is_value_null (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); } else if (ecma_is_value_boolean (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BOOLEAN); } else if (ecma_is_value_number (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NUMBER); } else if (ecma_is_value_string (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_STRING); } else { JERRY_ASSERT (ecma_is_value_object (left_value)); if (ecma_op_is_callable (left_value)) { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_FUNCTION); } else { type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); } } ret_value = ecma_make_string_value (type_str_p); return ret_value; } /* opfunc_typeof */
/** * PutValue operation part (lexical environment base or unresolvable reference). * * See also: ECMA-262 v5, 8.7.2, sections 3 and 5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_put_value_lex_env_base (ecma_object_t *ref_base_lex_env_p, /**< reference's base (lexical environment) */ ecma_string_t *var_name_string_p, /**< variable name */ bool is_strict, /**< flag indicating strict mode */ ecma_value_t value) /**< ECMA-value */ { const bool is_unresolvable_reference = (ref_base_lex_env_p == NULL); // 3. if (unlikely (is_unresolvable_reference)) { // 3.a. if (is_strict) { return ecma_raise_reference_error (""); } else { // 3.b. ecma_object_t *global_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); ecma_value_t completion = ecma_op_object_put (global_object_p, var_name_string_p, value, false); ecma_deref_object (global_object_p); JERRY_ASSERT (ecma_is_value_boolean (completion)); return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } } // 5. JERRY_ASSERT (ref_base_lex_env_p != NULL && ecma_is_lexical_environment (ref_base_lex_env_p)); // 5.a return ecma_op_set_mutable_binding (ref_base_lex_env_p, var_name_string_p, value, is_strict); } /* ecma_op_put_value_lex_env_base */
/** * [[Delete]] ecma Arguments object's operation * * See also: * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 * ECMA-262 v5, 10.6 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_arguments_object_delete (ecma_object_t *obj_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ bool is_throw) /**< flag that controls failure handling */ { // 1. ecma_property_t *map_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP); ecma_object_t *map_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, map_prop_p->u.internal_property.value); // 2. ecma_property_t *mapped_prop_p = ecma_op_object_get_own_property (map_p, property_name_p); // 3. ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (delete_in_args_ret, ecma_op_general_object_delete (obj_p, property_name_p, is_throw), ret_value); if (ecma_is_value_true (delete_in_args_ret)) { if (mapped_prop_p != NULL) { ecma_value_t delete_in_map_completion = ecma_op_object_delete (map_p, property_name_p, false); JERRY_ASSERT (ecma_is_value_true (delete_in_map_completion)); } ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); } else { JERRY_ASSERT (ecma_is_value_boolean (delete_in_args_ret)); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); } ECMA_FINALIZE (delete_in_args_ret); return ret_value; } /* ecma_op_arguments_object_delete */
/** * CreateMutableBinding operation. * * See also: ECMA-262 v5, 10.2.1 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { JERRY_ASSERT (lex_env_p != NULL && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { ecma_create_named_data_property (lex_env_p, name_p, true, false, is_deletable); } else { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_value_t completion; completion = ecma_builtin_helper_def_prop (binding_obj_p, name_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true, /* Writable */ true, /* Enumerable */ is_deletable, /* Configurable */ true); /* Failure handling */ if (ecma_is_value_error (completion)) { return completion; } else { JERRY_ASSERT (ecma_is_value_boolean (completion)); } } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); } /* ecma_op_create_mutable_binding */
/** * ToBoolean operation. Cannot throw an exception. * * See also: * ECMA-262 v5, 9.2 * * @return true if the logical value is true * false otherwise */ bool ecma_op_to_boolean (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_simple (value)) { JERRY_ASSERT (ecma_is_value_boolean (value) || ecma_is_value_undefined (value) || ecma_is_value_null (value)); return ecma_is_value_true (value); } if (ecma_is_value_integer_number (value)) { return (value != ecma_make_integer_value (0)); } if (ecma_is_value_float_number (value)) { ecma_number_t num = ecma_get_float_from_value (value); return (!ecma_number_is_nan (num) && !ecma_number_is_zero (num)); } if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_string_get_length (str_p) != 0; } JERRY_ASSERT (ecma_is_value_object (value)); return true; } /* ecma_op_to_boolean */
/** * 'Object' object creation operation with one argument. * * See also: ECMA-262 v5, 15.2.2.1 * * @return pointer to newly created 'Object' object */ ecma_completion_value_t ecma_op_create_object_object_arg (ecma_value_t value) /**< argument of constructor */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_object (value) || ecma_is_value_number (value) || ecma_is_value_string (value) || ecma_is_value_boolean (value)) { // 1.b, 1.c, 1.d return ecma_op_to_object (value); } else { // 2. JERRY_ASSERT (ecma_is_value_undefined (value) || ecma_is_value_null (value)); ecma_object_t *obj_p = ecma_op_create_object_object_noarg (); return ecma_make_normal_completion_value (ecma_make_object_value (obj_p)); } } /* ecma_op_create_object_object_arg */
/** * The Function.prototype object's 'bind' routine * * See also: * ECMA-262 v5, 15.3.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */ const ecma_value_t *arguments_list_p, /**< list of arguments */ ecma_length_t arguments_number) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 2. */ if (!ecma_op_is_callable (this_arg)) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("")); } else { /* 4. 11. 18. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *function_p = ecma_create_object (prototype_obj_p, false, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION); ecma_deref_object (prototype_obj_p); /* 7. */ ecma_value_t *target_function_prop_p; target_function_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION); ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); ECMA_SET_INTERNAL_VALUE_POINTER (*target_function_prop_p, this_arg_obj_p); /* 8. */ ecma_value_t *bound_this_prop_p; bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS); const ecma_length_t arg_count = arguments_number; if (arg_count > 0) { *bound_this_prop_p = ecma_copy_value_if_not_object (arguments_list_p[0]); } else { *bound_this_prop_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } if (arg_count > 1) { ecma_collection_header_t *bound_args_collection_p; bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false); ecma_value_t *bound_args_prop_p; bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS); ECMA_SET_INTERNAL_VALUE_POINTER (*bound_args_prop_p, bound_args_collection_p); } /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * * See also: ecma_object_get_class_name */ /* 16. */ ecma_number_t length = ECMA_NUMBER_ZERO; ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string (); /* 15. */ if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL) { ecma_value_t get_len_value = ecma_op_object_get (this_arg_obj_p, magic_string_length_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value)); JERRY_ASSERT (ecma_is_value_number (get_len_value)); const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0; /* 15.a */ length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) bound_arg_count); ecma_free_value (get_len_value); /* 15.b */ if (ecma_number_is_negative (length)) { length = ECMA_NUMBER_ZERO; } } /* 17. */ ecma_value_t completion = ecma_builtin_helper_def_prop (function_p, magic_string_length_p, ecma_make_number_value (length), false, /* Writable */ false, /* Enumerable */ false, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_length_p); /* 19-21. */ ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = false; prop_desc.is_get_defined = true; prop_desc.get_p = thrower_p; prop_desc.is_set_defined = true; prop_desc.set_p = thrower_p; } ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (function_p, magic_string_caller_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_caller_p); ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); completion = ecma_op_object_define_own_property (function_p, magic_string_arguments_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_boolean (completion)); ecma_deref_ecma_string (magic_string_arguments_p); ecma_deref_object (thrower_p); /* 22. */ ret_value = ecma_make_object_value (function_p); } return ret_value; } /* ecma_builtin_function_prototype_object_bind */
/** * GetValue operation part (object base). * * See also: ECMA-262 v5, 8.7.1, section 4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_get_value_object_base (ecma_reference_t ref) /**< ECMA-reference */ { const ecma_value_t base = ref.base; const bool is_unresolvable_reference = ecma_is_value_undefined (base); const bool has_primitive_base = (ecma_is_value_boolean (base) || ecma_is_value_number (base) || ecma_is_value_string (base)); const bool has_object_base = (ecma_is_value_object (base) && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); const bool is_property_reference = has_primitive_base || has_object_base; JERRY_ASSERT (!is_unresolvable_reference); JERRY_ASSERT (is_property_reference); ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp); // 4.a if (!has_primitive_base) { // 4.b case 1 ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); return ecma_op_object_get (obj_p, referenced_name_p); } else { // 4.b case 2 ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // 1. ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); // 2. ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); if (prop_p == NULL) { // 3. ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else if (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA) { // 4. ret_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p), true); } else { // 5. JERRY_ASSERT (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR); ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); // 6. if (obj_p == NULL) { ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { // 7. ret_value = ecma_op_function_call (obj_p, base, NULL, 0); } } ECMA_FINALIZE (obj_base); return ret_value; } } /* ecma_op_get_value_object_base */
/** * PutValue operation part (object base). * * See also: ECMA-262 v5, 8.7.2, section 4 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_put_value_object_base (ecma_reference_t ref, /**< ECMA-reference */ ecma_value_t value) /**< ECMA-value */ { const ecma_value_t base = ref.base; const bool is_unresolvable_reference = ecma_is_value_undefined (base); const bool has_primitive_base = (ecma_is_value_boolean (base) || ecma_is_value_number (base) || ecma_is_value_string (base)); const bool has_object_base = (ecma_is_value_object (base) && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); const bool is_property_reference = has_primitive_base || has_object_base; JERRY_ASSERT (!is_unresolvable_reference); JERRY_ASSERT (is_property_reference); // 4.a if (!has_primitive_base) { // 4.b case 1 ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (put_ret_value, ecma_op_object_put (obj_p, ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp), value, ref.is_strict), ret_value); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_FINALIZE (put_ret_value); return ret_value; } else { // 4.b case 2 ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); // sub_1. ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, ref.referenced_name_cp); // sub_2. if (!ecma_op_object_can_put (obj_p, referenced_name_p)) { ret_value = ecma_reject_put (ref.is_strict); } else { // sub_3. ecma_property_t *own_prop_p = ecma_op_object_get_own_property (obj_p, referenced_name_p); // sub_5. ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); // sub_4., sub_7 if ((own_prop_p != NULL && (own_prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDDATA)) || (prop_p == NULL) || !(prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR)) { ret_value = ecma_reject_put (ref.is_strict); } else { // sub_6. JERRY_ASSERT (prop_p != NULL && (prop_p->flags & ECMA_PROPERTY_FLAG_NAMEDACCESSOR)); ecma_object_t *setter_p = ecma_get_named_accessor_property_setter (prop_p); JERRY_ASSERT (setter_p != NULL); ECMA_TRY_CATCH (call_ret, ecma_op_function_call (setter_p, base, &value, 1), ret_value); ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_FINALIZE (call_ret); } } ECMA_FINALIZE (obj_base); return ret_value; } } /* ecma_op_put_value_object_base */
/** * ECMA strict equality comparison routine. * * See also: ECMA-262 v5, 11.9.6 * * @return true - if values are strict equal, * false - otherwise */ bool ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (ecma_is_value_direct (x) || ecma_is_value_direct (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (x) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_object (x) || ecma_is_value_object (y)) { JERRY_ASSERT (!ecma_is_value_direct (x) || ecma_is_value_undefined (x) || ecma_is_value_null (x) || ecma_is_value_boolean (x) || ecma_is_value_integer_number (x)); JERRY_ASSERT (!ecma_is_value_direct (y) || ecma_is_value_undefined (y) || ecma_is_value_null (y) || ecma_is_value_boolean (y) || ecma_is_value_integer_number (y)); if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) { return (x == y); } /* The +0 === -0 case handled below. */ } JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); if (ecma_is_value_string (x)) { if (!ecma_is_value_string (y)) { return false; } ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (!ecma_is_value_number (y)) { return false; } ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return is_x_equal_to_y; } /* ecma_op_strict_equality_compare */
/** * Recursive function for RegExp matching. Tests for a regular expression * match and returns a MatchResult value. * * See also: * ECMA-262 v5, 15.10.2.1 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ static ecma_completion_value_t re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */ re_bytecode_t *bc_p, /**< pointer to the current RegExp bytecode */ lit_utf8_iterator_t iter, /**< input string iterator */ lit_utf8_iterator_t *out_iter_p) /**< Output: matching substring iterator */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); re_opcode_t op; while ((op = re_get_opcode (&bc_p))) { switch (op) { case RE_OP_MATCH: { JERRY_DDLOG ("Execute RE_OP_MATCH: match\n"); *out_iter_p = iter; ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); return ret_value; /* match */ } case RE_OP_CHAR: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t ch1 = (ecma_char_t) re_get_value (&bc_p); /* Already canonicalized. */ ecma_char_t ch2 = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); JERRY_DDLOG ("Character matching %d to %d: ", ch1, ch2); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_PERIOD: { if (lit_utf8_iterator_is_eos (&iter)) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ecma_char_t ch = lit_utf8_iterator_read_next (&iter); JERRY_DDLOG ("Period matching '.' to %d: ", (uint32_t) ch); if (lit_char_is_line_terminator (ch)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_ASSERT_START: { JERRY_DDLOG ("Execute RE_OP_ASSERT_START: "); if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { JERRY_DDLOG ("match\n"); break; } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_prev (&iter))) { JERRY_DDLOG ("match\n"); break; } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_END: { JERRY_DDLOG ("Execute RE_OP_ASSERT_END: "); if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } if (!(re_ctx_p->flags & RE_FLAG_MULTILINE)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } if (lit_char_is_line_terminator (lit_utf8_iterator_peek_next (&iter))) { JERRY_DDLOG ("match\n"); break; /* tail merge */ } JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_ASSERT_WORD_BOUNDARY: case RE_OP_ASSERT_NOT_WORD_BOUNDARY: { bool is_wordchar_left, is_wordchar_right; if ((iter.buf_p + iter.buf_pos.offset) <= re_ctx_p->input_start_p) { is_wordchar_left = false; /* not a wordchar */ } else { is_wordchar_left = lit_char_is_word_char (lit_utf8_iterator_peek_prev (&iter)); } if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { is_wordchar_right = false; /* not a wordchar */ } else { is_wordchar_right = lit_char_is_word_char (lit_utf8_iterator_peek_next (&iter)); } if (op == RE_OP_ASSERT_WORD_BOUNDARY) { JERRY_DDLOG ("Execute RE_OP_ASSERT_WORD_BOUNDARY: "); if (is_wordchar_left == is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_ASSERT_NOT_WORD_BOUNDARY); JERRY_DDLOG ("Execute RE_OP_ASSERT_NOT_WORD_BOUNDARY: "); if (is_wordchar_left != is_wordchar_right) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_LOOKAHEAD_POS: case RE_OP_LOOKAHEAD_NEG: { ecma_completion_value_t match_value = ecma_make_empty_completion_value (); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); uint32_t array_size = re_ctx_p->num_of_captures + re_ctx_p->num_of_non_captures; MEM_DEFINE_LOCAL_ARRAY (saved_bck_p, array_size, lit_utf8_iterator_t); size_t size = (size_t) (array_size) * sizeof (lit_utf8_iterator_t); memcpy (saved_bck_p, re_ctx_p->saved_p, size); do { uint32_t offset = re_get_value (&bc_p); if (!sub_iter.buf_p) { match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_completion_value_throw (match_value)) { break; } } bc_p += offset; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); if (!ecma_is_completion_value_throw (match_value)) { JERRY_DDLOG ("Execute RE_OP_LOOKAHEAD_POS/NEG: "); ecma_free_completion_value (match_value); if ((op == RE_OP_LOOKAHEAD_POS && sub_iter.buf_p) || (op == RE_OP_LOOKAHEAD_NEG && !sub_iter.buf_p)) { JERRY_DDLOG ("match\n"); match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); } else { JERRY_DDLOG ("fail\n"); match_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } if (!ecma_is_completion_value_throw (match_value)) { if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; } else { JERRY_ASSERT (ecma_is_value_boolean (match_value)); /* restore saved */ memcpy (re_ctx_p->saved_p, saved_bck_p, size); } } MEM_FINALIZE_LOCAL_ARRAY (saved_bck_p); return match_value; } case RE_OP_CHAR_CLASS: case RE_OP_INV_CHAR_CLASS: { uint32_t num_of_ranges; bool is_match; JERRY_DDLOG ("Execute RE_OP_CHAR_CLASS/RE_OP_INV_CHAR_CLASS, "); if (lit_utf8_iterator_is_eos (&iter)) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } bool is_ignorecase = re_ctx_p->flags & RE_FLAG_IGNORE_CASE; ecma_char_t curr_ch = re_canonicalize (lit_utf8_iterator_read_next (&iter), is_ignorecase); num_of_ranges = re_get_value (&bc_p); is_match = false; while (num_of_ranges) { ecma_char_t ch1 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); ecma_char_t ch2 = re_canonicalize ((ecma_char_t) re_get_value (&bc_p), is_ignorecase); JERRY_DDLOG ("num_of_ranges=%d, ch1=%d, ch2=%d, curr_ch=%d; ", num_of_ranges, ch1, ch2, curr_ch); if (curr_ch >= ch1 && curr_ch <= ch2) { /* We must read all the ranges from bytecode. */ is_match = true; } num_of_ranges--; } if (op == RE_OP_CHAR_CLASS) { if (!is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } else { JERRY_ASSERT (op == RE_OP_INV_CHAR_CLASS); if (is_match) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_BACKREFERENCE: { uint32_t backref_idx; backref_idx = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_BACKREFERENCE (idx: %d): ", backref_idx); backref_idx *= 2; /* backref n -> saved indices [n*2, n*2+1] */ JERRY_ASSERT (backref_idx >= 2 && backref_idx + 1 < re_ctx_p->num_of_captures); if (!re_ctx_p->saved_p[backref_idx].buf_p || !re_ctx_p->saved_p[backref_idx + 1].buf_p) { JERRY_DDLOG ("match\n"); break; /* capture is 'undefined', always matches! */ } lit_utf8_iterator_t sub_iter = re_ctx_p->saved_p[backref_idx]; while (sub_iter.buf_pos.offset < re_ctx_p->saved_p[backref_idx + 1].buf_pos.offset) { ecma_char_t ch1, ch2; if ((iter.buf_p + iter.buf_pos.offset) >= re_ctx_p->input_end_p) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } ch1 = lit_utf8_iterator_read_next (&sub_iter); ch2 = lit_utf8_iterator_read_next (&iter); if (ch1 != ch2) { JERRY_DDLOG ("fail\n"); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } } JERRY_DDLOG ("match\n"); break; /* tail merge */ } case RE_OP_SAVE_AT_START: { re_bytecode_t *old_bc_p; JERRY_DDLOG ("Execute RE_OP_SAVE_AT_START\n"); lit_utf8_iterator_t old_start_p = re_ctx_p->saved_p[RE_GLOBAL_START_IDX]; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = iter; do { uint32_t offset = re_get_value (&bc_p); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->saved_p[RE_GLOBAL_START_IDX] = old_start_p; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_SAVE_AND_MATCH: { JERRY_DDLOG ("End of pattern is reached: match\n"); re_ctx_p->saved_p[RE_GLOBAL_END_IDX] = iter; *out_iter_p = iter; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_TRUE); /* match */ } case RE_OP_ALTERNATIVE: { /* * Alternatives should be jump over, when alternative opcode appears. */ uint32_t offset = re_get_value (&bc_p); JERRY_DDLOG ("Execute RE_OP_ALTERNATIVE"); bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { JERRY_DDLOG (", jump: %d"); bc_p++; offset = re_get_value (&bc_p); bc_p += offset; } JERRY_DDLOG ("\n"); break; /* tail merge */ } case RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START: { /* * On non-greedy iterations we have to execute the bytecode * after the group first, if zero iteration is allowed. */ uint32_t start_idx, iter_idx, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; old_bc_p = bc_p; /* save the bytecode start position of the group start */ start_idx = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx] = 0; /* Jump all over to the end of the END opcode. */ bc_p += offset; /* Try to match after the close paren if zero is allowed */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (RE_IS_CAPTURE_GROUP (op)) { re_ctx_p->saved_p[start_idx] = old_start; } bc_p = old_bc_p; /* FALLTHRU */ } case RE_OP_CAPTURE_GROUP_START: case RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START: case RE_OP_NON_CAPTURE_GROUP_START: case RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START: { uint32_t start_idx, iter_idx, old_iteration_cnt, offset; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; re_bytecode_t *end_bc_p = NULL; start_idx = re_get_value (&bc_p); if (op != RE_OP_CAPTURE_GROUP_START && op != RE_OP_NON_CAPTURE_GROUP_START) { offset = re_get_value (&bc_p); end_bc_p = bc_p + offset; } if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (start_idx <= re_ctx_p->num_of_captures / 2); iter_idx = start_idx - 1; start_idx *= 2; } else { JERRY_ASSERT (start_idx < re_ctx_p->num_of_non_captures); iter_idx = start_idx + (re_ctx_p->num_of_captures / 2) - 1; start_idx += re_ctx_p->num_of_captures; } lit_utf8_iterator_t old_start = re_ctx_p->saved_p[start_idx]; old_iteration_cnt = re_ctx_p->num_of_iterations_p[iter_idx]; re_ctx_p->saved_p[start_idx] = iter; re_ctx_p->num_of_iterations_p[iter_idx] = 0; do { offset = re_get_value (&bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } bc_p += offset; old_bc_p = bc_p; } while (re_get_opcode (&bc_p) == RE_OP_ALTERNATIVE); bc_p = old_bc_p; re_ctx_p->num_of_iterations_p[iter_idx] = old_iteration_cnt; /* Try to match after the close paren if zero is allowed. */ if (op == RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START || op == RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START) { JERRY_ASSERT (end_bc_p); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, end_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } re_ctx_p->saved_p[start_idx] = old_start; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_CAPTURE_NON_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END: { uint32_t end_idx, iter_idx, min, max; re_bytecode_t *old_bc_p; /* * On non-greedy iterations we have to execute the bytecode * after the group first. Try to iterate only if it fails. */ old_bc_p = bc_p; /* save the bytecode start position of the group end */ end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); re_get_value (&bc_p); /* start offset */ if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; end_idx = (end_idx * 2) + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; } re_ctx_p->num_of_iterations_p[iter_idx]++; if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { lit_utf8_iterator_t old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[end_idx] = old_end; } re_ctx_p->num_of_iterations_p[iter_idx]--; bc_p = old_bc_p; /* If non-greedy fails and try to iterate... */ /* FALLTHRU */ } case RE_OP_CAPTURE_GREEDY_GROUP_END: case RE_OP_NON_CAPTURE_GREEDY_GROUP_END: { uint32_t start_idx, end_idx, iter_idx, min, max, offset; lit_utf8_iterator_t old_start = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t old_end = lit_utf8_iterator_create (NULL, 0); lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); re_bytecode_t *old_bc_p; end_idx = re_get_value (&bc_p); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); if (RE_IS_CAPTURE_GROUP (op)) { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_captures / 2); iter_idx = end_idx - 1; start_idx = end_idx * 2; end_idx = start_idx + 1; } else { JERRY_ASSERT (end_idx <= re_ctx_p->num_of_non_captures); iter_idx = end_idx + (re_ctx_p->num_of_captures / 2) - 1; end_idx += re_ctx_p->num_of_captures; start_idx = end_idx; } /* Check the empty iteration if the minimum number of iterations is reached. */ if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && iter.buf_p == re_ctx_p->saved_p[start_idx].buf_p && iter.buf_pos.offset == re_ctx_p->saved_p[start_idx].buf_pos.offset) { return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } re_ctx_p->num_of_iterations_p[iter_idx]++; old_bc_p = bc_p; /* Save the bytecode end position of the END opcodes for matching after it. */ old_end = re_ctx_p->saved_p[end_idx]; re_ctx_p->saved_p[end_idx] = iter; if (re_ctx_p->num_of_iterations_p[iter_idx] < max) { bc_p -= offset; offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; /* Try to match alternatives if any. */ bc_p += offset; while (*bc_p == RE_OP_ALTERNATIVE) { bc_p++; /* RE_OP_ALTERNATIVE */ offset = re_get_value (&bc_p); old_start = re_ctx_p->saved_p[start_idx]; re_ctx_p->saved_p[start_idx] = iter; ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } re_ctx_p->saved_p[start_idx] = old_start; bc_p += offset; } } if (re_ctx_p->num_of_iterations_p[iter_idx] >= min && re_ctx_p->num_of_iterations_p[iter_idx] <= max) { /* Try to match the rest of the bytecode. */ ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, old_bc_p, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } /* restore if fails */ re_ctx_p->saved_p[end_idx] = old_end; re_ctx_p->num_of_iterations_p[iter_idx]--; return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_NON_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Non-greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter <= max) { if (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } } ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } case RE_OP_GREEDY_ITERATOR: { uint32_t min, max, offset, num_of_iter; lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); min = re_get_value (&bc_p); max = re_get_value (&bc_p); offset = re_get_value (&bc_p); JERRY_DDLOG ("Greedy iterator, min=%lu, max=%lu, offset=%ld\n", (unsigned long) min, (unsigned long) max, (long) offset); num_of_iter = 0; while (num_of_iter < max) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p, iter, &sub_iter); if (!ecma_is_value_true (match_value)) { if (ecma_is_completion_value_throw (match_value)) { return match_value; } break; } iter = sub_iter; num_of_iter++; } while (num_of_iter >= min) { ecma_completion_value_t match_value = re_match_regexp (re_ctx_p, bc_p + offset, iter, &sub_iter); if (ecma_is_value_true (match_value)) { *out_iter_p = sub_iter; return match_value; /* match */ } else if (ecma_is_completion_value_throw (match_value)) { return match_value; } if (num_of_iter == min) { break; } lit_utf8_iterator_read_prev (&iter); num_of_iter--; } return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } default: { JERRY_DDLOG ("UNKNOWN opcode (%d)!\n", (uint32_t) op); return ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_COMMON)); } } } JERRY_UNREACHABLE (); return ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_FALSE); /* fail */ } /* regexp_match */
/** * ECMA abstract equality comparison routine. * * See also: ECMA-262 v5, 11.9.3 * * Note: * This function might raise an exception, so the * returned value must be freed with ecma_free_value. * * @return true - if values are equal, * false - otherwise * error - in case of any problems */ ecma_value_t ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (x == y) { return ECMA_VALUE_TRUE; } if (ecma_are_values_integer_numbers (x, y)) { /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_number (x)) { if (ecma_is_value_number (y)) { /* 1.c */ ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return ecma_make_boolean_value (is_x_equal_to_y); } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } if (ecma_is_value_string (x)) { if (ecma_is_value_string (y)) { /* 1., d. */ ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); return ecma_make_boolean_value (is_equal); } if (ecma_is_value_number (y)) { /* 4. */ ecma_value_t x_num_value = ecma_op_to_number (x); if (ECMA_IS_VALUE_ERROR (x_num_value)) { return x_num_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); ecma_free_value (x_num_value); return compare_result; } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) if (ecma_is_value_symbol (x)) { return ECMA_VALUE_FALSE; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ if (ecma_is_value_boolean (y)) { if (ecma_is_value_boolean (x)) { /* 1., e. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } /* 7. */ return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); } if (ecma_is_value_object (x)) { if (ecma_is_value_string (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_number (y)) { /* 9. */ ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); if (ECMA_IS_VALUE_ERROR (x_prim_value)) { return x_prim_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); ecma_free_value (x_prim_value); return compare_result; } /* 1., f. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_boolean (x)) { /* 6. */ return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); } if (ecma_is_value_undefined (x) || ecma_is_value_null (x)) { /* 1. a., b. */ /* 2., 3. */ bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); return ecma_make_boolean_value (is_equal); } return ECMA_VALUE_FALSE; } /* ecma_op_abstract_equality_compare */