2020-04-15 21:58:22 +02:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < andreas @ ladybird . org >
2020-04-15 21:58:22 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-04-15 21:58:22 +02:00
*/
2022-12-20 22:09:57 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/DeclarativeEnvironment.h>
2020-06-08 13:31:21 -05:00
# include <LibJS/Runtime/Error.h>
2021-06-27 21:48:34 +02:00
# include <LibJS/Runtime/FunctionObject.h>
2020-09-27 15:18:55 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2020-06-08 13:31:21 -05:00
# include <LibJS/Runtime/Value.h>
2020-04-15 21:58:22 +02:00
namespace JS {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( DeclarativeEnvironment ) ;
2023-11-19 09:45:05 +01:00
2022-03-09 15:37:10 -05:00
DeclarativeEnvironment * DeclarativeEnvironment : : create_for_per_iteration_bindings ( Badge < ForStatement > , DeclarativeEnvironment & other , size_t bindings_size )
{
auto bindings = other . m_bindings . span ( ) . slice ( 0 , bindings_size ) ;
2022-05-01 01:10:05 +02:00
auto * parent_environment = other . outer_environment ( ) ;
2022-03-09 15:37:10 -05:00
2024-11-14 06:13:46 +13:00
return parent_environment - > heap ( ) . allocate < DeclarativeEnvironment > ( parent_environment , bindings ) ;
2022-03-09 15:37:10 -05:00
}
2021-07-01 12:24:46 +02:00
DeclarativeEnvironment : : DeclarativeEnvironment ( )
2024-05-11 13:31:33 +02:00
: Environment ( nullptr , IsDeclarative : : Yes )
2020-04-15 21:58:22 +02:00
{
}
2022-05-01 01:10:05 +02:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment )
2024-05-11 13:31:33 +02:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2021-06-22 00:56:14 +02:00
{
}
2023-02-05 19:02:54 +00:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment , ReadonlySpan < Binding > bindings )
2024-05-11 13:31:33 +02:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2022-03-09 15:37:10 -05:00
, m_bindings ( bindings )
{
}
2021-07-01 12:24:46 +02:00
void DeclarativeEnvironment : : visit_edges ( Visitor & visitor )
2020-04-15 21:58:22 +02:00
{
2021-01-28 10:13:47 +01:00
Base : : visit_edges ( visitor ) ;
2021-10-06 23:38:46 +02:00
for ( auto & binding : m_bindings )
visitor . visit ( binding . value ) ;
2022-12-20 22:09:57 +01:00
for ( auto & disposable : m_disposable_resource_stack ) {
visitor . visit ( disposable . resource_value ) ;
visitor . visit ( disposable . dispose_method ) ;
}
2020-04-15 21:58:22 +02:00
}
2021-06-23 12:26:37 +02:00
// 9.1.1.1.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : has_binding ( DeprecatedFlyString const & name , Optional < size_t > * out_index ) const
2021-06-23 12:26:37 +02:00
{
2022-09-01 23:22:17 +02:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) )
2021-10-06 23:53:22 +02:00
return false ;
2022-09-01 23:22:17 +02:00
if ( ! is_permanently_screwed_by_eval ( ) & & out_index & & binding_and_index - > index ( ) . has_value ( ) )
* out_index = * ( binding_and_index - > index ( ) ) ;
2021-10-06 23:53:22 +02:00
return true ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.2 CreateMutableBinding ( N, D ), https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_mutable_binding ( VM & , DeprecatedFlyString const & name , bool can_be_deleted )
2021-06-23 12:26:37 +02:00
{
2022-05-02 20:54:39 +02:00
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
2021-10-09 18:53:25 +01:00
// 2. Create a mutable binding in envRec for N and record that it is uninitialized. If D is true, record that the newly created binding may be deleted by a subsequent DeleteBinding call.
2024-10-24 10:32:04 +02:00
m_bindings_assoc . set ( name , m_bindings . size ( ) ) ;
2021-10-06 23:38:46 +02:00
m_bindings . append ( Binding {
2022-03-08 11:56:42 -05:00
. name = name ,
2021-10-06 23:38:46 +02:00
. value = { } ,
. strict = false ,
. mutable_ = true ,
. can_be_deleted = can_be_deleted ,
. initialized = false ,
} ) ;
2021-10-09 18:53:25 +01:00
2023-07-12 14:30:51 +02:00
+ + m_environment_serial_number ;
2022-05-02 20:54:39 +02:00
// 3. Return unused.
2021-10-09 18:53:25 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.3 CreateImmutableBinding ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-createimmutablebinding-n-s
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_immutable_binding ( VM & , DeprecatedFlyString const & name , bool strict )
2021-06-23 12:26:37 +02:00
{
2022-05-02 20:54:39 +02:00
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
2021-10-09 19:00:06 +01:00
// 2. Create an immutable binding in envRec for N and record that it is uninitialized. If S is true, record that the newly created binding is a strict binding.
2024-10-24 10:32:04 +02:00
m_bindings_assoc . set ( name , m_bindings . size ( ) ) ;
2021-10-06 23:38:46 +02:00
m_bindings . append ( Binding {
2022-03-08 11:56:42 -05:00
. name = name ,
2021-10-06 23:38:46 +02:00
. value = { } ,
. strict = strict ,
. mutable_ = false ,
. can_be_deleted = false ,
. initialized = false ,
} ) ;
2021-10-09 19:00:06 +01:00
2023-07-12 14:30:51 +02:00
+ + m_environment_serial_number ;
2022-05-02 20:54:39 +02:00
// 3. Return unused.
2021-10-09 19:00:06 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.4 InitializeBinding ( N, V ), https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
2022-12-14 13:26:10 +01:00
// 4.1.1.1.1 InitializeBinding ( N, V, hint ), https://tc39.es/proposal-explicit-resource-management/#sec-declarative-environment-records
2022-12-20 22:09:57 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding ( VM & vm , DeprecatedFlyString const & name , Value value , Environment : : InitializeBindingHint hint )
2021-06-23 12:26:37 +02:00
{
2024-05-13 22:03:52 +02:00
return initialize_binding_direct ( vm , find_binding_and_index ( name ) - > index ( ) . value ( ) , value , hint ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding_direct ( VM & vm , size_t index , Value value , Environment : : InitializeBindingHint hint )
{
auto & binding = m_bindings . at ( index ) ;
2022-03-08 12:02:55 -05:00
2021-10-09 19:16:24 +01:00
// 1. Assert: envRec must have an uninitialized binding for N.
2021-10-06 23:38:46 +02:00
VERIFY ( binding . initialized = = false ) ;
2021-10-09 19:16:24 +01:00
2022-12-20 22:09:57 +01:00
// 2. If hint is not normal, perform ? AddDisposableResource(envRec, V, hint).
if ( hint ! = Environment : : InitializeBindingHint : : Normal )
TRY ( add_disposable_resource ( vm , m_disposable_resource_stack , value , hint ) ) ;
2022-12-14 13:26:10 +01:00
// 3. Set the bound value for N in envRec to V.
2021-10-06 23:38:46 +02:00
binding . value = value ;
2021-10-09 19:16:24 +01:00
2022-12-14 13:26:10 +01:00
// 4. Record that the binding for N in envRec has been initialized.
2021-10-06 23:38:46 +02:00
binding . initialized = true ;
2021-10-09 19:16:24 +01:00
2022-12-14 13:26:10 +01:00
// 5. Return unused.
2021-10-09 19:16:24 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.5 SetMutableBinding ( N, V, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding ( VM & vm , DeprecatedFlyString const & name , Value value , bool strict )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:34:54 +01:00
// 1. If envRec does not have a binding for N, then
2022-09-01 23:22:17 +02:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) ) {
2021-10-09 19:34:54 +01:00
// a. If S is true, throw a ReferenceError exception.
if ( strict )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < ReferenceError > ( ErrorType : : UnknownIdentifier , name ) ;
2021-10-09 19:34:54 +01:00
2022-05-24 18:19:49 +01:00
// b. Perform ! envRec.CreateMutableBinding(N, true).
2022-08-21 15:12:43 +01:00
MUST ( create_mutable_binding ( vm , name , true ) ) ;
2021-10-09 19:34:54 +01:00
2022-12-14 13:26:10 +01:00
// c. Perform ! envRec.InitializeBinding(N, V, normal).
MUST ( initialize_binding ( vm , name , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-10-09 19:34:54 +01:00
2022-05-02 20:54:39 +02:00
// d. Return unused.
2021-10-09 19:34:54 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-10-09 19:34:54 +01:00
// 2-5. (extracted into a non-standard function below)
2022-09-01 23:22:17 +02:00
TRY ( set_mutable_binding_direct ( vm , binding_and_index - > binding ( ) , value , strict ) ) ;
2021-10-09 19:34:54 +01:00
2022-05-02 20:54:39 +02:00
// 6. Return unused.
2021-10-09 19:34:54 +01:00
return { } ;
2021-10-07 00:10:00 +02:00
}
2022-08-21 15:12:43 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , size_t index , Value value , bool strict )
2021-10-07 00:10:00 +02:00
{
2022-09-01 23:22:17 +02:00
return set_mutable_binding_direct ( vm , m_bindings [ index ] , value , strict ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , Binding & binding , Value value , bool strict )
{
2021-10-06 23:38:46 +02:00
if ( binding . strict )
2021-06-23 12:26:37 +02:00
strict = true ;
2021-10-09 19:34:54 +01:00
if ( ! binding . initialized )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < ReferenceError > ( ErrorType : : BindingNotInitialized , binding . name ) ;
2021-06-23 12:26:37 +02:00
2021-10-06 23:38:46 +02:00
if ( binding . mutable_ ) {
binding . value = value ;
2021-06-23 12:26:37 +02:00
} else {
2021-10-09 19:34:54 +01:00
if ( strict )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : InvalidAssignToConst ) ;
2021-06-23 12:26:37 +02:00
}
2021-10-09 19:34:54 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
2024-05-11 17:22:59 +02:00
ThrowCompletionOr < Value > DeclarativeEnvironment : : get_binding_value ( VM & vm , DeprecatedFlyString const & name , [[maybe_unused]] bool strict )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:43:19 +01:00
// 1. Assert: envRec has a binding for N.
2022-09-01 23:22:17 +02:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 19:43:19 +01:00
// 2-3. (extracted into a non-standard function below)
2024-05-11 17:22:59 +02:00
return get_binding_value_direct ( vm , binding_and_index - > binding ( ) ) ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : delete_binding ( VM & , DeprecatedFlyString const & name )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:49:08 +01:00
// 1. Assert: envRec has a binding for the name that is the value of N.
2022-09-01 23:22:17 +02:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 19:49:08 +01:00
// 2. If the binding for N in envRec cannot be deleted, return false.
2022-09-01 23:22:17 +02:00
if ( ! binding_and_index - > binding ( ) . can_be_deleted )
2021-06-23 12:26:37 +02:00
return false ;
2021-10-09 19:49:08 +01:00
// 3. Remove the binding for N from envRec.
2022-03-08 11:56:42 -05:00
// NOTE: We keep the entries in m_bindings to avoid disturbing indices.
2022-09-01 23:22:17 +02:00
binding_and_index - > binding ( ) = { } ;
2021-10-09 19:49:08 +01:00
2023-07-12 14:30:51 +02:00
+ + m_environment_serial_number ;
2021-10-09 19:49:08 +01:00
// 4. Return true.
2021-06-23 12:26:37 +02:00
return true ;
}
2023-01-08 19:23:00 -05:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_or_set_mutable_binding ( VM & vm , DeprecatedFlyString const & name , Value value )
2021-09-22 12:44:56 +02:00
{
2022-09-01 23:22:17 +02:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
if ( ! binding_and_index - > binding ( ) . initialized )
2022-12-14 13:26:10 +01:00
TRY ( initialize_binding ( vm , name , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-09-22 12:44:56 +02:00
else
2022-08-21 15:12:43 +01:00
TRY ( set_mutable_binding ( vm , name , value , false ) ) ;
2022-02-12 19:48:45 +03:30
return { } ;
}
2023-01-08 19:23:00 -05:00
void DeclarativeEnvironment : : initialize_or_set_mutable_binding ( Badge < ScopeNode > , VM & vm , DeprecatedFlyString const & name , Value value )
2022-02-12 19:48:45 +03:30
{
2022-08-21 15:12:43 +01:00
MUST ( initialize_or_set_mutable_binding ( vm , name , value ) ) ;
2021-09-22 12:44:56 +02:00
}
2022-11-26 20:33:52 +01:00
void DeclarativeEnvironment : : shrink_to_fit ( )
{
m_bindings . shrink_to_fit ( ) ;
}
2020-04-15 21:58:22 +02:00
}