FunctionInstance.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using System.Collections.Generic;
  2. using Jint.Native.Object;
  3. using Jint.Runtime;
  4. using Jint.Runtime.Descriptors;
  5. using Jint.Runtime.Environments;
  6. namespace Jint.Native.Function
  7. {
  8. public abstract class FunctionInstance : ObjectInstance, ICallable
  9. {
  10. private const string PropertyNamePrototype = "prototype";
  11. private const int PropertyNamePrototypeLength = 9;
  12. protected PropertyDescriptor _prototype;
  13. private const string PropertyNameLength = "length";
  14. private const int PropertyNameLengthLength = 6;
  15. protected PropertyDescriptor _length;
  16. protected readonly LexicalEnvironment _scope;
  17. protected internal readonly string[] _formalParameters;
  18. private readonly bool _strict;
  19. protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironment scope, bool strict)
  20. : this(engine, parameters, scope, strict, objectClass: "Function")
  21. {
  22. }
  23. protected FunctionInstance(
  24. Engine engine,
  25. string[] parameters,
  26. LexicalEnvironment scope,
  27. bool strict,
  28. in string objectClass)
  29. : base(engine, objectClass)
  30. {
  31. _formalParameters = parameters;
  32. _scope = scope;
  33. _strict = strict;
  34. }
  35. /// <summary>
  36. /// Executed when a function object is used as a function
  37. /// </summary>
  38. /// <param name="thisObject"></param>
  39. /// <param name="arguments"></param>
  40. /// <returns></returns>
  41. public abstract JsValue Call(JsValue thisObject, JsValue[] arguments);
  42. public LexicalEnvironment Scope => _scope;
  43. public string[] FormalParameters => _formalParameters;
  44. public bool Strict => _strict;
  45. public virtual bool HasInstance(JsValue v)
  46. {
  47. var vObj = v.TryCast<ObjectInstance>();
  48. if (ReferenceEquals(vObj, null))
  49. {
  50. return false;
  51. }
  52. var po = Get("prototype");
  53. if (!po.IsObject())
  54. {
  55. ExceptionHelper.ThrowTypeError(_engine, $"Function has non-object prototype '{TypeConverter.ToString(po)}' in instanceof check");
  56. }
  57. var o = po.AsObject();
  58. if (ReferenceEquals(o, null))
  59. {
  60. ExceptionHelper.ThrowTypeError(_engine);
  61. }
  62. while (true)
  63. {
  64. vObj = vObj.Prototype;
  65. if (ReferenceEquals(vObj, null))
  66. {
  67. return false;
  68. }
  69. if (vObj == o)
  70. {
  71. return true;
  72. }
  73. }
  74. }
  75. /// <summary>
  76. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.4
  77. /// </summary>
  78. /// <param name="propertyName"></param>
  79. /// <returns></returns>
  80. public override JsValue Get(string propertyName)
  81. {
  82. var v = base.Get(propertyName);
  83. if (propertyName.Length == 6
  84. && propertyName == "caller"
  85. && ((v.As<FunctionInstance>()?._strict).GetValueOrDefault()))
  86. {
  87. ExceptionHelper.ThrowTypeError(_engine);
  88. }
  89. return v;
  90. }
  91. public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
  92. {
  93. if (_prototype != null)
  94. {
  95. yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNamePrototype, _prototype);
  96. }
  97. if (_length != null)
  98. {
  99. yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameLength, _length);
  100. }
  101. foreach (var entry in base.GetOwnProperties())
  102. {
  103. yield return entry;
  104. }
  105. }
  106. public override PropertyDescriptor GetOwnProperty(string propertyName)
  107. {
  108. if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
  109. {
  110. return _prototype ?? PropertyDescriptor.Undefined;
  111. }
  112. if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
  113. {
  114. return _length ?? PropertyDescriptor.Undefined;
  115. }
  116. return base.GetOwnProperty(propertyName);
  117. }
  118. protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
  119. {
  120. if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
  121. {
  122. _prototype = desc;
  123. }
  124. else if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
  125. {
  126. _length = desc;
  127. }
  128. else
  129. {
  130. base.SetOwnProperty(propertyName, desc);
  131. }
  132. }
  133. public override bool HasOwnProperty(string propertyName)
  134. {
  135. if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
  136. {
  137. return _prototype != null;
  138. }
  139. if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
  140. {
  141. return _length != null;
  142. }
  143. return base.HasOwnProperty(propertyName);
  144. }
  145. public override void RemoveOwnProperty(string propertyName)
  146. {
  147. if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
  148. {
  149. _prototype = null;
  150. }
  151. if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
  152. {
  153. _prototype = null;
  154. }
  155. base.RemoveOwnProperty(propertyName);
  156. }
  157. }
  158. }