Reference.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/AST.h>
  7. #include <LibJS/Runtime/DeclarativeEnvironment.h>
  8. #include <LibJS/Runtime/Error.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. #include <LibJS/Runtime/Reference.h>
  11. namespace JS {
  12. // 6.2.4.6 PutValue ( V, W ), https://tc39.es/ecma262/#sec-putvalue
  13. void Reference::put_value(GlobalObject& global_object, Value value)
  14. {
  15. auto& vm = global_object.vm();
  16. if (!is_valid_reference()) {
  17. vm.throw_exception<ReferenceError>(global_object, ErrorType::InvalidLeftHandAssignment);
  18. return;
  19. }
  20. if (is_unresolvable()) {
  21. if (m_strict) {
  22. throw_reference_error(global_object);
  23. return;
  24. }
  25. MUST(global_object.set(m_name, value, Object::ShouldThrowExceptions::No));
  26. return;
  27. }
  28. if (is_property_reference()) {
  29. auto* base_obj = m_base_value.to_object(global_object);
  30. if (!base_obj)
  31. return;
  32. auto succeeded_or_error = base_obj->internal_set(m_name, value, get_this_value());
  33. if (succeeded_or_error.is_error())
  34. return;
  35. auto succeeded = succeeded_or_error.release_value();
  36. if (!succeeded && m_strict) {
  37. vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishSetProperty, m_name, m_base_value.to_string_without_side_effects());
  38. return;
  39. }
  40. return;
  41. }
  42. VERIFY(m_base_type == BaseType::Environment);
  43. // Note: Optimisation, not from the spec.
  44. if (m_function_argument_index.has_value()) {
  45. // Note: Modifying this binding requires us to sync with the environment.
  46. if (!m_base_environment) {
  47. auto real_reference = global_object.vm().resolve_binding(m_name.as_string(), m_referenced_function_context->lexical_environment);
  48. m_base_environment = real_reference.m_base_environment;
  49. }
  50. if (!global_object.vm().execution_context_stack().is_empty() && m_referenced_function_context == &global_object.vm().running_execution_context()) {
  51. auto& arguments = m_referenced_function_context->arguments;
  52. auto index = m_function_argument_index.value();
  53. if (arguments.size() > index) {
  54. arguments[index] = value;
  55. } else {
  56. arguments.ensure_capacity(index + 1);
  57. for (size_t i = arguments.size(); i < index; ++i)
  58. arguments.append(js_undefined());
  59. arguments.append(value);
  60. }
  61. m_base_environment->set_mutable_binding(global_object, name().as_string(), value, is_strict());
  62. return;
  63. }
  64. }
  65. VERIFY(m_base_environment);
  66. if (m_environment_coordinate.has_value())
  67. static_cast<DeclarativeEnvironment*>(m_base_environment)->set_mutable_binding_direct(global_object, m_environment_coordinate->index, value, m_strict);
  68. else
  69. m_base_environment->set_mutable_binding(global_object, m_name.as_string(), value, m_strict);
  70. }
  71. void Reference::throw_reference_error(GlobalObject& global_object) const
  72. {
  73. auto& vm = global_object.vm();
  74. if (!m_name.is_valid())
  75. vm.throw_exception<ReferenceError>(global_object, ErrorType::ReferenceUnresolvable);
  76. else
  77. vm.throw_exception<ReferenceError>(global_object, ErrorType::UnknownIdentifier, m_name.to_string_or_symbol().to_display_string());
  78. }
  79. // 6.2.4.5 GetValue ( V ), https://tc39.es/ecma262/#sec-getvalue
  80. Value Reference::get_value(GlobalObject& global_object) const
  81. {
  82. if (!is_valid_reference() || is_unresolvable()) {
  83. throw_reference_error(global_object);
  84. return {};
  85. }
  86. if (is_property_reference()) {
  87. auto* base_obj = m_base_value.to_object(global_object);
  88. if (!base_obj)
  89. return {};
  90. return TRY_OR_DISCARD(base_obj->get(m_name));
  91. }
  92. VERIFY(m_base_type == BaseType::Environment);
  93. // Note: Optimisation, not from the spec.
  94. if (m_function_argument_index.has_value()) {
  95. if (!global_object.vm().execution_context_stack().is_empty() && m_referenced_function_context == &global_object.vm().running_execution_context())
  96. return global_object.vm().argument(m_function_argument_index.value());
  97. if (!m_base_environment) {
  98. auto real_reference = global_object.vm().resolve_binding(m_name.as_string(), m_referenced_function_context->lexical_environment);
  99. m_base_environment = real_reference.m_base_environment;
  100. }
  101. }
  102. VERIFY(m_base_environment);
  103. if (m_environment_coordinate.has_value())
  104. return static_cast<DeclarativeEnvironment*>(m_base_environment)->get_binding_value_direct(global_object, m_environment_coordinate->index, m_strict);
  105. return m_base_environment->get_binding_value(global_object, m_name.as_string(), m_strict);
  106. }
  107. // 13.5.1.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
  108. bool Reference::delete_(GlobalObject& global_object)
  109. {
  110. // 13.5.1.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
  111. // UnaryExpression : delete UnaryExpression
  112. // NOTE: The following steps have already been evaluated by the time we get here:
  113. // 1. Let ref be the result of evaluating UnaryExpression.
  114. // 2. ReturnIfAbrupt(ref).
  115. // 3. If ref is not a Reference Record, return true.
  116. // 4. If IsUnresolvableReference(ref) is true, then
  117. if (is_unresolvable()) {
  118. // a. Assert: ref.[[Strict]] is false.
  119. VERIFY(!m_strict);
  120. // b. Return true.
  121. return true;
  122. }
  123. auto& vm = global_object.vm();
  124. // 5. If IsPropertyReference(ref) is true, then
  125. if (is_property_reference()) {
  126. // a. Assert: ! IsPrivateReference(ref) is false.
  127. // FIXME: We don't have private references yet.
  128. // b. If IsSuperReference(ref) is true, throw a ReferenceError exception.
  129. if (is_super_reference()) {
  130. vm.throw_exception<ReferenceError>(global_object, ErrorType::UnsupportedDeleteSuperProperty);
  131. return {};
  132. }
  133. // c. Let baseObj be ! ToObject(ref.[[Base]]).
  134. auto* base_obj = m_base_value.to_object(global_object);
  135. VERIFY(base_obj);
  136. // d. Let deleteStatus be ? baseObj.[[Delete]](ref.[[ReferencedName]]).
  137. bool delete_status = TRY_OR_DISCARD(base_obj->internal_delete(m_name));
  138. // e. If deleteStatus is false and ref.[[Strict]] is true, throw a TypeError exception.
  139. if (!delete_status && m_strict) {
  140. vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishDeleteProperty, m_name, m_base_value.to_string_without_side_effects());
  141. return {};
  142. }
  143. // f. Return deleteStatus.
  144. return delete_status;
  145. }
  146. // 6. Else,
  147. // a. Let base be ref.[[Base]].
  148. // b. Assert: base is an Environment Record.
  149. VERIFY(m_base_type == BaseType::Environment);
  150. // Note: Optimisation, not from the spec.
  151. if (m_function_argument_index.has_value()) {
  152. // This is a direct reference to a function argument.
  153. return false;
  154. }
  155. // c. Return ? base.DeleteBinding(ref.[[ReferencedName]]).
  156. return m_base_environment->delete_binding(global_object, m_name.as_string());
  157. }
  158. String Reference::to_string() const
  159. {
  160. StringBuilder builder;
  161. builder.append("Reference { Base=");
  162. switch (m_base_type) {
  163. case BaseType::Unresolvable:
  164. builder.append("Unresolvable");
  165. break;
  166. case BaseType::Environment:
  167. builder.appendff("{}", base_environment().class_name());
  168. break;
  169. case BaseType::Value:
  170. if (m_base_value.is_empty())
  171. builder.append("<empty>");
  172. else
  173. builder.appendff("{}", m_base_value.to_string_without_side_effects());
  174. break;
  175. }
  176. builder.append(", ReferencedName=");
  177. if (!m_name.is_valid())
  178. builder.append("<invalid>");
  179. else if (m_name.is_symbol())
  180. builder.appendff("{}", m_name.as_symbol()->to_string());
  181. else
  182. builder.appendff("{}", m_name.to_string());
  183. builder.appendff(", Strict={}", m_strict);
  184. builder.appendff(", ThisValue=");
  185. if (m_this_value.is_empty())
  186. builder.append("<empty>");
  187. else
  188. builder.appendff("{}", m_this_value.to_string_without_side_effects());
  189. builder.append(" }");
  190. return builder.to_string();
  191. }
  192. }