FunctionInstance.cs 6.9 KB

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