ObjectEnvironment.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 ObjectEnvironment : Environment
  13. {
  14. internal readonly ObjectInstance _bindingObject;
  15. private readonly bool _provideThis;
  16. private readonly bool _withEnvironment;
  17. public ObjectEnvironment(
  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. internal override bool HasBinding(Key name)
  28. {
  29. var property = new JsString(name.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(property);
  40. }
  41. internal override bool HasBinding(BindingName name)
  42. {
  43. var foundBinding = HasProperty(name.Value);
  44. if (!foundBinding)
  45. {
  46. return false;
  47. }
  48. if (!_withEnvironment)
  49. {
  50. return true;
  51. }
  52. return !IsBlocked(name.Value);
  53. }
  54. private bool HasProperty(JsValue property)
  55. {
  56. return _bindingObject.HasProperty(property);
  57. }
  58. internal override bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value)
  59. {
  60. // we unwrap by name
  61. if (!HasProperty(name.Value))
  62. {
  63. value = default;
  64. return false;
  65. }
  66. if (_withEnvironment && IsBlocked(name.Value))
  67. {
  68. value = default;
  69. return false;
  70. }
  71. value = _bindingObject.Get(name.Value);
  72. return true;
  73. }
  74. private bool IsBlocked(JsValue property)
  75. {
  76. var unscopables = _bindingObject.Get(GlobalSymbolRegistry.Unscopables);
  77. if (unscopables is ObjectInstance oi)
  78. {
  79. var blocked = TypeConverter.ToBoolean(oi.Get(property));
  80. if (blocked)
  81. {
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. /// <summary>
  88. /// http://www.ecma-international.org/ecma-262/6.0/#sec-object-environment-records-createmutablebinding-n-d
  89. /// </summary>
  90. internal override void CreateMutableBinding(Key name, bool canBeDeleted = false)
  91. {
  92. _bindingObject.DefinePropertyOrThrow(name.Name, new PropertyDescriptor(Undefined, canBeDeleted
  93. ? PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding
  94. : PropertyFlag.NonConfigurable | PropertyFlag.MutableBinding));
  95. }
  96. /// <summary>
  97. /// https://tc39.es/ecma262/#sec-object-environment-records-createimmutablebinding-n-s
  98. /// </summary>
  99. internal override void CreateImmutableBinding(Key name, bool strict = true)
  100. {
  101. ExceptionHelper.ThrowInvalidOperationException("The concrete Environment Record method CreateImmutableBinding is never used within this specification in association with Object Environment Records.");
  102. }
  103. /// <summary>
  104. /// https://tc39.es/ecma262/#sec-object-environment-records-initializebinding-n-v
  105. /// </summary>
  106. internal override void InitializeBinding(Key name, JsValue value) => SetMutableBinding(name, value, strict: false);
  107. internal override void SetMutableBinding(Key name, JsValue value, bool strict)
  108. {
  109. var jsString = new JsString(name);
  110. if (strict && !_bindingObject.HasProperty(jsString))
  111. {
  112. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
  113. }
  114. _bindingObject.Set(jsString, value);
  115. }
  116. internal override void SetMutableBinding(BindingName name, JsValue value, bool strict)
  117. {
  118. if (strict && !_bindingObject.HasProperty(name.Value))
  119. {
  120. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
  121. }
  122. _bindingObject.Set(name.Value, value);
  123. }
  124. internal override JsValue GetBindingValue(Key name, bool strict)
  125. {
  126. if (!_bindingObject.TryGetValue(name.Name, out var value) && strict)
  127. {
  128. ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
  129. }
  130. return value;
  131. }
  132. internal override bool DeleteBinding(Key name) => _bindingObject.Delete(name.Name);
  133. internal override bool HasThisBinding() => false;
  134. internal override bool HasSuperBinding() => false;
  135. internal override JsValue WithBaseObject() => _withEnvironment ? _bindingObject : Undefined;
  136. internal override bool HasBindings() => _bindingObject._properties?.Count > 0;
  137. internal override string[] GetAllBindingNames()
  138. {
  139. if (_bindingObject is not null)
  140. {
  141. var names = new List<string>(_bindingObject._properties?.Count ?? 0);
  142. foreach (var name in _bindingObject.GetOwnProperties())
  143. {
  144. names.Add(name.Key.ToString());
  145. }
  146. return names.ToArray();
  147. }
  148. return Array.Empty<string>();
  149. }
  150. public override bool Equals(JsValue? other)
  151. {
  152. return ReferenceEquals(_bindingObject, other);
  153. }
  154. internal override JsValue GetThisBinding()
  155. {
  156. throw new NotImplementedException();
  157. }
  158. }
  159. }