Reference.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/Error.h>
  7. #include <LibJS/Runtime/GlobalObject.h>
  8. #include <LibJS/Runtime/Reference.h>
  9. namespace JS {
  10. void Reference::put(GlobalObject& global_object, Value value)
  11. {
  12. auto& vm = global_object.vm();
  13. if (is_unresolvable()) {
  14. throw_reference_error(global_object);
  15. return;
  16. }
  17. if (is_local_variable() || is_global_variable()) {
  18. if (is_local_variable())
  19. vm.set_variable(m_name.to_string(), value, global_object);
  20. else
  21. global_object.put(m_name, value);
  22. return;
  23. }
  24. auto base = this->base();
  25. if (!base.is_object() && vm.in_strict_mode()) {
  26. if (base.is_nullish())
  27. vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishSetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects());
  28. else
  29. 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());
  30. return;
  31. }
  32. if (base.is_nullish()) {
  33. // This will always fail the to_object() call below, let's throw the TypeError ourselves with a nice message instead.
  34. vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishSetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects());
  35. return;
  36. }
  37. auto* object = base.to_object(global_object);
  38. if (!object)
  39. return;
  40. object->put(m_name, value);
  41. }
  42. void Reference::throw_reference_error(GlobalObject& global_object)
  43. {
  44. auto& vm = global_object.vm();
  45. if (!m_name.is_valid())
  46. vm.throw_exception<ReferenceError>(global_object, ErrorType::ReferenceUnresolvable);
  47. else
  48. vm.throw_exception<ReferenceError>(global_object, ErrorType::UnknownIdentifier, m_name.to_string_or_symbol().to_display_string());
  49. }
  50. Value Reference::get(GlobalObject& global_object)
  51. {
  52. auto& vm = global_object.vm();
  53. if (is_unresolvable()) {
  54. throw_reference_error(global_object);
  55. return {};
  56. }
  57. if (is_local_variable() || is_global_variable()) {
  58. Value value;
  59. if (is_local_variable())
  60. value = vm.get_variable(m_name.to_string(), global_object);
  61. else
  62. value = global_object.get(m_name);
  63. if (vm.exception())
  64. return {};
  65. if (value.is_empty()) {
  66. throw_reference_error(global_object);
  67. return {};
  68. }
  69. return value;
  70. }
  71. auto base = this->base();
  72. if (base.is_nullish()) {
  73. // This will always fail the to_object() call below, let's throw the TypeError ourselves with a nice message instead.
  74. vm.throw_exception<TypeError>(global_object, ErrorType::ReferenceNullishGetProperty, m_name.to_value(vm).to_string_without_side_effects(), base.to_string_without_side_effects());
  75. return {};
  76. }
  77. auto* object = base.to_object(global_object);
  78. if (!object)
  79. return {};
  80. return object->get(m_name).value_or(js_undefined());
  81. }
  82. }