FunctionInstance.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 _prototypeDescriptor;
  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, this);
  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. /// <param name="receiver"></param>
  94. /// <returns></returns>
  95. public override JsValue Get(in Key propertyName, JsValue receiver)
  96. {
  97. var v = base.Get(propertyName, receiver);
  98. if (propertyName == KnownKeys.Caller
  99. && ((v.As<FunctionInstance>()?._strict).GetValueOrDefault()))
  100. {
  101. ExceptionHelper.ThrowTypeError(_engine);
  102. }
  103. return v;
  104. }
  105. public override IEnumerable<KeyValuePair<Key, PropertyDescriptor>> GetOwnProperties()
  106. {
  107. if (_prototypeDescriptor != null)
  108. {
  109. yield return new KeyValuePair<Key, PropertyDescriptor>(KnownKeys.Prototype, _prototypeDescriptor);
  110. }
  111. if (_length != null)
  112. {
  113. yield return new KeyValuePair<Key, PropertyDescriptor>(KnownKeys.Length, _length);
  114. }
  115. if (!(_name is null))
  116. {
  117. yield return new KeyValuePair<Key, PropertyDescriptor>(KnownKeys.Name, GetOwnProperty(KnownKeys.Name));
  118. }
  119. foreach (var entry in base.GetOwnProperties())
  120. {
  121. yield return entry;
  122. }
  123. }
  124. internal override List<JsValue> GetOwnPropertyKeys(Types types)
  125. {
  126. var keys = new List<JsValue>();
  127. if (_prototypeDescriptor != null)
  128. {
  129. keys.Add(KnownKeys.Prototype);
  130. }
  131. if (_length != null)
  132. {
  133. keys.Add(KnownKeys.Length);
  134. }
  135. if (!(_name is null))
  136. {
  137. keys.Add(KnownKeys.Name);
  138. }
  139. keys.AddRange(base.GetOwnPropertyKeys(types));
  140. return keys;
  141. }
  142. public override PropertyDescriptor GetOwnProperty(in Key propertyName)
  143. {
  144. if (propertyName == KnownKeys.Prototype)
  145. {
  146. return _prototypeDescriptor ?? PropertyDescriptor.Undefined;
  147. }
  148. if (propertyName == KnownKeys.Length)
  149. {
  150. return _length ?? PropertyDescriptor.Undefined;
  151. }
  152. if (propertyName == KnownKeys.Name)
  153. {
  154. return !(_name is null)
  155. ? _nameDescriptor ?? (_nameDescriptor = new PropertyDescriptor(_name, PropertyFlag.Configurable))
  156. : PropertyDescriptor.Undefined;
  157. }
  158. return base.GetOwnProperty(propertyName);
  159. }
  160. protected internal override void SetOwnProperty(in Key propertyName, PropertyDescriptor desc)
  161. {
  162. if (propertyName == KnownKeys.Prototype)
  163. {
  164. _prototypeDescriptor = desc;
  165. }
  166. else if (propertyName == KnownKeys.Length)
  167. {
  168. _length = desc;
  169. }
  170. else if (propertyName == KnownKeys.Name)
  171. {
  172. _name = desc._value;
  173. _nameDescriptor = desc;
  174. }
  175. else
  176. {
  177. base.SetOwnProperty(propertyName, desc);
  178. }
  179. }
  180. public override bool HasOwnProperty(in Key propertyName)
  181. {
  182. if (propertyName == KnownKeys.Prototype)
  183. {
  184. return _prototypeDescriptor != null;
  185. }
  186. if (propertyName == KnownKeys.Length)
  187. {
  188. return _length != null;
  189. }
  190. if (propertyName == KnownKeys.Name)
  191. {
  192. return !(_name is null);
  193. }
  194. return base.HasOwnProperty(propertyName);
  195. }
  196. public override void RemoveOwnProperty(in Key propertyName)
  197. {
  198. if (propertyName == KnownKeys.Prototype)
  199. {
  200. _prototypeDescriptor = null;
  201. }
  202. if (propertyName == KnownKeys.Length)
  203. {
  204. _length = null;
  205. }
  206. if (propertyName == KnownKeys.Name)
  207. {
  208. _name = null;
  209. _nameDescriptor = null;
  210. }
  211. base.RemoveOwnProperty(propertyName);
  212. }
  213. internal void SetFunctionName(in Key key, bool throwIfExists = false)
  214. {
  215. if (_name is null)
  216. {
  217. _name = key.IsSymbol && key.Name.Length > 0 ? "[" + key.Name + "]" : key.Name;
  218. }
  219. else if (throwIfExists)
  220. {
  221. ExceptionHelper.ThrowError(_engine, "cannot set name");
  222. }
  223. }
  224. }
  225. }