Files
jerryscript/jerry-core/ecma/operations/ecma-exceptions.c
T
Dániel Bátyai 9860d66a56 Rework the public API (#4829)
Related to #4186.

Some notable changes:
  - The term 'Error' now strictly refers to native Error objects defined in
    the ECMA standard, which are ordinary objects. All other uses of
    'error' or 'error reference' where the term refers to a thrown value is
    now called 'exception'.

  - Simplified the naming scheme of many String API functions. These functions
    will now also take an 'encoding' argument to specify the desired
    encoding in which to operate.

  - Removed the substring-copy-to-buffer functions. These functions
    behaved awkwardly, as they use character index to specify the
    start/end positions, and were mostly used incorrectly with byte
    offsets instead. The functionality can still be replicated with
    other functions if necessary.

  - String-to-buffer functions will no longer fail if the buffer is not
    sufficiently large, the string will instead be cropped.

  - Fixed the usage of the '_sz' prefix in many API functions. The term
    'sz' means zero-terminated string in hungarian notation, this was
    used incorrectly in many cases.

  - Renamed most of the public API functions to have shorter, more on-point
    names, rather than the often too long descriptive names. Functions are now
    also grouped by the type of value they operate on, where this makes
    sense.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2021-12-06 10:20:09 +01:00

531 lines
15 KiB
C

/* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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-exceptions.h"
#include <stdarg.h>
#include "ecma-array-object.h"
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-iterator-object.h"
#include "ecma-objects.h"
#include "ecma-symbol-object.h"
#include "jcontext.h"
#include "jrt.h"
#if JERRY_LINE_INFO
#include "vm.h"
#endif /* JERRY_LINE_INFO */
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup exceptions Exceptions
* @{
*/
/**
* Standard ecma-error object constructor.
*
* Note:
* message_string_p can be NULL.
*
* Note:
* calling with JERRY_ERROR_NONE does not make sense thus it will
* cause a fault in the system.
*
* @return pointer to ecma-object representing specified error
* with reference counter set to one.
*/
ecma_object_t *
ecma_new_standard_error (jerry_error_t error_type, /**< native error type */
ecma_string_t *message_string_p) /**< message string */
{
#if JERRY_BUILTIN_ERRORS
ecma_builtin_id_t prototype_id = ECMA_BUILTIN_ID__COUNT;
switch (error_type)
{
case JERRY_ERROR_EVAL:
{
prototype_id = ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE;
break;
}
case JERRY_ERROR_RANGE:
{
prototype_id = ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE;
break;
}
case JERRY_ERROR_REFERENCE:
{
prototype_id = ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE;
break;
}
case JERRY_ERROR_TYPE:
{
prototype_id = ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE;
break;
}
#if JERRY_ESNEXT
case JERRY_ERROR_AGGREGATE:
{
prototype_id = ECMA_BUILTIN_ID_AGGREGATE_ERROR_PROTOTYPE;
break;
}
#endif /* JERRY_ESNEXT */
case JERRY_ERROR_URI:
{
prototype_id = ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE;
break;
}
case JERRY_ERROR_SYNTAX:
{
prototype_id = ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE;
break;
}
default:
{
JERRY_ASSERT (error_type == JERRY_ERROR_COMMON);
prototype_id = ECMA_BUILTIN_ID_ERROR_PROTOTYPE;
break;
}
}
#else /* !JERRY_BUILTIN_ERRORS */
JERRY_UNUSED (error_type);
ecma_builtin_id_t prototype_id = ECMA_BUILTIN_ID_ERROR_PROTOTYPE;
#endif /* JERRY_BUILTIN_ERRORS */
ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id);
ecma_object_t *error_object_p =
ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
ecma_extended_object_t *extended_object_p = (ecma_extended_object_t *) error_object_p;
extended_object_p->u.cls.type = ECMA_OBJECT_CLASS_ERROR;
extended_object_p->u.cls.u1.error_type = (uint8_t) error_type;
if (message_string_p != NULL)
{
ecma_property_value_t *prop_value_p;
prop_value_p = ecma_create_named_data_property (error_object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE),
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
ecma_ref_ecma_string (message_string_p);
prop_value_p->value = ecma_make_string_value (message_string_p);
}
/* Avoid calling the decorator function recursively. */
if (JERRY_CONTEXT (error_object_created_callback_p) != NULL
&& !(JERRY_CONTEXT (status_flags) & ECMA_STATUS_ERROR_UPDATE))
{
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_UPDATE;
JERRY_CONTEXT (error_object_created_callback_p)
(ecma_make_object_value (error_object_p), JERRY_CONTEXT (error_object_created_callback_user_p));
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_ERROR_UPDATE;
}
else
{
#if JERRY_LINE_INFO
/* Default decorator when line info is enabled. */
ecma_string_t *stack_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_STACK);
ecma_property_value_t *prop_value_p =
ecma_create_named_data_property (error_object_p, stack_str_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL);
ecma_deref_ecma_string (stack_str_p);
ecma_value_t backtrace_value = vm_get_backtrace (0);
prop_value_p->value = backtrace_value;
ecma_deref_object (ecma_get_object_from_value (backtrace_value));
#endif /* JERRY_LINE_INFO */
}
return error_object_p;
} /* ecma_new_standard_error */
#if JERRY_ESNEXT
/**
* aggregate-error object constructor.
*
* @return newly constructed aggregate errors
*/
ecma_value_t
ecma_new_aggregate_error (ecma_value_t error_list_val, /**< errors list */
ecma_value_t message_val) /**< message string */
{
ecma_object_t *new_error_object_p;
if (!ecma_is_value_undefined (message_val))
{
ecma_string_t *message_string_p = ecma_op_to_string (message_val);
if (JERRY_UNLIKELY (message_string_p == NULL))
{
return ECMA_VALUE_ERROR;
}
new_error_object_p = ecma_new_standard_error (JERRY_ERROR_AGGREGATE, message_string_p);
ecma_deref_ecma_string (message_string_p);
}
else
{
new_error_object_p = ecma_new_standard_error (JERRY_ERROR_AGGREGATE, NULL);
}
ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (error_list_val, LIT_GLOBAL_SYMBOL_ITERATOR);
if (ECMA_IS_VALUE_ERROR (using_iterator))
{
ecma_deref_object (new_error_object_p);
return using_iterator;
}
if (!ecma_is_value_undefined (using_iterator))
{
ecma_value_t next_method;
ecma_value_t iterator = ecma_op_get_iterator (error_list_val, using_iterator, &next_method);
ecma_free_value (using_iterator);
if (ECMA_IS_VALUE_ERROR (iterator))
{
ecma_deref_object (new_error_object_p);
return iterator;
}
ecma_collection_t *error_list_p = ecma_new_collection ();
ecma_value_t result = ECMA_VALUE_ERROR;
while (true)
{
ecma_value_t next = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (next))
{
break;
}
if (next == ECMA_VALUE_FALSE)
{
result = ECMA_VALUE_UNDEFINED;
break;
}
/* 8.e.iii */
ecma_value_t next_error = ecma_op_iterator_value (next);
ecma_free_value (next);
if (ECMA_IS_VALUE_ERROR (next_error))
{
break;
}
ecma_collection_push_back (error_list_p, next_error);
}
ecma_free_value (iterator);
ecma_free_value (next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_collection_free (error_list_p);
ecma_deref_object (new_error_object_p);
return result;
}
JERRY_ASSERT (ecma_is_value_undefined (result));
ecma_value_t error_list_arr = ecma_op_new_array_object_from_collection (error_list_p, true);
ecma_property_value_t *prop_value_p;
prop_value_p = ecma_create_named_data_property (new_error_object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_ERRORS_UL),
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
prop_value_p->value = error_list_arr;
ecma_free_value (error_list_arr);
}
return ecma_make_object_value (new_error_object_p);
} /* ecma_new_aggregate_error */
#endif /* JERRY_ESNEXT */
/**
* Return the error type for an Error object.
*
* @return one of the jerry_error_t value
* if it is not an Error object then JERRY_ERROR_NONE will be returned
*/
jerry_error_t
ecma_get_error_type (ecma_object_t *error_object_p) /**< possible error object */
{
if (!ecma_object_class_is (error_object_p, ECMA_OBJECT_CLASS_ERROR))
{
return JERRY_ERROR_NONE;
}
return (jerry_error_t) ((ecma_extended_object_t *) error_object_p)->u.cls.u1.error_type;
} /* ecma_get_error_type */
/**
* Raise a standard ecma-error with the given type and message.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_standard_error (jerry_error_t error_type, /**< error type */
const char *msg_p) /**< error message */
{
ecma_object_t *error_obj_p;
const lit_utf8_byte_t *str_p = (lit_utf8_byte_t *) msg_p;
if (msg_p != NULL)
{
ecma_string_t *error_msg_p = ecma_new_ecma_string_from_utf8 (str_p, lit_zt_utf8_string_size (str_p));
error_obj_p = ecma_new_standard_error (error_type, error_msg_p);
ecma_deref_ecma_string (error_msg_p);
}
else
{
error_obj_p = ecma_new_standard_error (error_type, NULL);
}
jcontext_raise_exception (ecma_make_object_value (error_obj_p));
return ECMA_VALUE_ERROR;
} /* ecma_raise_standard_error */
#if JERRY_ERROR_MESSAGES
/**
* Raise a standard ecma-error with the given format string and arguments.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_standard_error_with_format (jerry_error_t error_type, /**< error type */
const char *format, /**< format string */
...) /**< ecma-values */
{
JERRY_ASSERT (format != NULL);
ecma_stringbuilder_t builder = ecma_stringbuilder_create ();
const char *start_p = format;
const char *end_p = format;
va_list args;
va_start (args, format);
while (*end_p)
{
if (*end_p == '%')
{
/* Concat template string. */
if (end_p > start_p)
{
ecma_stringbuilder_append_raw (&builder, (lit_utf8_byte_t *) start_p, (lit_utf8_size_t) (end_p - start_p));
}
/* Convert an argument to string without side effects. */
ecma_string_t *arg_string_p;
const ecma_value_t arg_val = va_arg (args, ecma_value_t);
if (JERRY_UNLIKELY (ecma_is_value_object (arg_val)))
{
ecma_object_t *arg_object_p = ecma_get_object_from_value (arg_val);
lit_magic_string_id_t class_name = ecma_object_get_class_name (arg_object_p);
arg_string_p = ecma_get_magic_string (class_name);
}
#if JERRY_ESNEXT
else if (ecma_is_value_symbol (arg_val))
{
ecma_value_t symbol_desc_value = ecma_get_symbol_descriptive_string (arg_val);
arg_string_p = ecma_get_string_from_value (symbol_desc_value);
}
#endif /* JERRY_ESNEXT */
else
{
arg_string_p = ecma_op_to_string (arg_val);
JERRY_ASSERT (arg_string_p != NULL);
}
/* Concat argument. */
ecma_stringbuilder_append (&builder, arg_string_p);
ecma_deref_ecma_string (arg_string_p);
start_p = end_p + 1;
}
end_p++;
}
va_end (args);
/* Concat reset of template string. */
if (start_p < end_p)
{
ecma_stringbuilder_append_raw (&builder, (lit_utf8_byte_t *) start_p, (lit_utf8_size_t) (end_p - start_p));
}
ecma_string_t *builder_str_p = ecma_stringbuilder_finalize (&builder);
ecma_object_t *error_obj_p = ecma_new_standard_error (error_type, builder_str_p);
ecma_deref_ecma_string (builder_str_p);
jcontext_raise_exception (ecma_make_object_value (error_obj_p));
return ECMA_VALUE_ERROR;
} /* ecma_raise_standard_error_with_format */
#endif /* JERRY_ERROR_MESSAGES */
/**
* Raise a common error with the given message.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_common_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_COMMON, ecma_get_error_msg (msg));
} /* ecma_raise_common_error */
/**
* Raise a RangeError with the given message.
*
* See also: ECMA-262 v5, 15.11.6.2
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_range_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_RANGE, ecma_get_error_msg (msg));
} /* ecma_raise_range_error */
/**
* Raise a ReferenceError with the given message.
*
* See also: ECMA-262 v5, 15.11.6.3
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_reference_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_REFERENCE, ecma_get_error_msg (msg));
} /* ecma_raise_reference_error */
/**
* Raise a SyntaxError with the given message.
*
* See also: ECMA-262 v5, 15.11.6.4
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_syntax_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_SYNTAX, ecma_get_error_msg (msg));
} /* ecma_raise_syntax_error */
/**
* Raise a TypeError with the given message.
*
* See also: ECMA-262 v5, 15.11.6.5
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_type_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_TYPE, ecma_get_error_msg (msg));
} /* ecma_raise_type_error */
/**
* Raise a URIError with the given message.
*
* See also: ECMA-262 v5, 15.11.6.6
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_uri_error (ecma_error_msg_t msg) /**< error message */
{
return ecma_raise_standard_error (JERRY_ERROR_URI, ecma_get_error_msg (msg));
} /* ecma_raise_uri_error */
#if (JERRY_STACK_LIMIT != 0)
/**
* Raise a RangeError with "Maximum call stack size exceeded" message.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_maximum_callstack_error (void)
{
return ecma_raise_range_error (ECMA_ERR_MAXIMUM_CALL_STACK_SIZE_EXCEEDED);
} /* ecma_raise_maximum_callstack_error */
#endif /* (JERRY_STACK_LIMIT != 0) */
#if JERRY_ESNEXT
/**
* Raise a AggregateError with the given errors and message.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_aggregate_error (ecma_value_t error_list_val, /**< errors list */
ecma_value_t message_val) /**< error message */
{
ecma_value_t aggre_val = ecma_new_aggregate_error (error_list_val, message_val);
jcontext_raise_exception (aggre_val);
return ECMA_VALUE_ERROR;
} /* ecma_raise_aggregate_error */
#endif /* JERRY_ESNEXT */
/**
* @}
* @}
*/