Reference.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/String.h>
  8. #include <LibJS/Runtime/Environment.h>
  9. #include <LibJS/Runtime/EnvironmentCoordinate.h>
  10. #include <LibJS/Runtime/ExecutionContext.h>
  11. #include <LibJS/Runtime/PropertyKey.h>
  12. #include <LibJS/Runtime/Value.h>
  13. namespace JS {
  14. Reference make_private_reference(VM&, Value base_value, FlyString const& private_identifier);
  15. class Reference {
  16. public:
  17. enum class BaseType : u8 {
  18. Unresolvable,
  19. Value,
  20. Environment,
  21. };
  22. Reference() { }
  23. Reference(BaseType type, PropertyKey name, bool strict)
  24. : m_base_type(type)
  25. , m_name(move(name))
  26. , m_strict(strict)
  27. {
  28. }
  29. Reference(Value base, PropertyKey name, Value this_value, bool strict = false)
  30. : m_base_type(BaseType::Value)
  31. , m_base_value(base)
  32. , m_name(move(name))
  33. , m_this_value(this_value)
  34. , m_strict(strict)
  35. {
  36. if (base.is_nullish()) {
  37. m_base_type = BaseType::Unresolvable;
  38. m_base_value = {};
  39. m_this_value = {};
  40. m_name = {};
  41. }
  42. }
  43. Reference(Environment& base, FlyString referenced_name, bool strict = false, Optional<EnvironmentCoordinate> environment_coordinate = {})
  44. : m_base_type(BaseType::Environment)
  45. , m_base_environment(&base)
  46. , m_name(move(referenced_name))
  47. , m_strict(strict)
  48. , m_environment_coordinate(move(environment_coordinate))
  49. {
  50. }
  51. Reference(Value base, PrivateName name)
  52. : m_base_type(BaseType::Value)
  53. , m_base_value(base)
  54. , m_this_value(Value {})
  55. , m_strict(true)
  56. , m_is_private(true)
  57. , m_private_name(move(name))
  58. {
  59. }
  60. Value base() const
  61. {
  62. VERIFY(m_base_type == BaseType::Value);
  63. return m_base_value;
  64. }
  65. Environment& base_environment() const
  66. {
  67. VERIFY(m_base_type == BaseType::Environment);
  68. return *m_base_environment;
  69. }
  70. PropertyKey const& name() const { return m_name; }
  71. bool is_strict() const { return m_strict; }
  72. // 6.2.4.2 IsUnresolvableReference ( V ), https://tc39.es/ecma262/#sec-isunresolvablereference
  73. bool is_unresolvable() const { return m_base_type == BaseType::Unresolvable; }
  74. // 6.2.4.1 IsPropertyReference ( V ), https://tc39.es/ecma262/#sec-ispropertyreference
  75. bool is_property_reference() const
  76. {
  77. if (is_unresolvable())
  78. return false;
  79. if (m_base_type == BaseType::Environment)
  80. return false;
  81. return true;
  82. }
  83. // 6.2.4.7 GetThisValue ( V ), https://tc39.es/ecma262/#sec-getthisvalue
  84. Value get_this_value() const
  85. {
  86. VERIFY(is_property_reference());
  87. if (is_super_reference())
  88. return m_this_value;
  89. return m_base_value;
  90. }
  91. // 6.2.4.3 IsSuperReference ( V ), https://tc39.es/ecma262/#sec-issuperreference
  92. bool is_super_reference() const
  93. {
  94. return !m_this_value.is_empty();
  95. }
  96. // 6.2.4.4 IsPrivateReference ( V ), https://tc39.es/ecma262/#sec-isprivatereference
  97. bool is_private_reference() const
  98. {
  99. return m_is_private;
  100. }
  101. // Note: Non-standard helper.
  102. bool is_environment_reference() const
  103. {
  104. return m_base_type == BaseType::Environment;
  105. }
  106. // 6.2.4.8 InitializeReferencedBinding ( V, W ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty
  107. ThrowCompletionOr<void> initialize_referenced_binding(GlobalObject& global_object, Value value) const
  108. {
  109. VERIFY(!is_unresolvable());
  110. VERIFY(m_base_type == BaseType::Environment);
  111. return m_base_environment->initialize_binding(global_object, m_name.as_string(), value);
  112. }
  113. ThrowCompletionOr<void> put_value(GlobalObject&, Value);
  114. ThrowCompletionOr<Value> get_value(GlobalObject&) const;
  115. ThrowCompletionOr<bool> delete_(GlobalObject&);
  116. String to_string() const;
  117. bool is_valid_reference() const { return m_name.is_valid() || m_is_private; }
  118. Optional<EnvironmentCoordinate> environment_coordinate() const { return m_environment_coordinate; }
  119. private:
  120. Completion throw_reference_error(GlobalObject&) const;
  121. BaseType m_base_type { BaseType::Unresolvable };
  122. union {
  123. Value m_base_value {};
  124. mutable Environment* m_base_environment;
  125. };
  126. PropertyKey m_name;
  127. Value m_this_value;
  128. bool m_strict { false };
  129. bool m_is_private { false };
  130. // FIXME: This can (probably) be an union with m_name.
  131. PrivateName m_private_name;
  132. Optional<EnvironmentCoordinate> m_environment_coordinate;
  133. };
  134. }