| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  | #include <LibJS/Runtime/Error.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Reference.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace JS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  | void Reference::put(GlobalObject& global_object, Value value) | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |     auto& vm = global_object.vm(); | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |     if (is_unresolvable()) { | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |         throw_reference_error(global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |     if (is_local_variable() || is_global_variable()) { | 
					
						
							|  |  |  |         if (is_local_variable()) | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |             vm.set_variable(m_name.to_string(), value, global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2020-06-20 16:47:31 +02:00
										 |  |  |             global_object.put(m_name, value); | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-02 21:00:37 +02:00
										 |  |  |     auto base = this->base(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!base.is_object() && vm.in_strict_mode()) { | 
					
						
							|  |  |  |         if (base.is_nullish()) | 
					
						
							| 
									
										
										
										
											2021-04-14 22:17:42 +02:00
										 |  |  |             vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishSetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects()); | 
					
						
							| 
									
										
										
										
											2021-04-02 21:00:37 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2021-04-14 22:17:42 +02:00
										 |  |  |             vm.throw_exception<TypeError>(global_object, ErrorType::ReferencePrimitiveSetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.typeof(), base.to_string_without_side_effects()); | 
					
						
							| 
									
										
										
										
											2020-05-28 17:48:25 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-02 21:00:37 +02:00
										 |  |  |     if (base.is_nullish()) { | 
					
						
							|  |  |  |         // This will always fail the to_object() call below, let's throw the TypeError ourselves with a nice message instead.
 | 
					
						
							| 
									
										
										
										
											2021-04-14 22:17:42 +02:00
										 |  |  |         vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishSetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects()); | 
					
						
							| 
									
										
										
										
											2021-04-02 21:00:37 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto* object = base.to_object(global_object); | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  |     if (!object) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     object->put(m_name, value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  | void Reference::throw_reference_error(GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-04-02 21:00:37 +02:00
										 |  |  |     auto& vm = global_object.vm(); | 
					
						
							|  |  |  |     if (!m_name.is_valid()) | 
					
						
							|  |  |  |         vm.throw_exception<ReferenceError>(global_object, ErrorType::ReferenceUnresolvable); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         vm.throw_exception<ReferenceError>(global_object, ErrorType::UnknownIdentifier, m_name.to_string_or_symbol().to_display_string()); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  | Value Reference::get(GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |     auto& vm = global_object.vm(); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (is_unresolvable()) { | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |         throw_reference_error(global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_local_variable() || is_global_variable()) { | 
					
						
							|  |  |  |         Value value; | 
					
						
							|  |  |  |         if (is_local_variable()) | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |             value = vm.get_variable(m_name.to_string(), global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2020-06-20 16:47:31 +02:00
										 |  |  |             value = global_object.get(m_name); | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |         if (vm.exception()) | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |             return {}; | 
					
						
							|  |  |  |         if (value.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-09-29 16:45:24 +02:00
										 |  |  |             throw_reference_error(global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |             return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-14 22:17:42 +02:00
										 |  |  |     auto base = this->base(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (base.is_nullish()) { | 
					
						
							|  |  |  |         // This will always fail the to_object() call below, let's throw the TypeError ourselves with a nice message instead.
 | 
					
						
							|  |  |  |         vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishGetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects()); | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto* object = base.to_object(global_object); | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |     if (!object) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return object->get(m_name).value_or(js_undefined()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 04:00:53 +03:00
										 |  |  | bool Reference::delete_(GlobalObject& global_object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_unresolvable()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& vm = global_object.vm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_local_variable() || is_global_variable()) { | 
					
						
							|  |  |  |         if (is_local_variable()) | 
					
						
							|  |  |  |             return vm.delete_variable(m_name.to_string()); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             return global_object.delete_property(m_name); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto base = this->base(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (base.is_nullish()) { | 
					
						
							|  |  |  |         // This will always fail the to_object() call below, let's throw the TypeError ourselves with a nice message instead.
 | 
					
						
							|  |  |  |         vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishDeleteProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects()); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto* object = base.to_object(global_object); | 
					
						
							|  |  |  |     VERIFY(object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return object->delete_property(m_name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-27 12:56:09 +02:00
										 |  |  | } |