2020-03-07 19:42:11 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2020 - 2024 , Andreas Kling < andreas @ ladybird . org >
2023-02-11 16:02:14 +00:00
* Copyright ( c ) 2020 - 2023 , Linus Groh < linusg @ serenityos . org >
2022-01-18 19:07:13 +01:00
* Copyright ( c ) 2021 - 2022 , David Tuin < davidot @ serenityos . org >
2020-03-07 19:42:11 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-03-07 19:42:11 +01:00
*/
2021-01-17 09:21:15 +01:00
# include <AK/Demangle.h>
2020-09-18 18:00:57 +04:30
# include <AK/HashTable.h>
2022-01-27 02:44:03 +01:00
# include <AK/QuickSort.h>
2020-04-05 00:24:32 +02:00
# include <AK/ScopeGuard.h>
2020-03-12 19:22:13 +08:00
# include <AK/StringBuilder.h>
2020-11-28 16:14:26 +01:00
# include <AK/TemporaryChange.h>
2020-06-06 01:14:10 +01:00
# include <LibCrypto/BigInt/SignedBigInteger.h>
2024-11-15 04:01:23 +13:00
# include <LibGC/ConservativeVector.h>
2024-12-26 14:32:52 +01:00
# include <LibGC/RootVector.h>
2020-03-07 19:42:11 +01:00
# include <LibJS/AST.h>
2021-06-22 01:14:27 +02:00
# include <LibJS/Runtime/AbstractOperations.h>
2020-05-21 17:28:28 -07:00
# include <LibJS/Runtime/Accessor.h>
2020-03-20 20:29:57 +01:00
# include <LibJS/Runtime/Array.h>
2020-06-06 01:14:10 +01:00
# include <LibJS/Runtime/BigInt.h>
2021-09-24 22:40:38 +02:00
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
2020-03-24 14:37:39 +01:00
# include <LibJS/Runtime/Error.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/FunctionEnvironment.h>
2023-08-07 19:59:00 +02:00
# include <LibJS/Runtime/GlobalEnvironment.h>
2020-04-08 11:05:38 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2023-07-19 06:54:48 -04:00
# include <LibJS/Runtime/Iterator.h>
2020-04-01 18:31:24 +01:00
# include <LibJS/Runtime/NativeFunction.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/ObjectEnvironment.h>
2020-03-16 14:20:30 +01:00
# include <LibJS/Runtime/PrimitiveString.h>
2022-10-02 10:59:22 +01:00
# include <LibJS/Runtime/PromiseCapability.h>
2021-11-09 22:52:21 +02:00
# include <LibJS/Runtime/PromiseConstructor.h>
2020-04-27 12:10:16 +02:00
# include <LibJS/Runtime/Reference.h>
2020-06-03 16:05:49 -07:00
# include <LibJS/Runtime/RegExpObject.h>
2020-04-27 21:52:47 -07:00
# include <LibJS/Runtime/Shape.h>
2023-10-06 17:54:21 +02:00
# include <LibJS/Runtime/ValueInlines.h>
2025-04-08 00:45:27 +02:00
# include <memory>
2021-02-10 12:21:14 +01:00
# include <typeinfo>
2020-03-07 19:42:11 +01:00
namespace JS {
LibJS: Reduce AST memory usage by shrink-wrapping source range info
Before this change, each AST node had a 64-byte SourceRange member.
This SourceRange had the following layout:
filename: StringView (16 bytes)
start: Position (24 bytes)
end: Position (24 bytes)
The Position structs have { line, column, offset }, all members size_t.
To reduce memory consumption, AST nodes now only store the following:
source_code: NonnullRefPtr<SourceCode> (8 bytes)
start_offset: u32 (4 bytes)
end_offset: u32 (4 bytes)
SourceCode is a new ref-counted data structure that keeps the filename
and original parsed source code in a single location, and all AST nodes
have a pointer to it.
The start_offset and end_offset can be turned into (line, column) when
necessary by calling SourceCode::range_from_offsets(). This will walk
the source code string and compute line/column numbers on the fly, so
it's not necessarily fast, but it should be rare since this information
is primarily used for diagnostics and exception stack traces.
With this, ASTNode shrinks from 80 bytes to 32 bytes. This gives us a
~23% reduction in memory usage when loading twitter.com/awesomekling
(330 MiB before, 253 MiB after!) :^)
2022-11-21 17:37:38 +01:00
ASTNode : : ASTNode ( SourceRange source_range )
2022-11-26 19:01:55 +01:00
: m_start_offset ( source_range . start . offset )
, m_source_code ( source_range . code )
LibJS: Reduce AST memory usage by shrink-wrapping source range info
Before this change, each AST node had a 64-byte SourceRange member.
This SourceRange had the following layout:
filename: StringView (16 bytes)
start: Position (24 bytes)
end: Position (24 bytes)
The Position structs have { line, column, offset }, all members size_t.
To reduce memory consumption, AST nodes now only store the following:
source_code: NonnullRefPtr<SourceCode> (8 bytes)
start_offset: u32 (4 bytes)
end_offset: u32 (4 bytes)
SourceCode is a new ref-counted data structure that keeps the filename
and original parsed source code in a single location, and all AST nodes
have a pointer to it.
The start_offset and end_offset can be turned into (line, column) when
necessary by calling SourceCode::range_from_offsets(). This will walk
the source code string and compute line/column numbers on the fly, so
it's not necessarily fast, but it should be rare since this information
is primarily used for diagnostics and exception stack traces.
With this, ASTNode shrinks from 80 bytes to 32 bytes. This gives us a
~23% reduction in memory usage when loading twitter.com/awesomekling
(330 MiB before, 253 MiB after!) :^)
2022-11-21 17:37:38 +01:00
, m_end_offset ( source_range . end . offset )
{
}
SourceRange ASTNode : : source_range ( ) const
{
return m_source_code - > range_from_offsets ( m_start_offset , m_end_offset ) ;
}
2023-12-16 17:49:34 +03:30
ByteString ASTNode : : class_name ( ) const
2021-01-17 09:21:15 +01:00
{
// NOTE: We strip the "JS::" prefix.
2022-07-11 19:53:29 +00:00
auto const * typename_ptr = typeid ( * this ) . name ( ) ;
return demangle ( { typename_ptr , strlen ( typename_ptr ) } ) . substring ( 4 ) ;
2021-01-17 09:21:15 +01:00
}
2022-01-05 18:54:25 +01:00
static void print_indent ( int indent )
{
2023-12-16 17:49:34 +03:30
out ( " {} " , ByteString : : repeated ( ' ' , indent * 2 ) ) ;
2022-01-05 18:54:25 +01:00
}
2025-08-02 19:27:29 -04:00
static void update_function_name ( Value value , Utf16FlyString const & name )
2020-09-18 18:00:57 +04:30
{
2021-03-21 17:14:20 +01:00
if ( ! value . is_function ( ) )
return ;
auto & function = value . as_function ( ) ;
2025-04-09 22:31:12 +02:00
if ( is < ECMAScriptFunctionObject > ( function ) & & static_cast < ECMAScriptFunctionObject const & > ( function ) . name ( ) . is_empty ( ) )
2021-09-24 22:40:38 +02:00
static_cast < ECMAScriptFunctionObject & > ( function ) . set_name ( name ) ;
2020-09-18 18:00:57 +04:30
}
2022-01-05 18:54:25 +01:00
void LabelledStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
outln ( " (Label) " ) ;
print_indent ( indent + 2 ) ;
outln ( " \" {} \" " , m_label ) ;
print_indent ( indent + 1 ) ;
outln ( " (Labelled item) " ) ;
m_labelled_item - > dump ( indent + 2 ) ;
}
2021-09-22 12:44:56 +02:00
// 15.2.5 Runtime Semantics: InstantiateOrdinaryFunctionExpression, https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression
2025-08-02 19:27:29 -04:00
Value FunctionExpression : : instantiate_ordinary_function_expression ( VM & vm , Utf16FlyString given_name ) const
2021-09-22 12:44:56 +02:00
{
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2021-09-22 12:44:56 +02:00
if ( given_name . is_empty ( ) )
2025-08-02 19:27:29 -04:00
given_name = Utf16FlyString { } ;
2025-08-06 11:12:58 -04:00
auto own_name = name ( ) ;
auto has_own_name = ! own_name . is_empty ( ) ;
2021-07-07 22:53:32 +02:00
2025-08-02 19:27:29 -04:00
auto const & used_name = has_own_name ? own_name : given_name ;
2024-11-15 04:01:23 +13:00
auto environment = GC : : Ref { * vm . running_execution_context ( ) . lexical_environment } ;
2021-09-22 12:44:56 +02:00
if ( has_own_name ) {
2022-05-01 01:10:05 +02:00
VERIFY ( environment ) ;
environment = new_declarative_environment ( * environment ) ;
2025-08-02 19:27:29 -04:00
MUST ( environment - > create_immutable_binding ( vm , own_name , false ) ) ;
2020-04-26 13:53:40 +02:00
}
2023-08-07 19:59:00 +02:00
auto private_environment = vm . running_execution_context ( ) . private_environment ;
2021-09-22 12:44:56 +02:00
2025-04-07 21:08:55 +02:00
auto closure = ECMAScriptFunctionObject : : create_from_function_node ( * this , used_name , realm , environment , private_environment ) ;
2020-06-02 23:26:39 +02:00
2023-08-07 19:59:00 +02:00
// FIXME: 6. Perform SetFunctionName(closure, name).
// FIXME: 7. Perform MakeConstructor(closure).
2020-03-08 23:27:18 +02:00
2023-08-07 19:59:00 +02:00
if ( has_own_name )
2025-08-02 19:27:29 -04:00
MUST ( environment - > initialize_binding ( vm , own_name , closure , Environment : : InitializeBindingHint : : Normal ) ) ;
2020-03-08 23:27:18 +02:00
2023-08-07 19:59:00 +02:00
return closure ;
2020-06-08 13:31:21 -05:00
}
2025-08-06 11:12:58 -04:00
Optional < Utf16String > CallExpression : : expression_string ( ) const
2020-06-08 13:31:21 -05:00
{
2023-08-07 19:59:00 +02:00
if ( is < Identifier > ( * m_callee ) )
2025-08-06 11:12:58 -04:00
return static_cast < Identifier const & > ( * m_callee ) . string ( ) . to_utf16_string ( ) ;
2023-08-07 19:59:00 +02:00
if ( is < MemberExpression > ( * m_callee ) )
return static_cast < MemberExpression const & > ( * m_callee ) . to_string_approximation ( ) ;
return { } ;
2020-06-08 13:31:21 -05:00
}
2024-05-11 22:54:41 +00:00
static ThrowCompletionOr < ClassElementName > class_key_to_property_name ( VM & vm , Expression const & key , Value prop_key )
2021-08-28 17:11:05 +02:00
{
2021-10-12 22:45:52 +02:00
if ( is < PrivateIdentifier > ( key ) ) {
auto & private_identifier = static_cast < PrivateIdentifier const & > ( key ) ;
2023-06-25 17:33:17 +02:00
auto private_environment = vm . running_execution_context ( ) . private_environment ;
2021-10-12 22:45:52 +02:00
VERIFY ( private_environment ) ;
2025-08-06 11:12:58 -04:00
return ClassElementName { private_environment - > resolve_private_identifier ( private_identifier . string ( ) ) } ;
2021-10-12 22:45:52 +02:00
}
2021-10-07 01:09:04 +02:00
2025-04-04 23:16:34 +02:00
VERIFY ( ! prop_key . is_special_empty_value ( ) ) ;
2021-10-07 01:09:04 +02:00
if ( prop_key . is_object ( ) )
2022-08-21 14:00:56 +01:00
prop_key = TRY ( prop_key . to_primitive ( vm , Value : : PreferredType : : String ) ) ;
2021-10-07 01:09:04 +02:00
2022-08-21 14:00:56 +01:00
auto property_key = TRY ( PropertyKey : : from_value ( vm , prop_key ) ) ;
2022-04-20 00:06:45 +02:00
return ClassElementName { property_key } ;
2021-10-07 01:09:04 +02:00
}
// 15.4.5 Runtime Semantics: MethodDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
2024-05-11 22:54:41 +00:00
ThrowCompletionOr < ClassElement : : ClassValue > ClassMethod : : class_element_evaluation ( VM & vm , Object & target , Value property_key ) const
2021-10-07 01:09:04 +02:00
{
2024-05-11 22:54:41 +00:00
auto property_key_or_private_name = TRY ( class_key_to_property_name ( vm , * m_key , property_key ) ) ;
2021-10-07 01:09:04 +02:00
2025-04-07 21:08:55 +02:00
auto & method_function = * ECMAScriptFunctionObject : : create_from_function_node (
* m_function ,
2025-08-06 11:12:58 -04:00
m_function - > name ( ) ,
2025-04-07 21:08:55 +02:00
* vm . current_realm ( ) ,
vm . lexical_environment ( ) ,
vm . running_execution_context ( ) . private_environment ) ;
2021-10-07 01:09:04 +02:00
2024-05-12 04:24:06 +00:00
auto method_value = Value ( & method_function ) ;
2021-12-29 10:33:46 +01:00
method_function . make_method ( target ) ;
2021-10-07 01:09:04 +02:00
2025-08-02 19:27:29 -04:00
auto set_function_name = [ & ] ( StringView prefix = { } ) {
2022-02-06 15:59:04 +00:00
auto name = property_key_or_private_name . visit (
2025-08-02 19:27:29 -04:00
[ & ] ( PropertyKey const & property_key ) {
2022-02-06 15:59:04 +00:00
if ( property_key . is_symbol ( ) ) {
auto description = property_key . as_symbol ( ) - > description ( ) ;
2023-02-11 16:02:14 +00:00
if ( ! description . has_value ( ) | | description - > is_empty ( ) )
2025-08-02 19:27:29 -04:00
return Utf16String { } ;
return Utf16String : : formatted ( " [{}] " , * description ) ;
2021-10-12 22:45:52 +02:00
}
2025-03-18 18:08:02 -05:00
return property_key . to_string ( ) ;
2021-10-12 22:45:52 +02:00
} ,
2025-08-02 19:27:29 -04:00
[ & ] ( PrivateName const & private_name ) {
return private_name . description . to_utf16_string ( ) ;
2021-10-12 22:45:52 +02:00
} ) ;
2025-08-02 19:27:29 -04:00
update_function_name ( method_value , Utf16String : : formatted ( " {}{}{} " , prefix , prefix . is_empty ( ) ? " " : " " , name ) ) ;
2021-10-07 01:09:04 +02:00
} ;
2022-02-06 15:59:04 +00:00
if ( property_key_or_private_name . has < PropertyKey > ( ) ) {
auto & property_key = property_key_or_private_name . get < PropertyKey > ( ) ;
2021-10-12 22:45:52 +02:00
switch ( kind ( ) ) {
2025-09-15 16:43:27 +02:00
case ClassMethod : : Kind : : Method : {
2021-10-12 22:45:52 +02:00
set_function_name ( ) ;
2025-09-15 16:43:27 +02:00
PropertyDescriptor descriptor { . value = method_value , . writable = true , . enumerable = false , . configurable = true } ;
TRY ( target . define_property_or_throw ( property_key , descriptor ) ) ;
2021-10-12 22:45:52 +02:00
break ;
2025-09-15 16:43:27 +02:00
}
case ClassMethod : : Kind : : Getter : {
2025-08-02 19:27:29 -04:00
set_function_name ( " get " sv ) ;
2025-09-15 16:43:27 +02:00
PropertyDescriptor descriptor { . get = & method_function , . enumerable = false , . configurable = true } ;
TRY ( target . define_property_or_throw ( property_key , descriptor ) ) ;
2021-10-12 22:45:52 +02:00
break ;
2025-09-15 16:43:27 +02:00
}
case ClassMethod : : Kind : : Setter : {
2025-08-02 19:27:29 -04:00
set_function_name ( " set " sv ) ;
2025-09-15 16:43:27 +02:00
PropertyDescriptor descriptor { . set = & method_function , . enumerable = false , . configurable = true } ;
TRY ( target . define_property_or_throw ( property_key , descriptor ) ) ;
2021-10-12 22:45:52 +02:00
break ;
2025-09-15 16:43:27 +02:00
}
2021-10-12 22:45:52 +02:00
default :
VERIFY_NOT_REACHED ( ) ;
}
2021-10-07 01:09:04 +02:00
2025-04-04 18:11:45 +02:00
return ClassValue { normal_completion ( js_undefined ( ) ) } ;
2021-10-12 22:45:52 +02:00
} else {
2022-02-06 15:59:04 +00:00
auto & private_name = property_key_or_private_name . get < PrivateName > ( ) ;
2021-10-12 22:45:52 +02:00
switch ( kind ( ) ) {
case Kind : : Method :
set_function_name ( ) ;
2023-12-09 11:05:25 +01:00
return ClassValue { PrivateElement { private_name , PrivateElement : : Kind : : Method , method_value } } ;
2021-10-12 22:45:52 +02:00
case Kind : : Getter :
2025-08-02 19:27:29 -04:00
set_function_name ( " get " sv ) ;
2023-12-09 11:05:25 +01:00
return ClassValue { PrivateElement { private_name , PrivateElement : : Kind : : Accessor , Value ( Accessor : : create ( vm , & method_function , nullptr ) ) } } ;
2021-10-12 22:45:52 +02:00
case Kind : : Setter :
2025-08-02 19:27:29 -04:00
set_function_name ( " set " sv ) ;
2023-12-09 11:05:25 +01:00
return ClassValue { PrivateElement { private_name , PrivateElement : : Kind : : Accessor , Value ( Accessor : : create ( vm , nullptr , & method_function ) ) } } ;
2021-10-12 22:45:52 +02:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2021-10-07 01:09:04 +02:00
}
2023-06-17 10:11:23 +02:00
void ClassFieldInitializerStatement : : dump ( int ) const
{
// This should not be dumped as it is never part of an actual AST.
VERIFY_NOT_REACHED ( ) ;
}
2021-10-13 19:59:38 +02:00
2021-10-07 01:09:04 +02:00
// 15.7.10 Runtime Semantics: ClassFieldDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classfielddefinitionevaluation
2024-05-11 22:54:41 +00:00
ThrowCompletionOr < ClassElement : : ClassValue > ClassField : : class_element_evaluation ( VM & vm , Object & target , Value property_key ) const
2021-10-07 01:09:04 +02:00
{
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2024-05-11 22:54:41 +00:00
auto property_key_or_private_name = TRY ( class_key_to_property_name ( vm , * m_key , property_key ) ) ;
2025-04-01 20:53:57 +02:00
Variant < GC : : Ref < ECMAScriptFunctionObject > , Value , Empty > initializer ;
2021-10-07 01:09:04 +02:00
if ( m_initializer ) {
2025-04-01 20:53:57 +02:00
if ( auto const * literal = as_if < NumericLiteral > ( * m_initializer ) ) {
initializer = literal - > value ( ) ;
} else if ( auto const * literal = as_if < BooleanLiteral > ( * m_initializer ) ) {
initializer = literal - > value ( ) ;
} else if ( auto const * literal = as_if < NullLiteral > ( * m_initializer ) ) {
initializer = literal - > value ( ) ;
} else if ( auto const * literal = as_if < StringLiteral > ( * m_initializer ) ) {
initializer = Value ( PrimitiveString : : create ( vm , literal - > value ( ) ) ) ;
} else {
auto copy_initializer = m_initializer ;
auto name = property_key_or_private_name . visit (
2025-08-02 19:27:29 -04:00
[ & ] ( PropertyKey const & property_key ) {
2025-05-15 17:14:00 +03:00
return property_key . to_string ( ) ;
2025-04-01 20:53:57 +02:00
} ,
2025-08-02 19:27:29 -04:00
[ & ] ( PrivateName const & private_name ) {
return private_name . description . to_utf16_string ( ) ;
2025-04-01 20:53:57 +02:00
} ) ;
// FIXME: A potential optimization is not creating the functions here since these are never directly accessible.
2025-08-07 16:34:36 -04:00
auto function_code = create_ast_node < ClassFieldInitializerStatement > ( m_initializer - > source_range ( ) , copy_initializer . release_nonnull ( ) , move ( name ) ) ;
2025-04-01 20:53:57 +02:00
FunctionParsingInsights parsing_insights ;
parsing_insights . uses_this_from_environment = true ;
parsing_insights . uses_this = true ;
2025-08-02 19:27:29 -04:00
auto function = ECMAScriptFunctionObject : : create ( realm , " field " _utf16_fly_string , ByteString : : empty ( ) , * function_code , FunctionParameters : : empty ( ) , 0 , { } , vm . lexical_environment ( ) , vm . running_execution_context ( ) . private_environment , FunctionKind : : Normal , true , parsing_insights , false , property_key_or_private_name ) ;
2025-04-01 20:53:57 +02:00
function - > make_method ( target ) ;
initializer = function ;
}
2021-10-07 01:09:04 +02:00
}
return ClassValue {
ClassFieldDefinition {
2022-02-06 15:59:04 +00:00
move ( property_key_or_private_name ) ,
2022-02-04 16:22:29 +01:00
move ( initializer ) ,
2021-10-07 01:09:04 +02:00
}
} ;
2021-08-28 17:11:05 +02:00
}
2025-08-06 11:12:58 -04:00
static Optional < Utf16FlyString > nullopt_or_private_identifier_description ( Expression const & expression )
2021-10-12 22:45:52 +02:00
{
if ( is < PrivateIdentifier > ( expression ) )
return static_cast < PrivateIdentifier const & > ( expression ) . string ( ) ;
return { } ;
}
2025-08-06 11:12:58 -04:00
Optional < Utf16FlyString > ClassField : : private_bound_identifier ( ) const
2021-10-12 22:45:52 +02:00
{
return nullopt_or_private_identifier_description ( * m_key ) ;
}
2025-08-06 11:12:58 -04:00
Optional < Utf16FlyString > ClassMethod : : private_bound_identifier ( ) const
2021-10-12 22:45:52 +02:00
{
return nullopt_or_private_identifier_description ( * m_key ) ;
}
2021-10-20 21:29:47 +02:00
// 15.7.11 Runtime Semantics: ClassStaticBlockDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classstaticblockdefinitionevaluation
2024-05-11 22:54:41 +00:00
ThrowCompletionOr < ClassElement : : ClassValue > StaticInitializer : : class_element_evaluation ( VM & vm , Object & home_object , Value ) const
2021-10-20 21:29:47 +02:00
{
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2022-01-02 21:49:02 +01:00
// 1. Let lex be the running execution context's LexicalEnvironment.
2023-06-25 17:33:17 +02:00
auto lexical_environment = vm . running_execution_context ( ) . lexical_environment ;
2022-01-02 21:49:02 +01:00
2022-05-01 01:10:05 +02:00
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
2023-06-25 17:33:17 +02:00
auto private_environment = vm . running_execution_context ( ) . private_environment ;
2021-10-20 21:29:47 +02:00
2022-01-02 21:49:02 +01:00
// 3. Let sourceText be the empty sequence of Unicode code points.
// 4. Let formalParameters be an instance of the production FormalParameters : [empty] .
2022-05-01 01:10:05 +02:00
// 5. Let bodyFunction be OrdinaryFunctionCreate(%Function.prototype%, sourceText, formalParameters, ClassStaticBlockBody, non-lexical-this, lex, privateEnv).
2021-10-20 21:29:47 +02:00
// Note: The function bodyFunction is never directly accessible to ECMAScript code.
2024-05-22 11:04:50 +01:00
FunctionParsingInsights parsing_insights ;
parsing_insights . uses_this_from_environment = true ;
2024-05-22 18:50:45 +01:00
parsing_insights . uses_this = true ;
2025-08-02 19:27:29 -04:00
auto body_function = ECMAScriptFunctionObject : : create ( realm , { } , ByteString : : empty ( ) , * m_function_body , FunctionParameters : : empty ( ) , 0 , m_function_body - > local_variables_names ( ) , lexical_environment , private_environment , FunctionKind : : Normal , true , parsing_insights , false ) ;
2022-01-02 21:49:02 +01:00
// 6. Perform MakeMethod(bodyFunction, homeObject).
2021-12-29 10:33:46 +01:00
body_function - > make_method ( home_object ) ;
2021-10-20 21:29:47 +02:00
2022-01-02 21:49:02 +01:00
// 7. Return the ClassStaticBlockDefinition Record { [[BodyFunction]]: bodyFunction }.
2021-10-20 21:29:47 +02:00
return ClassValue { normal_completion ( body_function ) } ;
}
2025-08-02 19:27:29 -04:00
ThrowCompletionOr < ECMAScriptFunctionObject * > ClassExpression : : create_class_constructor ( VM & vm , Environment * class_environment , Environment * environment , Value super_class , ReadonlySpan < Value > element_keys , Optional < Utf16FlyString > const & binding_name , Utf16FlyString const & class_name ) const
2021-09-22 12:44:56 +02:00
{
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2021-10-07 01:09:04 +02:00
// We might not set the lexical environment but we always want to restore it eventually.
2021-09-22 12:44:56 +02:00
ArmedScopeGuard restore_environment = [ & ] {
vm . running_execution_context ( ) . lexical_environment = environment ;
} ;
2024-05-11 22:54:41 +00:00
vm . running_execution_context ( ) . lexical_environment = class_environment ;
2020-06-08 13:31:21 -05:00
2024-11-15 04:01:23 +13:00
auto proto_parent = GC : : Ptr { realm . intrinsics ( ) . object_prototype ( ) } ;
2023-06-28 18:22:27 +03:00
auto constructor_parent = realm . intrinsics ( ) . function_prototype ( ) ;
2021-10-07 01:09:04 +02:00
if ( ! m_super_class . is_null ( ) ) {
if ( super_class . is_null ( ) ) {
proto_parent = nullptr ;
} else if ( ! super_class . is_constructor ( ) ) {
2023-08-09 08:49:02 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : ClassExtendsValueNotAConstructorOrNull , super_class . to_string_without_side_effects ( ) ) ;
2021-10-07 01:09:04 +02:00
} else {
2022-08-21 14:00:56 +01:00
auto super_class_prototype = TRY ( super_class . get ( vm , vm . names . prototype ) ) ;
2021-10-07 01:09:04 +02:00
if ( ! super_class_prototype . is_null ( ) & & ! super_class_prototype . is_object ( ) )
2023-08-09 08:49:02 +02:00
return vm . throw_completion < TypeError > ( ErrorType : : ClassExtendsValueInvalidPrototype , super_class_prototype . to_string_without_side_effects ( ) ) ;
2020-06-08 13:31:21 -05:00
2021-10-07 01:09:04 +02:00
if ( super_class_prototype . is_null ( ) )
proto_parent = nullptr ;
else
2023-04-13 00:47:15 +02:00
proto_parent = super_class_prototype . as_object ( ) ;
2020-06-08 13:31:21 -05:00
2023-04-13 00:47:15 +02:00
constructor_parent = super_class . as_object ( ) ;
2021-10-07 01:09:04 +02:00
}
}
2020-06-08 13:31:21 -05:00
2024-05-04 15:48:23 +02:00
auto prototype = Object : : create_prototype ( realm , proto_parent ) ;
2021-10-07 01:09:04 +02:00
VERIFY ( prototype ) ;
2020-06-08 13:31:21 -05:00
2022-08-20 17:27:02 +02:00
// FIXME: Step 14.a is done in the parser. By using a synthetic super(...args) which does not call @@iterator of %Array.prototype%
2023-06-28 18:22:27 +03:00
auto const & constructor = * m_constructor ;
2025-04-07 21:08:55 +02:00
auto class_constructor = ECMAScriptFunctionObject : : create_from_function_node (
constructor ,
2025-08-06 11:12:58 -04:00
constructor . name ( ) ,
2025-04-07 21:08:55 +02:00
realm ,
2023-06-28 18:22:27 +03:00
vm . lexical_environment ( ) ,
2025-04-07 21:08:55 +02:00
vm . running_execution_context ( ) . private_environment ) ;
2023-06-28 18:22:27 +03:00
class_constructor - > set_name ( class_name ) ;
2021-10-07 01:09:04 +02:00
class_constructor - > set_home_object ( prototype ) ;
class_constructor - > set_is_class_constructor ( ) ;
class_constructor - > define_direct_property ( vm . names . prototype , prototype , Attribute : : Writable ) ;
TRY ( class_constructor - > internal_set_prototype_of ( constructor_parent ) ) ;
2021-08-28 17:11:05 +02:00
2021-10-07 01:09:04 +02:00
if ( ! m_super_class . is_null ( ) )
2025-04-08 00:45:27 +02:00
class_constructor - > set_constructor_kind ( ConstructorKind : : Derived ) ;
2021-08-28 17:11:05 +02:00
2021-10-07 01:09:04 +02:00
prototype - > define_direct_property ( vm . names . constructor , class_constructor , Attribute : : Writable | Attribute : : Configurable ) ;
2021-08-28 17:11:05 +02:00
2024-11-15 04:01:23 +13:00
using StaticElement = Variant < ClassFieldDefinition , GC : : Ref < ECMAScriptFunctionObject > > ;
2021-10-20 21:29:47 +02:00
2024-11-15 04:01:23 +13:00
GC : : ConservativeVector < PrivateElement > static_private_methods ( vm . heap ( ) ) ;
GC : : ConservativeVector < PrivateElement > instance_private_methods ( vm . heap ( ) ) ;
GC : : ConservativeVector < ClassFieldDefinition > instance_fields ( vm . heap ( ) ) ;
GC : : ConservativeVector < StaticElement > static_elements ( vm . heap ( ) ) ;
2021-08-28 17:11:05 +02:00
2024-05-11 22:54:41 +00:00
for ( size_t element_index = 0 ; element_index < m_elements . size ( ) ; element_index + + ) {
auto const & element = m_elements [ element_index ] ;
2021-10-07 01:09:04 +02:00
// Note: All ClassElementEvaluation start with evaluating the name (or we fake it).
2024-05-11 22:54:41 +00:00
auto element_value = TRY ( element - > class_element_evaluation ( vm , element - > is_static ( ) ? * class_constructor : * prototype , element_keys [ element_index ] ) ) ;
2021-10-07 01:09:04 +02:00
2021-10-12 22:45:52 +02:00
if ( element_value . has < PrivateElement > ( ) ) {
2023-03-06 14:17:01 +01:00
auto & container = element - > is_static ( ) ? static_private_methods : instance_private_methods ;
2021-10-12 22:45:52 +02:00
auto & private_element = element_value . get < PrivateElement > ( ) ;
auto added_to_existing = false ;
// FIXME: We can skip this loop in most cases.
for ( auto & existing : container ) {
if ( existing . key = = private_element . key ) {
VERIFY ( existing . kind = = PrivateElement : : Kind : : Accessor ) ;
VERIFY ( private_element . kind = = PrivateElement : : Kind : : Accessor ) ;
2023-12-09 11:05:25 +01:00
auto & accessor = private_element . value . as_accessor ( ) ;
2021-10-12 22:45:52 +02:00
if ( ! accessor . getter ( ) )
2023-12-09 11:05:25 +01:00
existing . value . as_accessor ( ) . set_setter ( accessor . setter ( ) ) ;
2021-10-12 22:45:52 +02:00
else
2023-12-09 11:05:25 +01:00
existing . value . as_accessor ( ) . set_getter ( accessor . getter ( ) ) ;
2021-10-12 22:45:52 +02:00
added_to_existing = true ;
}
}
if ( ! added_to_existing )
container . append ( move ( element_value . get < PrivateElement > ( ) ) ) ;
2022-04-20 00:06:45 +02:00
} else if ( auto * class_field_definition_ptr = element_value . get_pointer < ClassFieldDefinition > ( ) ) {
2023-03-06 14:17:01 +01:00
if ( element - > is_static ( ) )
2021-10-20 21:29:47 +02:00
static_elements . append ( move ( * class_field_definition_ptr ) ) ;
2021-10-07 01:09:04 +02:00
else
instance_fields . append ( move ( * class_field_definition_ptr ) ) ;
2023-03-06 14:17:01 +01:00
} else if ( element - > class_element_kind ( ) = = ClassElement : : ElementKind : : StaticInitializer ) {
2021-10-20 21:29:47 +02:00
// We use Completion to hold the ClassStaticBlockDefinition Record.
2025-04-04 18:11:45 +02:00
auto & element_object = element_value . get < Completion > ( ) . value ( ) . as_object ( ) ;
2021-12-28 17:42:14 +01:00
VERIFY ( is < ECMAScriptFunctionObject > ( element_object ) ) ;
2024-11-15 04:01:23 +13:00
static_elements . append ( GC : : Ref { static_cast < ECMAScriptFunctionObject & > ( element_object ) } ) ;
2021-08-28 17:11:05 +02:00
}
}
2021-09-22 12:44:56 +02:00
vm . running_execution_context ( ) . lexical_environment = environment ;
restore_environment . disarm ( ) ;
2021-10-07 01:09:04 +02:00
2024-01-24 14:55:56 -05:00
if ( binding_name . has_value ( ) )
MUST ( class_environment - > initialize_binding ( vm , binding_name . value ( ) , class_constructor , Environment : : InitializeBindingHint : : Normal ) ) ;
2020-06-08 13:31:21 -05:00
2021-10-07 01:09:04 +02:00
for ( auto & field : instance_fields )
2022-04-20 00:06:45 +02:00
class_constructor - > add_field ( field ) ;
2021-10-07 01:09:04 +02:00
2021-10-12 22:45:52 +02:00
for ( auto & private_method : instance_private_methods )
class_constructor - > add_private_method ( private_method ) ;
for ( auto & method : static_private_methods )
2023-02-27 22:13:37 +00:00
TRY ( class_constructor - > private_method_or_accessor_add ( move ( method ) ) ) ;
2021-10-12 22:45:52 +02:00
2021-10-20 21:29:47 +02:00
for ( auto & element : static_elements ) {
TRY ( element . visit (
2022-04-20 00:06:45 +02:00
[ & ] ( ClassFieldDefinition & field ) - > ThrowCompletionOr < void > {
return TRY ( class_constructor - > define_field ( field ) ) ;
2021-10-20 21:29:47 +02:00
} ,
2024-11-15 04:01:23 +13:00
[ & ] ( GC : : Root < ECMAScriptFunctionObject > static_block_function ) - > ThrowCompletionOr < void > {
2022-02-04 16:22:29 +01:00
VERIFY ( ! static_block_function . is_null ( ) ) ;
2021-10-20 21:29:47 +02:00
// We discard any value returned here.
2023-06-28 18:22:27 +03:00
TRY ( call ( vm , * static_block_function . cell ( ) , class_constructor ) ) ;
2021-10-20 21:29:47 +02:00
return { } ;
} ) ) ;
2021-10-07 01:09:04 +02:00
}
2023-06-28 18:22:27 +03:00
class_constructor - > set_source_text ( source_text ( ) ) ;
return { class_constructor } ;
}
2020-03-07 19:42:11 +01:00
void ASTNode : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , class_name ( ) ) ;
2020-03-07 19:42:11 +01:00
}
void ScopeNode : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2020-04-13 16:42:54 +02:00
if ( ! m_children . is_empty ( ) ) {
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Children) " ) ;
2020-04-13 16:42:54 +02:00
for ( auto & child : children ( ) )
2023-03-06 14:17:01 +01:00
child - > dump ( indent + 2 ) ;
2020-04-13 16:42:54 +02:00
}
2020-03-07 19:42:11 +01:00
}
void BinaryExpression : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * op_string = nullptr ;
2020-03-07 23:16:34 +01:00
switch ( m_op ) {
2020-04-05 12:56:53 +01:00
case BinaryOp : : Addition :
2020-03-07 23:16:34 +01:00
op_string = " + " ;
break ;
2020-04-05 12:56:53 +01:00
case BinaryOp : : Subtraction :
2020-03-07 23:16:34 +01:00
op_string = " - " ;
break ;
2020-04-05 12:56:53 +01:00
case BinaryOp : : Multiplication :
2020-03-12 23:04:52 +11:00
op_string = " * " ;
break ;
2020-04-05 12:56:53 +01:00
case BinaryOp : : Division :
2020-03-12 23:04:52 +11:00
op_string = " / " ;
break ;
2020-04-04 21:17:34 +02:00
case BinaryOp : : Modulo :
op_string = " % " ;
break ;
2020-04-05 13:40:00 +01:00
case BinaryOp : : Exponentiation :
op_string = " ** " ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyEquals :
2020-03-08 07:53:02 +02:00
op_string = " === " ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : StrictlyInequals :
2020-03-08 23:27:18 +02:00
op_string = " !== " ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyEquals :
2020-03-16 00:23:38 +02:00
op_string = " == " ;
break ;
2021-09-24 00:06:10 +02:00
case BinaryOp : : LooselyInequals :
2020-03-16 00:23:38 +02:00
op_string = " != " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : GreaterThan :
2020-03-08 23:27:18 +02:00
op_string = " > " ;
break ;
2020-03-12 23:07:08 +11:00
case BinaryOp : : GreaterThanEquals :
op_string = " >= " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : LessThan :
2020-03-08 23:27:18 +02:00
op_string = " < " ;
break ;
2020-03-12 23:07:08 +11:00
case BinaryOp : : LessThanEquals :
op_string = " <= " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : BitwiseAnd :
2020-03-08 23:27:18 +02:00
op_string = " & " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : BitwiseOr :
2020-03-08 23:27:18 +02:00
op_string = " | " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : BitwiseXor :
2020-03-08 23:27:18 +02:00
op_string = " ^ " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : LeftShift :
2020-03-08 23:27:18 +02:00
op_string = " << " ;
break ;
2020-03-10 11:35:05 +01:00
case BinaryOp : : RightShift :
2020-03-08 23:27:18 +02:00
op_string = " >> " ;
break ;
2020-04-23 15:43:10 +01:00
case BinaryOp : : UnsignedRightShift :
op_string = " >>> " ;
break ;
2020-04-23 16:06:01 +01:00
case BinaryOp : : In :
op_string = " in " ;
break ;
2020-03-28 16:56:54 +01:00
case BinaryOp : : InstanceOf :
op_string = " instanceof " ;
break ;
2020-03-08 07:53:02 +02:00
}
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , class_name ( ) ) ;
2020-03-08 07:53:02 +02:00
m_lhs - > dump ( indent + 1 ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2020-03-08 07:53:02 +02:00
m_rhs - > dump ( indent + 1 ) ;
}
2020-03-08 07:55:44 +02:00
void LogicalExpression : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * op_string = nullptr ;
2020-03-08 07:55:44 +02:00
switch ( m_op ) {
case LogicalOp : : And :
op_string = " && " ;
break ;
case LogicalOp : : Or :
op_string = " || " ;
break ;
2020-04-18 00:49:11 +01:00
case LogicalOp : : NullishCoalescing :
op_string = " ?? " ;
break ;
2020-03-07 23:16:34 +01:00
}
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , class_name ( ) ) ;
2020-03-07 19:42:11 +01:00
m_lhs - > dump ( indent + 1 ) ;
2020-03-07 23:16:34 +01:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2020-03-07 19:42:11 +01:00
m_rhs - > dump ( indent + 1 ) ;
}
2020-03-08 23:27:18 +02:00
void UnaryExpression : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * op_string = nullptr ;
2020-03-08 23:27:18 +02:00
switch ( m_op ) {
2020-03-14 20:43:35 +02:00
case UnaryOp : : BitwiseNot :
2020-03-08 23:27:18 +02:00
op_string = " ~ " ;
break ;
2020-03-09 19:04:44 +02:00
case UnaryOp : : Not :
op_string = " ! " ;
break ;
2020-04-02 17:58:39 +01:00
case UnaryOp : : Plus :
op_string = " + " ;
break ;
case UnaryOp : : Minus :
op_string = " - " ;
break ;
2020-03-18 06:33:32 +11:00
case UnaryOp : : Typeof :
op_string = " typeof " ;
break ;
2020-04-15 17:55:03 +01:00
case UnaryOp : : Void :
op_string = " void " ;
break ;
2020-04-26 13:53:40 +02:00
case UnaryOp : : Delete :
op_string = " delete " ;
break ;
2020-03-08 23:27:18 +02:00
}
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , class_name ( ) ) ;
2020-03-08 23:27:18 +02:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2020-03-08 23:27:18 +02:00
m_lhs - > dump ( indent + 1 ) ;
}
2020-03-07 19:42:11 +01:00
void CallExpression : : dump ( int indent ) const
{
2020-04-06 20:24:45 +02:00
print_indent ( indent ) ;
2021-01-01 19:34:07 +01:00
if ( is < NewExpression > ( * this ) )
2020-12-06 16:55:19 +00:00
outln ( " CallExpression [new] " ) ;
else
outln ( " CallExpression " ) ;
2020-03-12 23:02:41 +01:00
m_callee - > dump ( indent + 1 ) ;
2022-11-26 19:51:50 +01:00
for ( auto & argument : arguments ( ) )
2020-05-05 22:36:24 -07:00
argument . value - > dump ( indent + 1 ) ;
2020-03-07 19:42:11 +01:00
}
2021-07-02 19:30:38 +02:00
void SuperCall : : dump ( int indent ) const
{
print_indent ( indent ) ;
outln ( " SuperCall " ) ;
for ( auto & argument : m_arguments )
argument . value - > dump ( indent + 1 ) ;
}
2020-06-08 13:31:21 -05:00
void ClassDeclaration : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_class_expression - > dump ( indent + 1 ) ;
}
2023-07-02 01:04:07 +03:00
ThrowCompletionOr < void > ClassDeclaration : : for_each_bound_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
if ( ! m_class_expression - > m_name )
return { } ;
return callback ( * m_class_expression - > m_name ) ;
}
2020-06-08 13:31:21 -05:00
void ClassExpression : : dump ( int indent ) const
{
print_indent ( indent ) ;
2023-06-30 16:51:39 +03:00
outln ( " ClassExpression: \" {} \" " , name ( ) ) ;
2020-06-08 13:31:21 -05:00
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Constructor) " ) ;
2020-06-08 13:31:21 -05:00
m_constructor - > dump ( indent + 1 ) ;
if ( ! m_super_class . is_null ( ) ) {
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Super Class) " ) ;
2020-06-08 13:31:21 -05:00
m_super_class - > dump ( indent + 1 ) ;
}
print_indent ( indent ) ;
2021-10-07 01:09:04 +02:00
outln ( " (Elements) " ) ;
for ( auto & method : m_elements )
2023-03-06 14:17:01 +01:00
method - > dump ( indent + 1 ) ;
2020-06-08 13:31:21 -05:00
}
void ClassMethod : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Key) " ) ;
2020-06-08 13:31:21 -05:00
m_key - > dump ( indent + 1 ) ;
2022-04-01 20:58:27 +03:00
char const * kind_string = nullptr ;
2020-06-08 13:31:21 -05:00
switch ( m_kind ) {
case Kind : : Method :
kind_string = " Method " ;
break ;
case Kind : : Getter :
kind_string = " Getter " ;
break ;
case Kind : : Setter :
kind_string = " Setter " ;
break ;
}
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " Kind: {} " , kind_string ) ;
2020-06-08 13:31:21 -05:00
print_indent ( indent ) ;
2021-10-07 01:09:04 +02:00
outln ( " Static: {} " , is_static ( ) ) ;
2020-06-08 13:31:21 -05:00
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Function) " ) ;
2020-06-08 13:31:21 -05:00
m_function - > dump ( indent + 1 ) ;
}
2021-08-28 17:11:05 +02:00
void ClassField : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
outln ( " (Key) " ) ;
m_key - > dump ( indent + 1 ) ;
print_indent ( indent ) ;
2021-10-07 01:09:04 +02:00
outln ( " Static: {} " , is_static ( ) ) ;
2021-08-28 17:11:05 +02:00
if ( m_initializer ) {
print_indent ( indent ) ;
outln ( " (Initializer) " ) ;
m_initializer - > dump ( indent + 1 ) ;
}
}
2021-10-20 21:29:47 +02:00
void StaticInitializer : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_function_body - > dump ( indent + 1 ) ;
}
2020-03-12 12:19:11 +01:00
void StringLiteral : : dump ( int indent ) const
2020-03-07 19:42:11 +01:00
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " StringLiteral \" {} \" " , m_value ) ;
2020-03-12 12:19:11 +01:00
}
2020-06-08 13:31:21 -05:00
void SuperExpression : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " super " ) ;
2020-06-08 13:31:21 -05:00
}
2020-03-12 12:19:11 +01:00
void NumericLiteral : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " NumericLiteral {} " , m_value ) ;
2020-03-12 12:19:11 +01:00
}
2020-06-06 01:14:10 +01:00
void BigIntLiteral : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " BigIntLiteral {} " , m_value ) ;
2020-06-06 01:14:10 +01:00
}
2020-03-12 12:19:11 +01:00
void BooleanLiteral : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " BooleanLiteral {} " , m_value ) ;
2020-03-07 19:42:11 +01:00
}
2020-03-15 23:32:34 +02:00
void NullLiteral : : dump ( int indent ) const
{
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " null " ) ;
2020-03-15 23:32:34 +02:00
}
2021-09-22 12:44:56 +02:00
bool BindingPattern : : contains_expression ( ) const
{
for ( auto & entry : entries ) {
2023-09-20 01:19:09 +02:00
if ( entry . name . has < NonnullRefPtr < Expression const > > ( ) )
return true ;
2021-09-22 12:44:56 +02:00
if ( entry . initializer )
return true ;
2023-02-19 22:07:52 +01:00
if ( auto binding_ptr = entry . alias . get_pointer < NonnullRefPtr < BindingPattern const > > ( ) ; binding_ptr & & ( * binding_ptr ) - > contains_expression ( ) )
2021-09-22 12:44:56 +02:00
return true ;
}
return false ;
}
2023-07-02 01:04:07 +03:00
ThrowCompletionOr < void > BindingPattern : : for_each_bound_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
for ( auto const & entry : entries ) {
auto const & alias = entry . alias ;
if ( alias . has < NonnullRefPtr < Identifier const > > ( ) ) {
TRY ( callback ( alias . get < NonnullRefPtr < Identifier const > > ( ) ) ) ;
} else if ( alias . has < NonnullRefPtr < BindingPattern const > > ( ) ) {
TRY ( alias . get < NonnullRefPtr < BindingPattern const > > ( ) - > for_each_bound_identifier ( forward < decltype ( callback ) > ( callback ) ) ) ;
} else {
auto const & name = entry . name ;
if ( name . has < NonnullRefPtr < Identifier const > > ( ) )
TRY ( callback ( name . get < NonnullRefPtr < Identifier const > > ( ) ) ) ;
}
}
return { } ;
}
2021-05-29 16:03:19 +04:30
void BindingPattern : : dump ( int indent ) const
{
print_indent ( indent ) ;
outln ( " BindingPattern {} " , kind = = Kind : : Array ? " Array " : " Object " ) ;
2021-06-12 18:04:28 -07:00
for ( auto & entry : entries ) {
2021-05-29 16:03:19 +04:30
print_indent ( indent + 1 ) ;
2021-06-12 18:04:28 -07:00
outln ( " (Property) " ) ;
if ( kind = = Kind : : Object ) {
print_indent ( indent + 2 ) ;
outln ( " (Identifier) " ) ;
2023-02-19 22:07:52 +01:00
if ( entry . name . has < NonnullRefPtr < Identifier const > > ( ) ) {
entry . name . get < NonnullRefPtr < Identifier const > > ( ) - > dump ( indent + 3 ) ;
2023-07-02 11:24:55 +02:00
} else if ( entry . name . has < NonnullRefPtr < Expression const > > ( ) ) {
2023-02-19 22:07:52 +01:00
entry . name . get < NonnullRefPtr < Expression const > > ( ) - > dump ( indent + 3 ) ;
2023-07-02 11:24:55 +02:00
} else {
VERIFY ( entry . name . has < Empty > ( ) ) ;
print_indent ( indent + 3 ) ;
outln ( " <empty> " ) ;
2021-06-12 18:04:28 -07:00
}
} else if ( entry . is_elision ( ) ) {
2021-05-29 16:03:19 +04:30
print_indent ( indent + 2 ) ;
2021-06-12 18:04:28 -07:00
outln ( " (Elision) " ) ;
continue ;
2021-05-29 16:03:19 +04:30
}
2021-06-12 18:04:28 -07:00
print_indent ( indent + 2 ) ;
outln ( " (Pattern{}) " , entry . is_rest ? " rest=true " : " " ) ;
2023-02-19 22:07:52 +01:00
if ( entry . alias . has < NonnullRefPtr < Identifier const > > ( ) ) {
entry . alias . get < NonnullRefPtr < Identifier const > > ( ) - > dump ( indent + 3 ) ;
} else if ( entry . alias . has < NonnullRefPtr < BindingPattern const > > ( ) ) {
entry . alias . get < NonnullRefPtr < BindingPattern const > > ( ) - > dump ( indent + 3 ) ;
} else if ( entry . alias . has < NonnullRefPtr < MemberExpression const > > ( ) ) {
entry . alias . get < NonnullRefPtr < MemberExpression const > > ( ) - > dump ( indent + 3 ) ;
2021-05-29 16:03:19 +04:30
} else {
2021-06-12 18:04:28 -07:00
print_indent ( indent + 3 ) ;
outln ( " <empty> " ) ;
2021-05-29 16:03:19 +04:30
}
2021-06-12 18:04:28 -07:00
if ( entry . initializer ) {
print_indent ( indent + 2 ) ;
outln ( " (Initializer) " ) ;
entry . initializer - > dump ( indent + 3 ) ;
}
2021-05-29 16:03:19 +04:30
}
}
2025-05-05 21:53:19 +03:00
FunctionNode : : FunctionNode ( RefPtr < Identifier const > name , ByteString source_text , NonnullRefPtr < Statement const > body , NonnullRefPtr < FunctionParameters const > parameters , i32 function_length , FunctionKind kind , bool is_strict_mode , FunctionParsingInsights parsing_insights , bool is_arrow_function , Vector < LocalVariable > local_variables_names )
2025-04-08 00:45:27 +02:00
: m_name ( move ( name ) )
, m_source_text ( move ( source_text ) )
, m_body ( move ( body ) )
, m_parameters ( move ( parameters ) )
, m_function_length ( function_length )
, m_kind ( kind )
, m_is_strict_mode ( is_strict_mode )
, m_is_arrow_function ( is_arrow_function )
, m_parsing_insights ( parsing_insights )
, m_local_variables_names ( move ( local_variables_names ) )
{
if ( m_is_arrow_function )
VERIFY ( ! parsing_insights . might_need_arguments_object ) ;
}
FunctionNode : : ~ FunctionNode ( ) = default ;
void FunctionNode : : set_shared_data ( RefPtr < SharedFunctionInstanceData > shared_data ) const
{
m_shared_data = move ( shared_data ) ;
}
RefPtr < SharedFunctionInstanceData > FunctionNode : : shared_data ( ) const
{
return m_shared_data ;
}
2023-12-16 17:49:34 +03:30
void FunctionNode : : dump ( int indent , ByteString const & class_name ) const
2020-03-07 19:42:11 +01:00
{
print_indent ( indent ) ;
2021-11-15 01:53:24 +01:00
auto is_async = m_kind = = FunctionKind : : Async | | m_kind = = FunctionKind : : AsyncGenerator ;
auto is_generator = m_kind = = FunctionKind : : Generator | | m_kind = = FunctionKind : : AsyncGenerator ;
outln ( " {}{}{} '{}' " , class_name , is_async ? " async " : " " , is_generator ? " * " : " " , name ( ) ) ;
2024-05-22 11:04:50 +01:00
if ( m_parsing_insights . contains_direct_call_to_eval ) {
2021-10-08 12:43:38 +02:00
print_indent ( indent + 1 ) ;
outln ( " \033 [31;1m(direct eval) \033 [0m " ) ;
}
2025-03-27 12:59:50 +00:00
if ( ! m_parameters - > is_empty ( ) ) {
2020-05-02 11:46:39 -07:00
print_indent ( indent + 1 ) ;
2021-06-03 22:49:37 +02:00
outln ( " (Parameters) " ) ;
2020-05-02 11:46:39 -07:00
2025-03-27 12:59:50 +00:00
for ( auto & parameter : m_parameters - > parameters ( ) ) {
2021-05-29 16:03:19 +04:30
parameter . binding . visit (
2023-07-06 17:49:38 +02:00
[ & ] ( Identifier const & identifier ) {
if ( parameter . is_rest ) {
print_indent ( indent + 2 ) ;
2023-06-24 06:23:46 +02:00
out ( " ... " ) ;
2023-07-06 17:49:38 +02:00
identifier . dump ( 0 ) ;
} else {
identifier . dump ( indent + 2 ) ;
}
2021-05-29 16:03:19 +04:30
} ,
2021-06-11 02:13:06 +04:30
[ & ] ( BindingPattern const & pattern ) {
2021-05-29 16:03:19 +04:30
pattern . dump ( indent + 2 ) ;
} ) ;
2020-05-04 16:05:13 +01:00
if ( parameter . default_value )
2020-05-02 11:46:39 -07:00
parameter . default_value - > dump ( indent + 3 ) ;
}
}
2020-04-13 16:42:54 +02:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Body) " ) ;
2020-04-13 16:42:54 +02:00
body ( ) . dump ( indent + 2 ) ;
2020-03-07 19:42:11 +01:00
}
2020-03-19 11:12:08 +01:00
void FunctionDeclaration : : dump ( int indent ) const
{
2021-09-22 12:44:56 +02:00
FunctionNode : : dump ( indent , class_name ( ) ) ;
}
2023-07-02 01:04:07 +03:00
ThrowCompletionOr < void > FunctionDeclaration : : for_each_bound_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
if ( ! m_name )
return { } ;
return callback ( * m_name ) ;
}
2020-03-19 11:12:08 +01:00
void FunctionExpression : : dump ( int indent ) const
{
FunctionNode : : dump ( indent , class_name ( ) ) ;
}
2021-06-11 01:38:30 +04:30
void YieldExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
if ( argument ( ) )
argument ( ) - > dump ( indent + 1 ) ;
}
2021-11-09 22:52:21 +02:00
void AwaitExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_argument - > dump ( indent + 1 ) ;
}
2020-03-07 19:42:11 +01:00
void ReturnStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2020-03-11 19:27:43 +01:00
if ( argument ( ) )
argument ( ) - > dump ( indent + 1 ) ;
2020-03-07 19:42:11 +01:00
}
2020-03-08 07:58:58 +02:00
void IfStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " If " ) ;
2020-03-08 07:58:58 +02:00
predicate ( ) . dump ( indent + 1 ) ;
consequent ( ) . dump ( indent + 1 ) ;
2020-03-21 18:40:17 +01:00
if ( alternate ( ) ) {
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " Else " ) ;
2020-03-21 18:40:17 +01:00
alternate ( ) - > dump ( indent + 1 ) ;
}
2020-03-08 07:58:58 +02:00
}
2020-03-09 03:22:21 +08:00
void WhileStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " While " ) ;
2020-04-04 21:21:19 +02:00
test ( ) . dump ( indent + 1 ) ;
2020-03-09 03:22:21 +08:00
body ( ) . dump ( indent + 1 ) ;
}
2020-11-28 15:05:57 +01:00
void WithStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " Object " ) ;
2020-11-28 15:05:57 +01:00
object ( ) . dump ( indent + 2 ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " Body " ) ;
2020-11-28 15:05:57 +01:00
body ( ) . dump ( indent + 2 ) ;
}
2020-04-04 21:29:23 +02:00
void DoWhileStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " DoWhile " ) ;
2020-04-04 21:29:23 +02:00
test ( ) . dump ( indent + 1 ) ;
body ( ) . dump ( indent + 1 ) ;
}
2020-03-12 23:12:12 +11:00
void ForStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " For " ) ;
2020-03-12 23:12:12 +11:00
if ( init ( ) )
init ( ) - > dump ( indent + 1 ) ;
if ( test ( ) )
test ( ) - > dump ( indent + 1 ) ;
if ( update ( ) )
update ( ) - > dump ( indent + 1 ) ;
body ( ) . dump ( indent + 1 ) ;
}
2020-04-21 19:21:26 +01:00
void ForInStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " ForIn " ) ;
2021-09-22 12:44:56 +02:00
lhs ( ) . visit ( [ & ] ( auto & lhs ) { lhs - > dump ( indent + 1 ) ; } ) ;
2020-04-21 19:21:26 +01:00
rhs ( ) . dump ( indent + 1 ) ;
body ( ) . dump ( indent + 1 ) ;
}
void ForOfStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " ForOf " ) ;
2021-09-22 12:44:56 +02:00
lhs ( ) . visit ( [ & ] ( auto & lhs ) { lhs - > dump ( indent + 1 ) ; } ) ;
2020-04-21 19:21:26 +01:00
rhs ( ) . dump ( indent + 1 ) ;
body ( ) . dump ( indent + 1 ) ;
}
2021-11-23 16:09:28 +01:00
void ForAwaitOfStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
outln ( " ForAwaitOf " ) ;
m_lhs . visit ( [ & ] ( auto & lhs ) { lhs - > dump ( indent + 1 ) ; } ) ;
m_rhs - > dump ( indent + 1 ) ;
m_body - > dump ( indent + 1 ) ;
}
2020-03-09 21:13:55 +01:00
void Identifier : : dump ( int indent ) const
{
print_indent ( indent ) ;
2023-07-05 00:14:41 +02:00
if ( is_local ( ) ) {
2025-04-25 17:10:47 +02:00
outln ( " Identifier \" {} \" is_local=(true) index=({}) " , m_string , m_local_index - > index ) ;
2023-07-12 04:02:27 +02:00
} else if ( is_global ( ) ) {
outln ( " Identifier \" {} \" is_global=(true) " , m_string ) ;
2023-07-05 00:14:41 +02:00
} else {
outln ( " Identifier \" {} \" " , m_string ) ;
}
2020-03-09 21:13:55 +01:00
}
2021-10-12 22:45:52 +02:00
void PrivateIdentifier : : dump ( int indent ) const
{
print_indent ( indent ) ;
outln ( " PrivateIdentifier \" {} \" " , m_string ) ;
}
2020-04-26 23:05:37 -07:00
void SpreadExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_target - > dump ( indent + 1 ) ;
}
2020-04-13 00:42:14 +02:00
void ThisExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
}
2020-03-09 21:13:55 +01:00
void AssignmentExpression : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * op_string = nullptr ;
2020-03-09 21:13:55 +01:00
switch ( m_op ) {
2020-03-12 13:54:56 +01:00
case AssignmentOp : : Assignment :
2020-03-09 21:13:55 +01:00
op_string = " = " ;
break ;
2020-03-12 13:54:56 +01:00
case AssignmentOp : : AdditionAssignment :
2020-03-12 23:09:15 +11:00
op_string = " += " ;
break ;
2020-03-12 13:54:56 +01:00
case AssignmentOp : : SubtractionAssignment :
2020-03-12 23:09:15 +11:00
op_string = " -= " ;
break ;
2020-03-12 13:54:56 +01:00
case AssignmentOp : : MultiplicationAssignment :
2020-03-12 23:09:15 +11:00
op_string = " *= " ;
break ;
2020-03-12 13:54:56 +01:00
case AssignmentOp : : DivisionAssignment :
2020-03-12 23:09:15 +11:00
op_string = " /= " ;
break ;
2020-05-04 23:07:05 +01:00
case AssignmentOp : : ModuloAssignment :
op_string = " %= " ;
break ;
2020-05-04 23:03:35 +01:00
case AssignmentOp : : ExponentiationAssignment :
op_string = " **= " ;
break ;
2020-05-04 22:34:45 +01:00
case AssignmentOp : : BitwiseAndAssignment :
op_string = " &= " ;
break ;
case AssignmentOp : : BitwiseOrAssignment :
op_string = " |= " ;
break ;
case AssignmentOp : : BitwiseXorAssignment :
op_string = " ^= " ;
break ;
2020-04-23 13:36:14 +01:00
case AssignmentOp : : LeftShiftAssignment :
op_string = " <<= " ;
break ;
2020-04-23 13:45:19 +01:00
case AssignmentOp : : RightShiftAssignment :
op_string = " >>= " ;
break ;
2020-04-23 15:43:10 +01:00
case AssignmentOp : : UnsignedRightShiftAssignment :
op_string = " >>>= " ;
break ;
2020-10-05 16:49:43 +01:00
case AssignmentOp : : AndAssignment :
op_string = " &&= " ;
break ;
case AssignmentOp : : OrAssignment :
op_string = " ||= " ;
break ;
case AssignmentOp : : NullishAssignment :
op_string = " \ ? \ ?= " ;
break ;
2020-03-09 21:13:55 +01:00
}
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2021-07-11 01:16:17 +04:30
m_lhs . visit ( [ & ] ( auto & lhs ) { lhs - > dump ( indent + 1 ) ; } ) ;
2020-03-09 21:13:55 +01:00
m_rhs - > dump ( indent + 1 ) ;
}
2020-03-12 13:45:45 +02:00
void UpdateExpression : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * op_string = nullptr ;
2020-03-12 13:45:45 +02:00
switch ( m_op ) {
case UpdateOp : : Increment :
op_string = " ++ " ;
break ;
case UpdateOp : : Decrement :
op_string = " -- " ;
break ;
}
ASTNode : : dump ( indent ) ;
2020-10-19 00:17:46 +01:00
if ( m_prefixed ) {
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2020-10-19 00:17:46 +01:00
}
2020-03-12 13:45:45 +02:00
m_argument - > dump ( indent + 1 ) ;
2020-03-14 20:44:57 +02:00
if ( ! m_prefixed ) {
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , op_string ) ;
2020-03-14 20:44:57 +02:00
}
2020-03-12 13:45:45 +02:00
}
2023-07-02 01:04:07 +03:00
ThrowCompletionOr < void > VariableDeclaration : : for_each_bound_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
for ( auto const & entry : declarations ( ) ) {
TRY ( entry - > target ( ) . visit (
[ & ] ( NonnullRefPtr < Identifier const > const & id ) {
return callback ( id ) ;
} ,
[ & ] ( NonnullRefPtr < BindingPattern const > const & binding ) {
return binding - > for_each_bound_identifier ( [ & ] ( auto const & id ) {
return callback ( id ) ;
} ) ;
} ) ) ;
}
return { } ;
}
2020-03-09 21:13:55 +01:00
void VariableDeclaration : : dump ( int indent ) const
{
2022-04-01 20:58:27 +03:00
char const * declaration_kind_string = nullptr ;
2020-04-08 11:59:18 +02:00
switch ( m_declaration_kind ) {
2025-05-04 01:41:49 +02:00
case DeclarationKind : : None :
VERIFY_NOT_REACHED ( ) ;
2020-04-08 11:59:18 +02:00
case DeclarationKind : : Let :
declaration_kind_string = " Let " ;
2020-03-11 21:09:20 +02:00
break ;
2020-04-08 11:59:18 +02:00
case DeclarationKind : : Var :
declaration_kind_string = " Var " ;
2020-03-12 14:24:34 +02:00
break ;
2020-04-08 11:59:18 +02:00
case DeclarationKind : : Const :
declaration_kind_string = " Const " ;
2020-03-11 21:09:20 +02:00
break ;
}
2020-03-09 21:13:55 +01:00
ASTNode : : dump ( indent ) ;
2020-03-11 21:09:20 +02:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} " , declaration_kind_string ) ;
2020-04-04 21:46:25 +02:00
for ( auto & declarator : m_declarations )
2023-03-06 14:17:01 +01:00
declarator - > dump ( indent + 1 ) ;
2020-04-04 21:46:25 +02:00
}
2023-07-02 01:04:07 +03:00
ThrowCompletionOr < void > UsingDeclaration : : for_each_bound_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
for ( auto const & entry : m_declarations ) {
VERIFY ( entry - > target ( ) . has < NonnullRefPtr < Identifier const > > ( ) ) ;
TRY ( callback ( entry - > target ( ) . get < NonnullRefPtr < Identifier const > > ( ) ) ) ;
}
return { } ;
}
2022-12-20 22:09:57 +01:00
void UsingDeclaration : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
for ( auto & declarator : m_declarations )
2023-03-06 14:17:01 +01:00
declarator - > dump ( indent + 1 ) ;
2022-12-20 22:09:57 +01:00
}
2020-04-04 21:46:25 +02:00
void VariableDeclarator : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2022-04-01 20:58:27 +03:00
m_target . visit ( [ indent ] ( auto const & value ) { value - > dump ( indent + 1 ) ; } ) ;
2020-04-04 21:46:25 +02:00
if ( m_init )
m_init - > dump ( indent + 1 ) ;
2020-03-09 21:13:55 +01:00
}
2020-04-23 19:37:53 +01:00
void ObjectProperty : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2021-10-11 20:30:31 +02:00
if ( m_property_type = = Type : : Spread ) {
print_indent ( indent + 1 ) ;
outln ( " ...Spreading " ) ;
m_key - > dump ( indent + 1 ) ;
} else {
m_key - > dump ( indent + 1 ) ;
m_value - > dump ( indent + 1 ) ;
}
2020-04-23 19:37:53 +01:00
}
2020-03-09 21:28:31 +01:00
void ObjectExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2020-04-23 19:37:53 +01:00
for ( auto & property : m_properties ) {
2023-03-06 14:17:01 +01:00
property - > dump ( indent + 1 ) ;
2020-03-21 02:29:00 +02:00
}
2020-03-09 21:28:31 +01:00
}
2020-03-11 19:27:43 +01:00
void ExpressionStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_expression - > dump ( indent + 1 ) ;
}
2020-03-11 18:58:19 +01:00
void MemberExpression : : dump ( int indent ) const
{
2020-03-20 20:51:03 +01:00
print_indent ( indent ) ;
2021-04-24 13:49:43 +02:00
outln ( " {}(computed={}) " , class_name ( ) , is_computed ( ) ) ;
2020-03-11 18:58:19 +01:00
m_object - > dump ( indent + 1 ) ;
m_property - > dump ( indent + 1 ) ;
}
2025-08-06 11:12:58 -04:00
Utf16String MemberExpression : : to_string_approximation ( ) const
2020-04-19 01:12:51 +01:00
{
2025-08-06 11:12:58 -04:00
Utf16View object_string = " <object> " sv ;
2021-01-01 19:34:07 +01:00
if ( is < Identifier > ( * m_object ) )
2025-08-06 11:12:58 -04:00
object_string = static_cast < Identifier const & > ( * m_object ) . string ( ) . view ( ) ;
2020-04-19 01:12:51 +01:00
if ( is_computed ( ) )
2025-08-06 11:12:58 -04:00
return Utf16String : : formatted ( " {}[<computed>] " , object_string ) ;
2023-06-15 12:38:28 +02:00
if ( is < PrivateIdentifier > ( * m_property ) )
2025-08-06 11:12:58 -04:00
return Utf16String : : formatted ( " {}.{} " , object_string , as < PrivateIdentifier > ( * m_property ) . string ( ) ) ;
return Utf16String : : formatted ( " {}.{} " , object_string , as < Identifier > ( * m_property ) . string ( ) ) ;
2020-04-19 01:12:51 +01:00
}
2021-10-12 22:45:52 +02:00
bool MemberExpression : : ends_in_private_name ( ) const
{
if ( is_computed ( ) )
return false ;
if ( is < PrivateIdentifier > ( * m_property ) )
return true ;
if ( is < MemberExpression > ( * m_property ) )
return static_cast < MemberExpression const & > ( * m_property ) . ends_in_private_name ( ) ;
return false ;
}
2021-09-14 06:56:31 +04:30
void OptionalChain : : dump ( int indent ) const
{
print_indent ( indent ) ;
outln ( " {} " , class_name ( ) ) ;
m_base - > dump ( indent + 1 ) ;
for ( auto & reference : m_references ) {
reference . visit (
[ & ] ( Call const & call ) {
print_indent ( indent + 1 ) ;
outln ( " Call({}) " , call . mode = = Mode : : Optional ? " Optional " : " Not Optional " ) ;
for ( auto & argument : call . arguments )
argument . value - > dump ( indent + 2 ) ;
} ,
[ & ] ( ComputedReference const & ref ) {
print_indent ( indent + 1 ) ;
outln ( " ComputedReference({}) " , ref . mode = = Mode : : Optional ? " Optional " : " Not Optional " ) ;
ref . expression - > dump ( indent + 2 ) ;
} ,
[ & ] ( MemberReference const & ref ) {
print_indent ( indent + 1 ) ;
outln ( " MemberReference({}) " , ref . mode = = Mode : : Optional ? " Optional " : " Not Optional " ) ;
ref . identifier - > dump ( indent + 2 ) ;
2021-10-18 23:32:47 +02:00
} ,
[ & ] ( PrivateMemberReference const & ref ) {
print_indent ( indent + 1 ) ;
outln ( " PrivateMemberReference({}) " , ref . mode = = Mode : : Optional ? " Optional " : " Not Optional " ) ;
ref . private_identifier - > dump ( indent + 2 ) ;
2021-09-14 06:56:31 +04:30
} ) ;
}
}
2020-11-02 21:27:42 +00:00
void MetaProperty : : dump ( int indent ) const
{
2023-12-16 17:49:34 +03:30
ByteString name ;
2020-11-02 21:27:42 +00:00
if ( m_type = = MetaProperty : : Type : : NewTarget )
name = " new.target " ;
else if ( m_type = = MetaProperty : : Type : : ImportMeta )
name = " import.meta " ;
else
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2020-11-02 21:27:42 +00:00
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " {} {} " , class_name ( ) , name ) ;
2020-11-02 21:27:42 +00:00
}
2021-11-26 23:45:10 +01:00
void ImportCall : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
outln ( " (Specifier) " ) ;
m_specifier - > dump ( indent + 1 ) ;
if ( m_options ) {
outln ( " (Options) " ) ;
m_options - > dump ( indent + 1 ) ;
}
}
2020-06-03 16:05:49 -07:00
void RegExpLiteral : : dump ( int indent ) const
{
print_indent ( indent ) ;
2021-05-10 11:56:08 +01:00
outln ( " {} (/{}/{}) " , class_name ( ) , pattern ( ) , flags ( ) ) ;
2020-06-03 16:05:49 -07:00
}
2020-03-20 20:29:57 +01:00
void ArrayExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
for ( auto & element : m_elements ) {
2020-04-15 20:09:06 +01:00
if ( element ) {
element - > dump ( indent + 1 ) ;
} else {
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " <empty> " ) ;
2020-04-15 20:09:06 +01:00
}
2020-03-20 20:29:57 +01:00
}
}
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
void TemplateLiteral : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
2020-05-06 10:17:35 +01:00
for ( auto & expression : m_expressions )
2023-03-06 14:17:01 +01:00
expression - > dump ( indent + 1 ) ;
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
}
2020-05-06 10:17:35 +01:00
void TaggedTemplateLiteral : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Tag) " ) ;
2020-05-06 10:17:35 +01:00
m_tag - > dump ( indent + 2 ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Template Literal) " ) ;
2020-05-06 10:17:35 +01:00
m_template_literal - > dump ( indent + 2 ) ;
}
2020-03-24 14:03:55 +01:00
void TryStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Block) " ) ;
2020-03-24 14:03:55 +01:00
block ( ) . dump ( indent + 1 ) ;
if ( handler ( ) ) {
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Handler) " ) ;
2020-03-24 14:03:55 +01:00
handler ( ) - > dump ( indent + 1 ) ;
}
if ( finalizer ( ) ) {
print_indent ( indent ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Finalizer) " ) ;
2020-03-24 14:03:55 +01:00
finalizer ( ) - > dump ( indent + 1 ) ;
}
}
void CatchClause : : dump ( int indent ) const
{
print_indent ( indent ) ;
2025-04-21 19:49:38 +02:00
outln ( " CatchClause " ) ;
2021-07-11 15:15:38 +04:30
m_parameter . visit (
2025-04-21 19:49:38 +02:00
[ & ] ( NonnullRefPtr < Identifier const > const & parameter ) {
parameter - > dump ( indent + 1 ) ;
2021-07-11 15:15:38 +04:30
} ,
2023-02-19 22:07:52 +01:00
[ & ] ( NonnullRefPtr < BindingPattern const > const & pattern ) {
2021-07-11 15:15:38 +04:30
print_indent ( indent ) ;
outln ( " (Parameter) " ) ;
pattern - > dump ( indent + 2 ) ;
2025-04-21 19:49:38 +02:00
} ,
[ & ] ( Empty ) { } ) ;
2021-07-11 15:15:38 +04:30
2020-03-24 14:03:55 +01:00
body ( ) . dump ( indent + 1 ) ;
}
2020-03-24 22:03:50 +01:00
void ThrowStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
argument ( ) . dump ( indent + 1 ) ;
}
2020-03-29 13:09:54 +02:00
void SwitchStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
m_discriminant - > dump ( indent + 1 ) ;
for ( auto & switch_case : m_cases ) {
2023-03-06 14:17:01 +01:00
switch_case - > dump ( indent + 1 ) ;
2020-03-29 13:09:54 +02:00
}
}
void SwitchCase : : dump ( int indent ) const
{
2020-05-04 19:01:24 +01:00
print_indent ( indent + 1 ) ;
2020-03-29 13:09:54 +02:00
if ( m_test ) {
2020-12-06 16:55:19 +00:00
outln ( " (Test) " ) ;
2020-05-04 19:01:24 +01:00
m_test - > dump ( indent + 2 ) ;
2020-03-29 13:09:54 +02:00
} else {
2020-12-06 16:55:19 +00:00
outln ( " (Default) " ) ;
2020-03-29 13:09:54 +02:00
}
2020-05-04 19:01:24 +01:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Consequent) " ) ;
2021-09-22 12:44:56 +02:00
ScopeNode : : dump ( indent + 2 ) ;
2020-03-29 13:09:54 +02:00
}
2020-04-01 18:31:24 +01:00
2020-04-03 12:14:28 +02:00
void ConditionalExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Test) " ) ;
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
m_test - > dump ( indent + 2 ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Consequent) " ) ;
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
m_consequent - > dump ( indent + 2 ) ;
print_indent ( indent + 1 ) ;
2020-12-06 16:55:19 +00:00
outln ( " (Alternate) " ) ;
LibJS: Add template literals
Adds fully functioning template literals. Because template literals
contain expressions, most of the work has to be done in the Lexer rather
than the Parser. And because of the complexity of template literals
(expressions, nesting, escapes, etc), the Lexer needs to have some
template-related state.
When entering a new template literal, a TemplateLiteralStart token is
emitted. When inside a literal, all text will be parsed up until a '${'
or '`' (or EOF, but that's a syntax error) is seen, and then a
TemplateLiteralExprStart token is emitted. At this point, the Lexer
proceeds as normal, however it keeps track of the number of opening
and closing curly braces it has seen in order to determine the close
of the expression. Once it finds a matching curly brace for the '${',
a TemplateLiteralExprEnd token is emitted and the state is updated
accordingly.
When the Lexer is inside of a template literal, but not an expression,
and sees a '`', this must be the closing grave: a TemplateLiteralEnd
token is emitted.
The state required to correctly parse template strings consists of a
vector (for nesting) of two pieces of information: whether or not we
are in a template expression (as opposed to a template string); and
the count of the number of unmatched open curly braces we have seen
(only applicable if the Lexer is currently in a template expression).
TODO: Add support for template literal newlines in the JS REPL (this will
cause a syntax error currently):
> `foo
> bar`
'foo
bar'
2020-05-03 15:41:14 -07:00
m_alternate - > dump ( indent + 2 ) ;
2020-04-03 12:14:28 +02:00
}
2020-04-07 15:11:05 +02:00
void SequenceExpression : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
for ( auto & expression : m_expressions )
2023-03-06 14:17:01 +01:00
expression - > dump ( indent + 1 ) ;
2020-04-07 15:11:05 +02:00
}
2024-05-04 22:36:56 +02:00
bool ScopeNode : : has_non_local_lexical_declarations ( ) const
{
bool result = false ;
MUST ( for_each_lexically_declared_identifier ( [ & ] ( Identifier const & identifier ) {
if ( ! identifier . is_local ( ) )
result = true ;
} ) ) ;
return result ;
}
2022-02-07 13:31:01 +01:00
ThrowCompletionOr < void > ScopeNode : : for_each_lexically_scoped_declaration ( ThrowCompletionOrVoidCallback < Declaration const & > & & callback ) const
2021-09-22 12:44:56 +02:00
{
2022-02-07 13:31:01 +01:00
for ( auto & declaration : m_lexical_declarations )
TRY ( callback ( declaration ) ) ;
return { } ;
2021-09-22 12:44:56 +02:00
}
2023-07-06 17:49:38 +02:00
ThrowCompletionOr < void > ScopeNode : : for_each_lexically_declared_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
for ( auto const & declaration : m_lexical_declarations ) {
TRY ( declaration - > for_each_bound_identifier ( [ & ] ( auto const & identifier ) {
return callback ( identifier ) ;
} ) ) ;
}
return { } ;
}
2023-07-05 02:10:40 +02:00
ThrowCompletionOr < void > ScopeNode : : for_each_var_declared_identifier ( ThrowCompletionOrVoidCallback < Identifier const & > & & callback ) const
{
for ( auto & declaration : m_var_declarations ) {
TRY ( declaration - > for_each_bound_identifier ( [ & ] ( auto const & id ) {
return callback ( id ) ;
} ) ) ;
}
return { } ;
}
2022-02-07 13:31:01 +01:00
ThrowCompletionOr < void > ScopeNode : : for_each_var_function_declaration_in_reverse_order ( ThrowCompletionOrVoidCallback < FunctionDeclaration const & > & & callback ) const
2021-09-22 12:44:56 +02:00
{
for ( ssize_t i = m_var_declarations . size ( ) - 1 ; i > = 0 ; i - - ) {
auto & declaration = m_var_declarations [ i ] ;
2022-02-07 13:31:01 +01:00
if ( is < FunctionDeclaration > ( declaration ) )
2023-03-06 14:17:01 +01:00
TRY ( callback ( static_cast < FunctionDeclaration const & > ( * declaration ) ) ) ;
2021-09-22 12:44:56 +02:00
}
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
}
2022-02-07 13:31:01 +01:00
ThrowCompletionOr < void > ScopeNode : : for_each_var_scoped_variable_declaration ( ThrowCompletionOrVoidCallback < VariableDeclaration const & > & & callback ) const
2021-09-22 12:44:56 +02:00
{
for ( auto & declaration : m_var_declarations ) {
if ( ! is < FunctionDeclaration > ( declaration ) ) {
VERIFY ( is < VariableDeclaration > ( declaration ) ) ;
2023-03-06 14:17:01 +01:00
TRY ( callback ( static_cast < VariableDeclaration const & > ( * declaration ) ) ) ;
2021-09-22 12:44:56 +02:00
}
}
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
}
2022-02-07 13:31:01 +01:00
ThrowCompletionOr < void > ScopeNode : : for_each_function_hoistable_with_annexB_extension ( ThrowCompletionOrVoidCallback < FunctionDeclaration & > & & callback ) const
2021-09-22 12:44:56 +02:00
{
for ( auto & function : m_functions_hoistable_with_annexB_extension ) {
// We need const_cast here since it might have to set a property on function declaration.
2023-03-06 14:17:01 +01:00
TRY ( callback ( const_cast < FunctionDeclaration & > ( * function ) ) ) ;
2021-09-22 12:44:56 +02:00
}
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
}
2023-02-19 22:07:52 +01:00
void ScopeNode : : add_lexical_declaration ( NonnullRefPtr < Declaration const > declaration )
2020-04-13 16:42:54 +02:00
{
2021-09-22 12:44:56 +02:00
m_lexical_declarations . append ( move ( declaration ) ) ;
2020-04-13 16:42:54 +02:00
}
2023-02-19 22:07:52 +01:00
void ScopeNode : : add_var_scoped_declaration ( NonnullRefPtr < Declaration const > declaration )
2020-06-04 14:48:36 +02:00
{
2021-09-22 12:44:56 +02:00
m_var_declarations . append ( move ( declaration ) ) ;
2020-06-04 14:48:36 +02:00
}
2023-02-19 22:07:52 +01:00
void ScopeNode : : add_hoisted_function ( NonnullRefPtr < FunctionDeclaration const > declaration )
2021-07-04 03:15:52 +02:00
{
2021-09-22 12:44:56 +02:00
m_functions_hoistable_with_annexB_extension . append ( move ( declaration ) ) ;
2021-07-04 03:15:52 +02:00
}
2021-08-14 17:42:30 +02:00
2025-08-06 11:12:58 -04:00
Utf16FlyString ExportStatement : : local_name_for_default = " *default* " _utf16_fly_string ;
2022-01-16 23:51:28 +01:00
2021-12-20 15:29:25 +01:00
static void dump_assert_clauses ( ModuleRequest const & request )
{
2023-12-02 16:20:01 +01:00
if ( ! request . attributes . is_empty ( ) ) {
2021-12-20 15:29:25 +01:00
out ( " [ " ) ;
2023-12-02 16:20:01 +01:00
for ( auto & assertion : request . attributes )
2021-12-20 15:29:25 +01:00
out ( " {}: {}, " , assertion . key , assertion . value ) ;
out ( " ] " ) ;
}
}
2021-08-14 17:42:30 +02:00
void ExportStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
outln ( " (ExportEntries) " ) ;
2025-08-06 11:12:58 -04:00
auto string_or_null = [ ] < typename T > ( Optional < T > const & string ) - > ByteString {
2024-01-24 14:45:11 -05:00
if ( ! string . has_value ( ) ) {
2021-08-14 17:42:30 +02:00
return " null " ;
}
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " \" {} \" " , string ) ;
2021-08-14 17:42:30 +02:00
} ;
for ( auto & entry : m_entries ) {
print_indent ( indent + 2 ) ;
2022-01-27 01:54:47 +01:00
out ( " ExportName: {}, ImportName: {}, LocalName: {}, ModuleRequest: " ,
string_or_null ( entry . export_name ) ,
entry . is_module_request ( ) ? string_or_null ( entry . local_or_import_name ) : " null " ,
entry . is_module_request ( ) ? " null " : string_or_null ( entry . local_or_import_name ) ) ;
if ( entry . is_module_request ( ) ) {
out ( " {} " , entry . m_module_request - > module_specifier ) ;
dump_assert_clauses ( * entry . m_module_request ) ;
outln ( ) ;
} else {
outln ( " null " ) ;
}
2021-08-14 17:42:30 +02:00
}
2022-01-18 19:07:13 +01:00
if ( m_statement ) {
print_indent ( indent + 1 ) ;
outln ( " (Statement) " ) ;
m_statement - > dump ( indent + 2 ) ;
}
2021-08-14 17:42:30 +02:00
}
void ImportStatement : : dump ( int indent ) const
{
ASTNode : : dump ( indent ) ;
print_indent ( indent + 1 ) ;
if ( m_entries . is_empty ( ) ) {
// direct from "module" import
2021-12-20 15:29:25 +01:00
outln ( " Entire module '{}' " , m_module_request . module_specifier ) ;
dump_assert_clauses ( m_module_request ) ;
2021-08-14 17:42:30 +02:00
} else {
2021-12-20 15:29:25 +01:00
outln ( " (ExportEntries) from {} " , m_module_request . module_specifier ) ;
dump_assert_clauses ( m_module_request ) ;
2021-08-14 17:42:30 +02:00
for ( auto & entry : m_entries ) {
print_indent ( indent + 2 ) ;
outln ( " ImportName: {}, LocalName: {} " , entry . import_name , entry . local_name ) ;
}
}
}
2025-08-06 11:12:58 -04:00
bool ExportStatement : : has_export ( Utf16FlyString const & export_name ) const
2021-08-14 17:42:30 +02:00
{
return any_of ( m_entries . begin ( ) , m_entries . end ( ) , [ & ] ( auto & entry ) {
2022-08-29 22:12:25 +02:00
// Make sure that empty exported names does not overlap with anything
2022-09-01 22:55:02 +02:00
if ( entry . kind ! = ExportEntry : : Kind : : NamedExport )
2022-08-29 22:12:25 +02:00
return false ;
2021-08-14 17:42:30 +02:00
return entry . export_name = = export_name ;
} ) ;
}
2025-08-06 11:12:58 -04:00
bool ImportStatement : : has_bound_name ( Utf16FlyString const & name ) const
2021-08-14 17:42:30 +02:00
{
return any_of ( m_entries . begin ( ) , m_entries . end ( ) , [ & ] ( auto & entry ) {
return entry . local_name = = name ;
} ) ;
}
2021-09-22 12:44:56 +02:00
// 14.2.3 BlockDeclarationInstantiation ( code, env ), https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
2023-06-16 16:12:11 +02:00
void ScopeNode : : block_declaration_instantiation ( VM & vm , Environment * environment ) const
2021-09-22 12:44:56 +02:00
{
// See also B.3.2.6 Changes to BlockDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-blockdeclarationinstantiation
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2021-09-22 12:44:56 +02:00
VERIFY ( environment ) ;
2023-09-17 21:51:27 +12:00
// 1. Let declarations be the LexicallyScopedDeclarations of code.
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
2023-02-26 16:09:02 -07:00
auto private_environment = vm . running_execution_context ( ) . private_environment ;
2023-09-17 21:51:27 +12:00
2022-02-07 13:31:01 +01:00
// Note: All the calls here are ! and thus we do not need to TRY this callback.
2023-02-27 22:13:37 +00:00
// We use MUST to ensure it does not throw and to avoid discarding the returned ThrowCompletionOr<void>.
2023-09-17 21:51:27 +12:00
// 3. For each element d of declarations, do
2023-02-27 22:13:37 +00:00
MUST ( for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) {
2021-09-22 12:44:56 +02:00
auto is_constant_declaration = declaration . is_constant_declaration ( ) ;
2023-02-27 22:13:37 +00:00
// NOTE: Due to the use of MUST with `create_immutable_binding` and `create_mutable_binding` below,
// an exception should not result from `for_each_bound_name`.
2023-09-17 21:51:27 +12:00
// a. For each element dn of the BoundNames of d, do
2025-08-02 19:27:29 -04:00
MUST ( declaration . for_each_bound_identifier ( [ & ] ( Identifier const & identifier ) {
2023-08-11 17:23:56 +02:00
if ( identifier . is_local ( ) ) {
2023-07-09 20:01:22 +02:00
// NOTE: No need to create bindings for local variables as their values are not stored in an environment.
return ;
}
2025-08-06 11:12:58 -04:00
auto const & name = identifier . string ( ) ;
2025-08-02 19:27:29 -04:00
2023-09-17 21:51:27 +12:00
// i. If IsConstantDeclaration of d is true, then
2021-09-22 12:44:56 +02:00
if ( is_constant_declaration ) {
2023-09-17 21:51:27 +12:00
// 1. Perform ! env.CreateImmutableBinding(dn, true).
2022-08-21 15:12:43 +01:00
MUST ( environment - > create_immutable_binding ( vm , name , true ) ) ;
2023-09-17 21:51:27 +12:00
}
// ii. Else,
else {
// 1. Perform ! env.CreateMutableBinding(dn, false). NOTE: This step is replaced in section B.3.2.6.
2021-10-09 17:07:32 +01:00
if ( ! MUST ( environment - > has_binding ( name ) ) )
2022-08-21 15:12:43 +01:00
MUST ( environment - > create_mutable_binding ( vm , name , false ) ) ;
2021-09-22 12:44:56 +02:00
}
2023-02-27 22:13:37 +00:00
} ) ) ;
2021-09-22 12:44:56 +02:00
2023-09-17 21:51:27 +12:00
// b. If d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
2021-09-22 12:44:56 +02:00
if ( is < FunctionDeclaration > ( declaration ) ) {
2023-09-17 21:51:27 +12:00
// i. Let fn be the sole element of the BoundNames of d.
2021-09-22 12:44:56 +02:00
auto & function_declaration = static_cast < FunctionDeclaration const & > ( declaration ) ;
2023-09-17 21:51:27 +12:00
// ii. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
2025-04-07 21:08:55 +02:00
auto function = ECMAScriptFunctionObject : : create_from_function_node (
function_declaration ,
2025-08-06 11:12:58 -04:00
function_declaration . name ( ) ,
2025-04-07 21:08:55 +02:00
realm ,
environment ,
private_environment ) ;
2023-09-17 21:51:27 +12:00
// iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6.
2023-08-11 17:23:56 +02:00
if ( function_declaration . name_identifier ( ) - > is_local ( ) ) {
2024-05-12 18:49:03 +02:00
auto & running_execution_context = vm . running_execution_context ( ) ;
auto number_of_registers = running_execution_context . executable - > number_of_registers ;
auto number_of_constants = running_execution_context . executable - > constants . size ( ) ;
2025-04-25 17:10:47 +02:00
auto local_index = function_declaration . name_identifier ( ) - > local_index ( ) ;
if ( local_index . is_variable ( ) ) {
running_execution_context . local ( local_index . index + number_of_registers + number_of_constants ) = function ;
} else {
VERIFY_NOT_REACHED ( ) ;
}
2023-07-08 19:31:41 +02:00
} else {
VERIFY ( is < DeclarativeEnvironment > ( * environment ) ) ;
2025-08-02 19:27:29 -04:00
static_cast < DeclarativeEnvironment & > ( * environment ) . initialize_or_set_mutable_binding ( { } , vm , function - > name ( ) , function ) ;
2023-07-08 19:31:41 +02:00
}
2021-09-22 12:44:56 +02:00
}
2023-02-27 22:13:37 +00:00
} ) ) ;
2021-09-22 12:44:56 +02:00
}
// 16.1.7 GlobalDeclarationInstantiation ( script, env ), https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
2023-06-15 10:37:42 +02:00
ThrowCompletionOr < void > Program : : global_declaration_instantiation ( VM & vm , GlobalEnvironment & global_environment ) const
2021-09-22 12:44:56 +02:00
{
2022-08-22 19:00:49 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-08-16 00:20:49 +01:00
2022-02-07 13:31:01 +01:00
// 1. Let lexNames be the LexicallyDeclaredNames of script.
// 2. Let varNames be the VarDeclaredNames of script.
// 3. For each element name of lexNames, do
2023-07-06 17:49:38 +02:00
TRY ( for_each_lexically_declared_identifier ( [ & ] ( Identifier const & identifier ) - > ThrowCompletionOr < void > {
2025-08-06 11:12:58 -04:00
auto const & name = identifier . string ( ) ;
2023-07-06 17:49:38 +02:00
2025-04-28 17:02:01 -04:00
// a. If HasLexicalDeclaration(env, name) is true, throw a SyntaxError exception.
2022-02-07 13:31:01 +01:00
if ( global_environment . has_lexical_declaration ( name ) )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < SyntaxError > ( ErrorType : : TopLevelVariableAlreadyDeclared , name ) ;
2021-09-22 12:44:56 +02:00
2025-04-28 17:02:01 -04:00
// b. Let hasRestrictedGlobal be ? HasRestrictedGlobalProperty(env, name).
2022-02-07 13:31:01 +01:00
auto has_restricted_global = TRY ( global_environment . has_restricted_global_property ( name ) ) ;
2021-09-22 12:44:56 +02:00
2025-04-28 17:02:01 -04:00
// c. NOTE: Global var and function bindings (except those that are introduced by non-strict direct eval) are
// non-configurable and are therefore restricted global properties.
2022-02-07 13:31:01 +01:00
// d. If hasRestrictedGlobal is true, throw a SyntaxError exception.
if ( has_restricted_global )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < SyntaxError > ( ErrorType : : RestrictedGlobalProperty , name ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
return { } ;
} ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 4. For each element name of varNames, do
2025-08-02 19:27:29 -04:00
TRY ( for_each_var_declared_identifier ( [ & ] ( Identifier const & identifier ) - > ThrowCompletionOr < void > {
2022-02-07 13:31:01 +01:00
// a. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
2025-08-06 11:12:58 -04:00
if ( global_environment . has_lexical_declaration ( identifier . string ( ) ) )
2023-07-20 17:00:43 +02:00
return vm . throw_completion < SyntaxError > ( ErrorType : : TopLevelVariableAlreadyDeclared , identifier . string ( ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
return { } ;
} ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 5. Let varDeclarations be the VarScopedDeclarations of script.
// 6. Let functionsToInitialize be a new empty List.
Vector < FunctionDeclaration const & > functions_to_initialize ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 7. Let declaredFunctionNames be a new empty List.
2025-08-02 19:27:29 -04:00
HashTable < Utf16FlyString > declared_function_names ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 8. For each element d of varDeclarations, in reverse List order, do
TRY ( for_each_var_function_declaration_in_reverse_order ( [ & ] ( FunctionDeclaration const & function ) - > ThrowCompletionOr < void > {
2025-08-06 11:12:58 -04:00
auto function_name = function . name ( ) ;
2025-08-02 19:27:29 -04:00
2022-02-07 13:31:01 +01:00
// a. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
// i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
// Note: This is checked in for_each_var_function_declaration_in_reverse_order.
// ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
// iii. Let fn be the sole element of the BoundNames of d.
// iv. If fn is not an element of declaredFunctionNames, then
2025-08-02 19:27:29 -04:00
if ( declared_function_names . set ( function_name ) ! = AK : : HashSetResult : : InsertedNewEntry )
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn).
2025-08-02 19:27:29 -04:00
auto function_definable = TRY ( global_environment . can_declare_global_function ( function_name ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 2. If fnDefinable is false, throw a TypeError exception.
if ( ! function_definable )
2025-08-06 11:12:58 -04:00
return vm . throw_completion < TypeError > ( ErrorType : : CannotDeclareGlobalFunction , function_name ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 3. Append fn to declaredFunctionNames.
// Note: Already done in step iv. above.
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 4. Insert d as the first element of functionsToInitialize.
2022-11-17 01:39:59 +01:00
// NOTE: Since prepending is much slower, we just append
// and iterate in reverse order in step 16 below.
2022-02-07 13:31:01 +01:00
functions_to_initialize . append ( function ) ;
return { } ;
} ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 9. Let declaredVarNames be a new empty List.
2025-08-02 19:27:29 -04:00
HashTable < Utf16FlyString > declared_var_names ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 10. For each element d of varDeclarations, do
TRY ( for_each_var_scoped_variable_declaration ( [ & ] ( Declaration const & declaration ) {
// a. If d is a VariableDeclaration, a ForBinding, or a BindingIdentifier, then
// Note: This is done in for_each_var_scoped_variable_declaration.
// i. For each String vn of the BoundNames of d, do
2025-08-02 19:27:29 -04:00
return declaration . for_each_bound_identifier ( [ & ] ( Identifier const & identifier ) - > ThrowCompletionOr < void > {
2025-08-06 11:12:58 -04:00
auto const & name = identifier . string ( ) ;
2025-08-02 19:27:29 -04:00
2022-02-07 13:31:01 +01:00
// 1. If vn is not an element of declaredFunctionNames, then
2021-09-22 12:44:56 +02:00
if ( declared_function_names . contains ( name ) )
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// a. Let vnDefinable be ? env.CanDeclareGlobalVar(vn).
auto var_definable = TRY ( global_environment . can_declare_global_var ( name ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// b. If vnDefinable is false, throw a TypeError exception.
if ( ! var_definable )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : CannotDeclareGlobalVariable , name ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// c. If vn is not an element of declaredVarNames, then
// i. Append vn to declaredVarNames.
2021-09-22 12:44:56 +02:00
declared_var_names . set ( name ) ;
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
} ) ;
2022-02-07 13:31:01 +01:00
} ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 11. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. However, if the global object is a Proxy exotic object it may exhibit behaviours that cause abnormal terminations in some of the following steps.
// 12. NOTE: Annex B.3.2.2 adds additional steps at this point.
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 12. Let strict be IsStrict of script.
// 13. If strict is false, then
2021-09-22 12:44:56 +02:00
if ( ! m_is_strict_mode ) {
2022-02-07 13:31:01 +01:00
// a. Let declaredFunctionOrVarNames be the list-concatenation of declaredFunctionNames and declaredVarNames.
// b. For each FunctionDeclaration f that is directly contained in the StatementList of a Block, CaseClause, or DefaultClause Contained within script, do
TRY ( for_each_function_hoistable_with_annexB_extension ( [ & ] ( FunctionDeclaration & function_declaration ) - > ThrowCompletionOr < void > {
// i. Let F be StringValue of the BindingIdentifier of f.
2025-08-06 11:12:58 -04:00
auto function_name = function_declaration . name ( ) ;
2022-02-07 13:31:01 +01:00
// ii. If replacing the FunctionDeclaration f with a VariableStatement that has F as a BindingIdentifier would not produce any Early Errors for script, then
// Note: This step is already performed during parsing and for_each_function_hoistable_with_annexB_extension so this always passes here.
// 1. If env.HasLexicalDeclaration(F) is false, then
2021-09-22 12:44:56 +02:00
if ( global_environment . has_lexical_declaration ( function_name ) )
2022-02-07 13:31:01 +01:00
return { } ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// a. Let fnDefinable be ? env.CanDeclareGlobalVar(F).
auto function_definable = TRY ( global_environment . can_declare_global_function ( function_name ) ) ;
// b. If fnDefinable is true, then
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
if ( ! function_definable )
return { } ;
// i. NOTE: A var binding for F is only instantiated here if it is neither a VarDeclaredName nor the name of another FunctionDeclaration.
// ii. If declaredFunctionOrVarNames does not contain F, then
2021-09-22 12:44:56 +02:00
if ( ! declared_function_names . contains ( function_name ) & & ! declared_var_names . contains ( function_name ) ) {
2022-02-07 13:31:01 +01:00
// i. Perform ? env.CreateGlobalVarBinding(F, false).
TRY ( global_environment . create_global_var_binding ( function_name , false ) ) ;
// ii. Append F to declaredFunctionOrVarNames.
2021-09-22 12:44:56 +02:00
declared_function_names . set ( function_name ) ;
}
2022-02-07 13:31:01 +01:00
// iii. When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6:
// i. Let genv be the running execution context's VariableEnvironment.
// ii. Let benv be the running execution context's LexicalEnvironment.
// iii. Let fobj be ! benv.GetBindingValue(F, false).
// iv. Perform ? genv.SetMutableBinding(F, fobj, false).
2022-05-02 20:54:39 +02:00
// v. Return unused.
2021-09-22 12:44:56 +02:00
function_declaration . set_should_do_additional_annexB_steps ( ) ;
2022-02-07 13:31:01 +01:00
return { } ;
} ) ) ;
2021-09-22 12:44:56 +02:00
// We should not use declared function names below here anymore since these functions are not in there in the spec.
declared_function_names . clear ( ) ;
}
2022-02-07 13:31:01 +01:00
// 13. Let lexDeclarations be the LexicallyScopedDeclarations of script.
// 14. Let privateEnv be null.
2021-10-11 20:29:31 +02:00
PrivateEnvironment * private_environment = nullptr ;
2022-02-07 13:31:01 +01:00
// 15. For each element d of lexDeclarations, do
TRY ( for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) {
// a. NOTE: Lexically declared names are only instantiated here but not initialized.
// b. For each element dn of the BoundNames of d, do
2025-08-02 19:27:29 -04:00
return declaration . for_each_bound_identifier ( [ & ] ( Identifier const & identifier ) - > ThrowCompletionOr < void > {
2025-08-06 11:12:58 -04:00
auto const & name = identifier . string ( ) ;
2025-08-02 19:27:29 -04:00
2022-02-07 13:31:01 +01:00
// i. If IsConstantDeclaration of d is true, then
if ( declaration . is_constant_declaration ( ) ) {
// 1. Perform ? env.CreateImmutableBinding(dn, true).
2022-08-21 15:12:43 +01:00
TRY ( global_environment . create_immutable_binding ( vm , name , true ) ) ;
2022-02-07 13:31:01 +01:00
}
// ii. Else,
else {
// 1. Perform ? env.CreateMutableBinding(dn, false).
2022-08-21 15:12:43 +01:00
TRY ( global_environment . create_mutable_binding ( vm , name , false ) ) ;
2022-02-07 13:31:01 +01:00
}
return { } ;
2021-09-22 12:44:56 +02:00
} ) ;
2022-02-07 13:31:01 +01:00
} ) ) ;
2021-09-22 12:44:56 +02:00
2022-02-07 13:31:01 +01:00
// 16. For each Parse Node f of functionsToInitialize, do
2022-11-17 01:39:59 +01:00
// NOTE: We iterate in reverse order since we appended the functions
// instead of prepending. We append because prepending is much slower
// and we only use the created vector here.
for ( auto & declaration : functions_to_initialize . in_reverse ( ) ) {
2022-02-07 13:31:01 +01:00
// a. Let fn be the sole element of the BoundNames of f.
// b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
2025-04-07 21:08:55 +02:00
auto function = ECMAScriptFunctionObject : : create_from_function_node (
declaration ,
2025-08-06 11:12:58 -04:00
declaration . name ( ) ,
2025-04-07 21:08:55 +02:00
realm ,
& global_environment ,
private_environment ) ;
2022-02-07 13:31:01 +01:00
// c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
2025-08-02 19:27:29 -04:00
TRY ( global_environment . create_global_function_binding ( function - > name ( ) , function , false ) ) ;
2021-09-22 12:44:56 +02:00
}
2022-02-07 13:31:01 +01:00
// 17. For each String vn of declaredVarNames, do
for ( auto & var_name : declared_var_names ) {
// a. Perform ? env.CreateGlobalVarBinding(vn, false).
2021-12-29 16:00:36 +01:00
TRY ( global_environment . create_global_var_binding ( var_name , false ) ) ;
2022-02-07 13:31:01 +01:00
}
2021-09-22 12:44:56 +02:00
2022-05-02 20:54:39 +02:00
// 18. Return unused.
2021-09-22 12:44:56 +02:00
return { } ;
}
2025-08-06 11:12:58 -04:00
ModuleRequest : : ModuleRequest ( Utf16FlyString module_specifier_ , Vector < ImportAttribute > attributes )
2022-01-27 02:44:03 +01:00
: module_specifier ( move ( module_specifier_ ) )
2023-12-02 16:20:01 +01:00
, attributes ( move ( attributes ) )
2022-01-27 02:44:03 +01:00
{
2025-04-28 15:03:56 -04:00
// 13.3.10.2 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/ecma262/#sec-evaluate-import-call
// 16.2.2.4 Static Semantics: WithClauseToAttributes, https://tc39.es/ecma262/#sec-withclausetoattributes
// 2. Sort attributes according to the lexicographic order of their [[Key]] field, treating the value of each such
// field as a sequence of UTF-16 code unit values.
2023-12-02 16:20:01 +01:00
quick_sort ( this - > attributes , [ ] ( ImportAttribute const & lhs , ImportAttribute const & rhs ) {
2022-01-27 02:44:03 +01:00
return lhs . key < rhs . key ;
} ) ;
}
2023-12-16 17:49:34 +03:30
ByteString SourceRange : : filename ( ) const
LibJS: Reduce AST memory usage by shrink-wrapping source range info
Before this change, each AST node had a 64-byte SourceRange member.
This SourceRange had the following layout:
filename: StringView (16 bytes)
start: Position (24 bytes)
end: Position (24 bytes)
The Position structs have { line, column, offset }, all members size_t.
To reduce memory consumption, AST nodes now only store the following:
source_code: NonnullRefPtr<SourceCode> (8 bytes)
start_offset: u32 (4 bytes)
end_offset: u32 (4 bytes)
SourceCode is a new ref-counted data structure that keeps the filename
and original parsed source code in a single location, and all AST nodes
have a pointer to it.
The start_offset and end_offset can be turned into (line, column) when
necessary by calling SourceCode::range_from_offsets(). This will walk
the source code string and compute line/column numbers on the fly, so
it's not necessarily fast, but it should be rare since this information
is primarily used for diagnostics and exception stack traces.
With this, ASTNode shrinks from 80 bytes to 32 bytes. This gives us a
~23% reduction in memory usage when loading twitter.com/awesomekling
(330 MiB before, 253 MiB after!) :^)
2022-11-21 17:37:38 +01:00
{
2023-12-16 17:49:34 +03:30
return code - > filename ( ) . to_byte_string ( ) ;
LibJS: Reduce AST memory usage by shrink-wrapping source range info
Before this change, each AST node had a 64-byte SourceRange member.
This SourceRange had the following layout:
filename: StringView (16 bytes)
start: Position (24 bytes)
end: Position (24 bytes)
The Position structs have { line, column, offset }, all members size_t.
To reduce memory consumption, AST nodes now only store the following:
source_code: NonnullRefPtr<SourceCode> (8 bytes)
start_offset: u32 (4 bytes)
end_offset: u32 (4 bytes)
SourceCode is a new ref-counted data structure that keeps the filename
and original parsed source code in a single location, and all AST nodes
have a pointer to it.
The start_offset and end_offset can be turned into (line, column) when
necessary by calling SourceCode::range_from_offsets(). This will walk
the source code string and compute line/column numbers on the fly, so
it's not necessarily fast, but it should be rare since this information
is primarily used for diagnostics and exception stack traces.
With this, ASTNode shrinks from 80 bytes to 32 bytes. This gives us a
~23% reduction in memory usage when loading twitter.com/awesomekling
(330 MiB before, 253 MiB after!) :^)
2022-11-21 17:37:38 +01:00
}
2023-06-15 15:13:48 +05:30
NonnullRefPtr < CallExpression > CallExpression : : create ( SourceRange source_range , NonnullRefPtr < Expression const > callee , ReadonlySpan < Argument > arguments , InvocationStyleEnum invocation_style , InsideParenthesesEnum inside_parens )
2022-11-26 19:51:50 +01:00
{
2023-06-15 15:13:48 +05:30
return ASTNodeWithTailArray : : create < CallExpression > ( arguments . size ( ) , move ( source_range ) , move ( callee ) , arguments , invocation_style , inside_parens ) ;
2022-11-26 19:51:50 +01:00
}
2023-06-15 15:13:48 +05:30
NonnullRefPtr < NewExpression > NewExpression : : create ( SourceRange source_range , NonnullRefPtr < Expression const > callee , ReadonlySpan < Argument > arguments , InvocationStyleEnum invocation_style , InsideParenthesesEnum inside_parens )
2022-11-26 19:51:50 +01:00
{
2023-06-15 15:13:48 +05:30
return ASTNodeWithTailArray : : create < NewExpression > ( arguments . size ( ) , move ( source_range ) , move ( callee ) , arguments , invocation_style , inside_parens ) ;
2022-11-26 19:51:50 +01:00
}
2025-03-27 12:59:50 +00:00
NonnullRefPtr < FunctionParameters > FunctionParameters : : empty ( )
{
static auto empty = adopt_ref ( * new FunctionParameters ( { } ) ) ;
return empty ;
}
2020-03-07 19:42:11 +01:00
}