FunctionInstance.cs 5.7 KB

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