2020-03-24 14:37:39 +01:00
/*
* Copyright ( c ) 2020 , Andreas Kling < kling @ serenityos . org >
2021-04-22 22:51:19 +02:00
* Copyright ( c ) 2021 , Linus Groh < linusg @ serenityos . org >
2020-03-24 14:37:39 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-03-24 14:37:39 +01:00
*/
2022-02-06 17:00:28 +01:00
# include <LibJS/AST.h>
2021-10-02 16:03:45 +01:00
# include <LibJS/Runtime/Completion.h>
2020-03-24 14:37:39 +01:00
# include <LibJS/Runtime/Error.h>
2022-02-06 17:00:28 +01:00
# include <LibJS/Runtime/ExecutionContext.h>
2020-04-17 19:31:48 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2022-02-06 17:00:28 +01:00
# include <LibJS/SourceRange.h>
2020-03-24 14:37:39 +01:00
namespace JS {
2021-06-11 20:40:08 +01:00
Error * Error : : create ( GlobalObject & global_object )
{
return global_object . heap ( ) . allocate < Error > ( global_object , * global_object . error_prototype ( ) ) ;
}
Error * Error : : create ( GlobalObject & global_object , String const & message )
2020-04-17 19:31:48 +02:00
{
2021-04-12 00:08:28 +02:00
auto & vm = global_object . vm ( ) ;
2021-06-11 20:40:08 +01:00
auto * error = Error : : create ( global_object ) ;
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2021-07-06 02:15:08 +03:00
error - > define_direct_property ( vm . names . message , js_string ( vm , message ) , attr ) ;
2021-04-12 00:08:28 +02:00
return error ;
2020-04-17 19:31:48 +02:00
}
2021-04-12 00:08:28 +02:00
Error : : Error ( Object & prototype )
2020-06-23 17:21:53 +02:00
: Object ( prototype )
2020-03-24 14:37:39 +01:00
{
2022-02-06 17:00:28 +01:00
populate_stack ( ) ;
2020-03-24 14:37:39 +01:00
}
2021-12-21 08:34:06 -05:00
// 20.5.8.1 InstallErrorCause ( O, options ), https://tc39.es/ecma262/#sec-installerrorcause
2021-10-02 16:03:45 +01:00
ThrowCompletionOr < void > Error : : install_error_cause ( Value options )
2021-06-26 19:06:55 +01:00
{
auto & vm = this - > vm ( ) ;
2021-10-02 16:03:45 +01:00
// 1. If Type(options) is Object and ? HasProperty(options, "cause") is true, then
2021-10-03 02:00:39 +01:00
if ( options . is_object ( ) & & TRY ( options . as_object ( ) . has_property ( vm . names . cause ) ) ) {
2021-10-02 16:03:45 +01:00
// a. Let cause be ? Get(options, "cause").
2021-10-02 23:52:27 +01:00
auto cause = TRY ( options . as_object ( ) . get ( vm . names . cause ) ) ;
2021-10-02 16:03:45 +01:00
// b. Perform ! CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
2021-10-03 01:22:32 +01:00
MUST ( create_non_enumerable_data_property_or_throw ( vm . names . cause , cause ) ) ;
2021-10-02 16:03:45 +01:00
}
2021-12-21 08:34:06 -05:00
// 2. Return NormalCompletion(undefined).
2021-10-02 16:03:45 +01:00
return { } ;
2021-06-26 19:06:55 +01:00
}
2022-02-06 17:00:28 +01:00
void Error : : populate_stack ( )
{
2022-02-07 14:48:09 +01:00
auto & vm = this - > vm ( ) ;
m_traceback . ensure_capacity ( vm . execution_context_stack ( ) . size ( ) ) ;
for ( ssize_t i = vm . execution_context_stack ( ) . size ( ) - 1 ; i > = 0 ; i - - ) {
auto * context = vm . execution_context_stack ( ) [ i ] ;
auto function_name = context - > function_name ;
if ( function_name . is_empty ( ) )
function_name = " <unknown> " sv ;
m_traceback . empend (
move ( function_name ) ,
// We might not have an AST node associated with the execution context, e.g. in promise
// reaction jobs (which aren't called anywhere from the source code).
// They're not going to generate any _unhandled_ exceptions though, so a meaningless
// source range is fine.
context - > current_node ? context - > current_node - > source_range ( ) : SourceRange { } ) ;
}
}
2022-02-06 17:00:28 +01:00
2022-02-07 14:48:09 +01:00
String Error : : stack_string ( ) const
{
StringBuilder stack_string_builder ;
2022-02-06 17:00:28 +01:00
// Note: We roughly follow V8's formatting
// Note: The error's name and message get prepended by ErrorPrototype::stack
2022-02-08 18:17:12 +00:00
// Note: We don't want to capture the global execution context, so we omit the last frame
2022-02-06 17:00:28 +01:00
// FIXME: We generate a stack-frame for the Errors constructor, other engines do not
2022-02-07 14:48:09 +01:00
for ( size_t i = 0 ; i < m_traceback . size ( ) - 1 ; + + i ) {
auto const & frame = m_traceback [ i ] ;
auto function_name = frame . function_name ;
// Note: Since we don't know whether we have a valid SourceRange here we just check for some default values.
if ( ! frame . source_range . filename . is_null ( ) | | frame . source_range . start . offset ! = 0 | | frame . source_range . end . offset ! = 0 ) {
2022-02-06 17:00:28 +01:00
2022-02-07 14:48:09 +01:00
if ( function_name = = " <unknown> " sv )
stack_string_builder . appendff ( " at {}:{}:{} \n " , frame . source_range . filename , frame . source_range . start . line , frame . source_range . start . column ) ;
2022-02-06 17:00:28 +01:00
else
2022-02-07 14:48:09 +01:00
stack_string_builder . appendff ( " at {} ({}:{}:{}) \n " , function_name , frame . source_range . filename , frame . source_range . start . line , frame . source_range . start . column ) ;
2022-02-06 17:00:28 +01:00
} else {
stack_string_builder . appendff ( " at {} \n " , function_name . is_empty ( ) ? " <unknown> " sv : function_name . view ( ) ) ;
}
}
2022-02-07 14:48:09 +01:00
return stack_string_builder . build ( ) ;
2022-02-06 17:00:28 +01:00
}
2021-06-11 20:40:08 +01:00
# define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ClassName * ClassName : : create ( GlobalObject & global_object ) \
{ \
return global_object . heap ( ) . allocate < ClassName > ( global_object , * global_object . snake_name # # _prototype ( ) ) ; \
} \
\
ClassName * ClassName : : create ( GlobalObject & global_object , String const & message ) \
{ \
auto & vm = global_object . vm ( ) ; \
auto * error = ClassName : : create ( global_object ) ; \
u8 attr = Attribute : : Writable | Attribute : : Configurable ; \
2021-07-06 02:15:08 +03:00
error - > define_direct_property ( vm . names . message , js_string ( vm , message ) , attr ) ; \
2021-06-11 20:40:08 +01:00
return error ; \
} \
\
ClassName : : ClassName ( Object & prototype ) \
: Error ( prototype ) \
{ \
2021-04-12 00:08:28 +02:00
}
2020-04-10 12:42:33 +02:00
2021-06-11 17:54:42 +01:00
JS_ENUMERATE_NATIVE_ERRORS
2020-04-10 14:06:52 +02:00
# undef __JS_ENUMERATE
2020-04-10 12:42:33 +02:00
2020-03-24 14:37:39 +01:00
}