ObjectEnvironmentRecord.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using System.Diagnostics.CodeAnalysis;
  2. using Jint.Native;
  3. using Jint.Native.Object;
  4. using Jint.Native.Symbol;
  5. using Jint.Runtime.Descriptors;
  6. namespace Jint.Runtime.Environments
  7. {
  8. /// <summary>
  9. /// Represents an object environment record
  10. /// https://tc39.es/ecma262/#sec-object-environment-records
  11. /// </summary>
  12. internal sealed class ObjectEnvironmentRecord : EnvironmentRecord
  13. {
  14. internal readonly ObjectInstance _bindingObject;
  15. private readonly bool _provideThis;
  16. private readonly bool _withEnvironment;
  17. public ObjectEnvironmentRecord(
  18. Engine engine,
  19. ObjectInstance bindingObject,
  20. bool provideThis,
  21. bool withEnvironment) : base(engine)
  22. {
  23. _bindingObject = bindingObject;
  24. _provideThis = provideThis;
  25. _withEnvironment = withEnvironment;
  26. }
  27. public override bool HasBinding(string name)
  28. {
  29. var property = new JsString(name);
  30. var foundBinding = HasProperty(property);
  31. if (!foundBinding)
  32. {
  33. return false;
  34. }
  35. if (!_withEnvironment)
  36. {
  37. return true;
  38. }
  39. return !IsBlocked(name);
  40. }
  41. internal override bool HasBinding(in BindingName name)
  42. {
  43. var foundBinding = HasProperty(name.StringValue);
  44. if (!foundBinding)
  45. {
  46. return false;
  47. }
  48. if (!_withEnvironment)
  49. {
  50. return true;
  51. }
  52. return !IsBlocked(name.StringValue);
  53. }
  54. private bool HasProperty(JsValue property)
  55. {
  56. return _bindingObject.HasProperty(property);
  57. }
  58. internal override bool TryGetBinding(
  59. in BindingName name,
  60. bool strict,
  61. out Binding binding,
  62. [NotNullWhen(true)] out JsValue? value)
  63. {
  64. // we unwrap by name
  65. binding = default;
  66. if (!HasProperty(name.StringValue))
  67. {
  68. value = default;
  69. return false;
  70. }
  71. if (_withEnvironment && IsBlocked(name.StringValue))
  72. {
  73. value = default;
  74. return false;
  75. }
  76. var desc = _bindingObject.GetProperty(name.StringValue);
  77. value = ObjectInstance.UnwrapJsValue(desc, _bindingObject);
  78. return true;
  79. }
  80. private bool IsBlocked(JsValue property)
  81. {
  82. var unscopables = _bindingObject.Get(GlobalSymbolRegistry.Unscopables);
  83. if (unscopables is ObjectInstance oi)
  84. {
  85. var blocked = TypeConverter.ToBoolean(oi.Get(property));
  86. if (blocked)
  87. {
  88. return true;
  89. }
  90. }
  91. return false;
  92. }
  93. /// <summary>
  94. /// http://www.ecma-international.org/ecma-262/6.0/#sec-object-environment-records-createmutablebinding-n-d
  95. /// </summary>
  96. public override void CreateMutableBinding(string name, bool canBeDeleted = false)
  97. {
  98. _bindingObject.DefinePropertyOrThrow(name, new PropertyDescriptor(Undefined, canBeDeleted
  99. ? PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding
  100. : PropertyFlag.NonConfigurable | PropertyFlag.MutableBinding));
  101. }
  102. /// <summary>
  103. /// https://tc39.es/ecma262/#sec-object-environment-records-createimmutablebinding-n-s
  104. /// </summary>
  105. public override void CreateImmutableBinding(string name, bool strict = true)
  106. {
  107. ExceptionHelper.ThrowInvalidOperationException("The concrete Environment Record method CreateImmutableBinding is never used within this specification in association with Object Environment Records.");
  108. }
  109. /// <summary>
  110. /// https://tc39.es/ecma262/#sec-object-environment-records-initializebinding-n-v
  111. /// </summary>
  112. public override void InitializeBinding(string name, JsValue value)
  113. {
  114. SetMutableBinding(name, value, false);
  115. }
  116. public override void SetMutableBinding(string name, JsValue value, bool strict)
  117. {
  118. var jsString = new JsString(name);
  119. if (strict && !_bindingObject.HasProperty(jsString))
  120. {
  121. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
  122. }
  123. _bindingObject.Set(jsString, value);
  124. }
  125. internal override void SetMutableBinding(in BindingName name, JsValue value, bool strict)
  126. {
  127. if (strict && !_bindingObject.HasProperty(name.StringValue))
  128. {
  129. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
  130. }
  131. _bindingObject.Set(name.StringValue, value);
  132. }
  133. public override JsValue GetBindingValue(string name, bool strict)
  134. {
  135. var desc = _bindingObject.GetProperty(name);
  136. if (strict && desc == PropertyDescriptor.Undefined)
  137. {
  138. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
  139. }
  140. return ObjectInstance.UnwrapJsValue(desc, _bindingObject);
  141. }
  142. internal override bool TryGetBindingValue(string name, bool strict, [NotNullWhen(true)] out JsValue? value)
  143. {
  144. var desc = _bindingObject.GetProperty(name);
  145. if (strict && desc == PropertyDescriptor.Undefined)
  146. {
  147. value = null;
  148. return false;
  149. }
  150. value = ObjectInstance.UnwrapJsValue(desc, _bindingObject);
  151. return true;
  152. }
  153. public override bool DeleteBinding(string name)
  154. {
  155. return _bindingObject.Delete(name);
  156. }
  157. public override bool HasThisBinding() => false;
  158. public override bool HasSuperBinding() => false;
  159. public override JsValue WithBaseObject() => _withEnvironment ? _bindingObject : Undefined;
  160. internal override string[] GetAllBindingNames()
  161. {
  162. if (!ReferenceEquals(_bindingObject, null))
  163. {
  164. var names = new List<string>(_bindingObject._properties?.Count ?? 0);
  165. foreach (var name in _bindingObject.GetOwnProperties())
  166. {
  167. names.Add(name.Key.ToString());
  168. }
  169. return names.ToArray();
  170. }
  171. return Array.Empty<string>();
  172. }
  173. public override bool Equals(JsValue? other)
  174. {
  175. return ReferenceEquals(_bindingObject, other);
  176. }
  177. public override JsValue GetThisBinding()
  178. {
  179. throw new NotImplementedException();
  180. }
  181. }
  182. }