ObjectInstance.Private.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using System.Runtime.CompilerServices;
  2. using Jint.Native.Function;
  3. using Jint.Runtime;
  4. namespace Jint.Native.Object;
  5. public partial class ObjectInstance
  6. {
  7. private Dictionary<PrivateName, PrivateElement>? _privateElements;
  8. /// <summary>
  9. /// https://tc39.es/ecma262/#sec-initializeinstanceelements
  10. /// </summary>
  11. internal void InitializeInstanceElements(ScriptFunction constructor)
  12. {
  13. var methods = constructor._privateMethods;
  14. if (methods is not null)
  15. {
  16. for (var i = 0; i < methods.Count; i++)
  17. {
  18. PrivateMethodOrAccessorAdd(methods[i]);
  19. }
  20. }
  21. var fields = constructor._fields;
  22. if (fields is not null)
  23. {
  24. for (var i = 0; i < fields.Count; i++)
  25. {
  26. DefineField(this, fields[i]);
  27. }
  28. }
  29. }
  30. /// <summary>
  31. /// https://tc39.es/ecma262/#sec-privatemethodoraccessoradd
  32. /// </summary>
  33. internal void PrivateMethodOrAccessorAdd(PrivateElement method)
  34. {
  35. // If the host is a web browser, then
  36. // Perform ? HostEnsureCanAddPrivateElement(O).
  37. var entry = PrivateElementFind(method.Key);
  38. if (entry is not null)
  39. {
  40. Throw.TypeError(_engine.Realm, "Already present");
  41. }
  42. _privateElements ??= new Dictionary<PrivateName, PrivateElement>();
  43. _privateElements.Add(method.Key, method);
  44. }
  45. /// <summary>
  46. /// https://tc39.es/ecma262/#sec-privatefieldadd
  47. /// </summary>
  48. private void PrivateFieldAdd(PrivateName property, JsValue value)
  49. {
  50. // If the host is a web browser, then
  51. // Perform ? HostEnsureCanAddPrivateElement(O).
  52. var entry = PrivateElementFind(property);
  53. if (entry is not null)
  54. {
  55. Throw.TypeError(_engine.Realm, "Already present");
  56. }
  57. _privateElements ??= new Dictionary<PrivateName, PrivateElement>();
  58. _privateElements.Add(property, new PrivateElement { Key = property, Kind = PrivateElementKind.Field, Value = value });
  59. }
  60. /// <summary>
  61. /// https://tc39.es/ecma262/#sec-privateget
  62. /// </summary>
  63. internal JsValue PrivateGet(PrivateName property)
  64. {
  65. var entry = PrivateElementFind(property);
  66. if (entry is null)
  67. {
  68. Throw.TypeError(_engine.Realm, $"Cannot read private member #{property} from an object whose class did not declare it");
  69. }
  70. if (entry.Kind is PrivateElementKind.Field or PrivateElementKind.Method)
  71. {
  72. return entry.Value ?? Undefined;
  73. }
  74. var getter = entry.Get;
  75. if (getter is null)
  76. {
  77. Throw.TypeError(_engine.Realm, $"'#{property}' was defined without a getter");
  78. }
  79. var functionInstance = (Function.Function) getter;
  80. var privateGet = functionInstance._engine.Call(functionInstance, this);
  81. return privateGet;
  82. }
  83. /// <summary>
  84. /// https://tc39.es/ecma262/#sec-privateset
  85. /// </summary>
  86. internal void PrivateSet(PrivateName property, JsValue value)
  87. {
  88. var entry = PrivateElementFind(property);
  89. if (entry is null)
  90. {
  91. Throw.TypeError(_engine.Realm, "Not found");
  92. }
  93. if (entry.Kind == PrivateElementKind.Field)
  94. {
  95. entry.Value = value;
  96. }
  97. else if (entry.Kind == PrivateElementKind.Method)
  98. {
  99. Throw.TypeError(_engine.Realm, "Cannot set method");
  100. }
  101. else
  102. {
  103. var setter = entry.Set;
  104. if (setter is null)
  105. {
  106. Throw.TypeError(_engine.Realm, $"'#{property}' was defined without a setter");
  107. }
  108. _engine.Call(setter, this, [value]);
  109. }
  110. }
  111. /// <summary>
  112. /// https://tc39.es/ecma262/#sec-privateelementfind
  113. /// </summary>
  114. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  115. internal PrivateElement? PrivateElementFind(PrivateName property)
  116. {
  117. return _privateElements?.TryGetValue(property, out var pe) == true ? pe : null;
  118. }
  119. }
  120. internal sealed class ClassFieldDefinition
  121. {
  122. public required JsValue Name { get; set; }
  123. public ScriptFunction? Initializer { get; set; }
  124. }
  125. internal sealed class ClassStaticBlockDefinition
  126. {
  127. public required Function.Function BodyFunction { get; set; }
  128. }
  129. internal sealed class PrivateElement
  130. {
  131. public required PrivateName Key { get; set; }
  132. public PrivateElementKind Kind { get; set; }
  133. public JsValue? Value { get; set; }
  134. public JsValue? Get { get; set; }
  135. public JsValue? Set { get; set; }
  136. }
  137. internal enum PrivateElementKind
  138. {
  139. Field,
  140. Method,
  141. Accessor
  142. }