FunctionInstance.cs 7.0 KB

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