2020-03-24 10:37:39 -03:00
/*
* Copyright ( c ) 2020 , Andreas Kling < kling @ serenityos . org >
2021-04-22 17:51:19 -03:00
* Copyright ( c ) 2021 , Linus Groh < linusg @ serenityos . org >
2020-03-24 10:37:39 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-03-24 10:37:39 -03:00
*/
2022-02-06 13:00:28 -03:00
# include <LibJS/AST.h>
2021-10-02 12:03:45 -03:00
# include <LibJS/Runtime/Completion.h>
2020-03-24 10:37:39 -03:00
# include <LibJS/Runtime/Error.h>
2022-02-06 13:00:28 -03:00
# include <LibJS/Runtime/ExecutionContext.h>
2020-04-17 14:31:48 -03:00
# include <LibJS/Runtime/GlobalObject.h>
2022-02-06 13:00:28 -03:00
# include <LibJS/SourceRange.h>
2020-03-24 10:37:39 -03:00
namespace JS {
2021-06-11 16:40:08 -03: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 14:31:48 -03:00
{
2021-04-11 19:08:28 -03:00
auto & vm = global_object . vm ( ) ;
2021-06-11 16:40:08 -03:00
auto * error = Error : : create ( global_object ) ;
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2021-07-05 20:15:08 -03:00
error - > define_direct_property ( vm . names . message , js_string ( vm , message ) , attr ) ;
2021-04-11 19:08:28 -03:00
return error ;
2020-04-17 14:31:48 -03:00
}
2021-04-11 19:08:28 -03:00
Error : : Error ( Object & prototype )
2020-06-23 12:21:53 -03:00
: Object ( prototype )
2020-03-24 10:37:39 -03:00
{
2022-02-06 13:00:28 -03:00
populate_stack ( ) ;
2020-03-24 10:37:39 -03:00
}
2021-12-21 10:34:06 -03:00
// 20.5.8.1 InstallErrorCause ( O, options ), https://tc39.es/ecma262/#sec-installerrorcause
2021-10-02 12:03:45 -03:00
ThrowCompletionOr < void > Error : : install_error_cause ( Value options )
2021-06-26 15:06:55 -03:00
{
auto & vm = this - > vm ( ) ;
2021-10-02 12:03:45 -03:00
// 1. If Type(options) is Object and ? HasProperty(options, "cause") is true, then
2021-10-02 22:00:39 -03:00
if ( options . is_object ( ) & & TRY ( options . as_object ( ) . has_property ( vm . names . cause ) ) ) {
2021-10-02 12:03:45 -03:00
// a. Let cause be ? Get(options, "cause").
2021-10-02 19:52:27 -03:00
auto cause = TRY ( options . as_object ( ) . get ( vm . names . cause ) ) ;
2021-10-02 12:03:45 -03:00
// b. Perform ! CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
2021-10-02 21:22:32 -03:00
MUST ( create_non_enumerable_data_property_or_throw ( vm . names . cause , cause ) ) ;
2021-10-02 12:03:45 -03:00
}
2021-12-21 10:34:06 -03:00
// 2. Return NormalCompletion(undefined).
2021-10-02 12:03:45 -03:00
return { } ;
2021-06-26 15:06:55 -03:00
}
2022-02-06 13:00:28 -03:00
void Error : : populate_stack ( )
{
2022-02-07 10:48:09 -03: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 13:00:28 -03:00
2022-02-07 10:48:09 -03:00
String Error : : stack_string ( ) const
{
StringBuilder stack_string_builder ;
2022-02-06 13:00:28 -03:00
// Note: We roughly follow V8's formatting
// Note: The error's name and message get prepended by ErrorPrototype::stack
2022-02-08 15:17:12 -03:00
// Note: We don't want to capture the global execution context, so we omit the last frame
2022-02-06 13:00:28 -03:00
// FIXME: We generate a stack-frame for the Errors constructor, other engines do not
2022-02-07 10:48:09 -03: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 13:00:28 -03:00
2022-02-07 10:48:09 -03: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 13:00:28 -03:00
else
2022-02-07 10:48:09 -03: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 13:00:28 -03:00
} else {
stack_string_builder . appendff ( " at {} \n " , function_name . is_empty ( ) ? " <unknown> " sv : function_name . view ( ) ) ;
}
}
2022-02-07 10:48:09 -03:00
return stack_string_builder . build ( ) ;
2022-02-06 13:00:28 -03:00
}
2021-06-11 16:40:08 -03: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-05 20:15:08 -03:00
error - > define_direct_property ( vm . names . message , js_string ( vm , message ) , attr ) ; \
2021-06-11 16:40:08 -03:00
return error ; \
} \
\
ClassName : : ClassName ( Object & prototype ) \
: Error ( prototype ) \
{ \
2021-04-11 19:08:28 -03:00
}
2020-04-10 07:42:33 -03:00
2021-06-11 13:54:42 -03:00
JS_ENUMERATE_NATIVE_ERRORS
2020-04-10 09:06:52 -03:00
# undef __JS_ENUMERATE
2020-04-10 07:42:33 -03:00
2020-03-24 10:37:39 -03:00
}