PageRenderTime 763ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Jurassic/Library/Function/FunctionInstance.cs

http://jurassic.codeplex.com
C# | 254 lines | 125 code | 34 blank | 95 comment | 35 complexity | aa614744c831a02b15bbe6265f38a8ee MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Jurassic.Library
  4. {
  5. /// <summary>
  6. /// Represents a JavaScript function.
  7. /// </summary>
  8. [Serializable]
  9. public abstract class FunctionInstance : ObjectInstance
  10. {
  11. // Used to speed up access to the prototype property.
  12. private int cachedInstancePrototypeIndex;
  13. private object cachedInstancePrototypeSchema;
  14. // INITIALIZATION
  15. //_________________________________________________________________________________________
  16. /// <summary>
  17. /// Creates a new instance of a built-in function object, with the default Function
  18. /// prototype.
  19. /// </summary>
  20. /// <param name="engine"> The associated script engine. </param>
  21. protected FunctionInstance(ScriptEngine engine)
  22. : base(engine, engine.Function.InstancePrototype)
  23. {
  24. }
  25. /// <summary>
  26. /// Creates a new instance of a built-in function object.
  27. /// </summary>
  28. /// <param name="prototype"> The next object in the prototype chain. </param>
  29. protected FunctionInstance(ObjectInstance prototype)
  30. : base(prototype)
  31. {
  32. }
  33. /// <summary>
  34. /// Creates a new instance of a built-in function object.
  35. /// </summary>
  36. /// <param name="engine"> The associated script engine. </param>
  37. /// <param name="prototype"> The next object in the prototype chain. Can be <c>null</c>. </param>
  38. protected FunctionInstance(ScriptEngine engine, ObjectInstance prototype)
  39. : base(engine, prototype)
  40. {
  41. }
  42. // .NET ACCESSOR PROPERTIES
  43. //_________________________________________________________________________________________
  44. /// <summary>
  45. /// Gets the internal class name of the object. Used by the default toString()
  46. /// implementation.
  47. /// </summary>
  48. protected override string InternalClassName
  49. {
  50. get { return "Function"; }
  51. }
  52. /// <summary>
  53. /// Gets the prototype of objects constructed using this function. Equivalent to
  54. /// the Function.prototype property.
  55. /// </summary>
  56. public ObjectInstance InstancePrototype
  57. {
  58. get
  59. {
  60. // See 13.2.2
  61. // Retrieve the value of the prototype property.
  62. //var prototype = this["prototype"] as ObjectInstance;
  63. ObjectInstance prototype;
  64. if (this.cachedInstancePrototypeSchema == this.InlineCacheKey)
  65. prototype = this.InlinePropertyValues[this.cachedInstancePrototypeIndex] as ObjectInstance;
  66. else
  67. prototype = this.InlineGetPropertyValue("prototype", out this.cachedInstancePrototypeIndex, out this.cachedInstancePrototypeSchema) as ObjectInstance;
  68. // If the prototype property is not set to an object, use the Object prototype property instead.
  69. if (prototype == null && this != this.Engine.Object)
  70. return this.Engine.Object.InstancePrototype;
  71. return prototype;
  72. }
  73. }
  74. /// <summary>
  75. /// Gets the name of the function.
  76. /// </summary>
  77. public string Name
  78. {
  79. get { return TypeConverter.ToString(this["name"]); }
  80. }
  81. /// <summary>
  82. /// Gets the display name of the function. This is equal to the displayName property, if
  83. /// it exists, or the name property otherwise.
  84. /// </summary>
  85. public string DisplayName
  86. {
  87. get
  88. {
  89. if (this.HasProperty("displayName"))
  90. return TypeConverter.ToString(this["displayName"]);
  91. var name = TypeConverter.ToString(this["name"]);
  92. if (name == string.Empty)
  93. return "[Anonymous]";
  94. return name;
  95. }
  96. }
  97. /// <summary>
  98. /// Gets the number of arguments expected by the function.
  99. /// </summary>
  100. public int Length
  101. {
  102. get { return TypeConverter.ToInteger(this["length"]); }
  103. protected set { this.FastSetProperty("length", value); }
  104. }
  105. // JAVASCRIPT INTERNAL FUNCTIONS
  106. //_________________________________________________________________________________________
  107. /// <summary>
  108. /// Determines whether the given object inherits from this function. More precisely, it
  109. /// checks whether the prototype chain of the object contains the prototype property of
  110. /// this function. Used by the "instanceof" operator.
  111. /// </summary>
  112. /// <param name="instance"> The instance to check. </param>
  113. /// <returns> <c>true</c> if the object inherits from this function; <c>false</c>
  114. /// otherwise. </returns>
  115. public virtual bool HasInstance(object instance)
  116. {
  117. if ((instance is ObjectInstance) == false)
  118. return false;
  119. object functionPrototype = this["prototype"];
  120. if ((functionPrototype is ObjectInstance) == false)
  121. throw new JavaScriptException(this.Engine, "TypeError", "Function has non-object prototype in instanceof check");
  122. var instancePrototype = ((ObjectInstance)instance).Prototype;
  123. while (instancePrototype != null)
  124. {
  125. if (instancePrototype == functionPrototype)
  126. return true;
  127. instancePrototype = instancePrototype.Prototype;
  128. }
  129. return false;
  130. }
  131. /// <summary>
  132. /// Calls this function, passing in the given "this" value and zero or more arguments.
  133. /// </summary>
  134. /// <param name="thisObject"> The value of the "this" keyword within the function. </param>
  135. /// <param name="argumentValues"> An array of argument values. </param>
  136. /// <returns> The value that was returned from the function. </returns>
  137. public abstract object CallLateBound(object thisObject, params object[] argumentValues);
  138. /// <summary>
  139. /// Creates an object, using this function as the constructor.
  140. /// </summary>
  141. /// <param name="argumentValues"> An array of argument values. </param>
  142. /// <returns> The object that was created. </returns>
  143. public virtual ObjectInstance ConstructLateBound(params object[] argumentValues)
  144. {
  145. // Create a new object and set the prototype to the instance prototype of the function.
  146. var newObject = ObjectInstance.CreateRawObject(this.InstancePrototype);
  147. // Run the function, with the new object as the "this" keyword.
  148. var result = CallLateBound(newObject, argumentValues);
  149. // Return the result of the function if it is an object.
  150. if (result is ObjectInstance)
  151. return (ObjectInstance)result;
  152. // Otherwise, return the new object.
  153. return newObject;
  154. }
  155. // JAVASCRIPT FUNCTIONS
  156. //_________________________________________________________________________________________
  157. /// <summary>
  158. /// Calls the function, passing in parameters from the given array.
  159. /// </summary>
  160. /// <param name="thisObj"> The value of <c>this</c> in the context of the function. </param>
  161. /// <param name="argumentArray"> The arguments passed to the function, as an array. </param>
  162. /// <returns> The result from the function call. </returns>
  163. [JSInternalFunction(Name = "apply")]
  164. public object Apply(object thisObj, object arguments)
  165. {
  166. // Convert the arguments parameter into an array.
  167. object[] argumentsArray;
  168. if (arguments == null || arguments == Undefined.Value || arguments == Null.Value)
  169. argumentsArray = new object[0];
  170. else
  171. {
  172. if ((arguments is ObjectInstance) == false)
  173. throw new JavaScriptException(this.Engine, "TypeError", "The second parameter of apply() must be an array or an array-like object.");
  174. ObjectInstance argumentsObject = (ObjectInstance)arguments;
  175. object arrayLengthObj = argumentsObject["length"];
  176. if (arrayLengthObj == null || arrayLengthObj == Undefined.Value || arrayLengthObj == Null.Value)
  177. throw new JavaScriptException(this.Engine, "TypeError", "The second parameter of apply() must be an array or an array-like object.");
  178. uint arrayLength = TypeConverter.ToUint32(arrayLengthObj);
  179. if (arrayLength != TypeConverter.ToNumber(arrayLengthObj))
  180. throw new JavaScriptException(this.Engine, "TypeError", "The second parameter of apply() must be an array or an array-like object.");
  181. argumentsArray = new object[arrayLength];
  182. for (uint i = 0; i < arrayLength; i++)
  183. argumentsArray[i] = argumentsObject[i];
  184. }
  185. return this.CallLateBound(thisObj, argumentsArray);
  186. }
  187. /// <summary>
  188. /// Calls the function.
  189. /// </summary>
  190. /// <param name="thisObj"> The value of <c>this</c> in the context of the function. </param>
  191. /// <param name="arguments"> Any number of arguments that will be passed to the function. </param>
  192. /// <returns> The result from the function call. </returns>
  193. [JSInternalFunction(Name = "call", Length = 1)]
  194. public object Call(object thisObj, params object[] arguments)
  195. {
  196. return this.CallLateBound(thisObj, arguments);
  197. }
  198. /// <summary>
  199. /// Creates a new function that, when called, calls this function with the given "this"
  200. /// value and, optionally, one or more more arguments.
  201. /// </summary>
  202. /// <param name="boundThis"> The fixed value of "this". </param>
  203. /// <param name="boundArguments"> Any number of fixed arguments values. </param>
  204. /// <returns> A new function. </returns>
  205. [JSInternalFunction(Name = "bind", Length = 1)]
  206. public FunctionInstance Bind(object boundThis, params object[] boundArguments)
  207. {
  208. return new BoundFunction(this, boundThis, boundArguments);
  209. }
  210. /// <summary>
  211. /// Returns a string representing this object.
  212. /// </summary>
  213. /// <returns> A string representing this object. </returns>
  214. [JSInternalFunction(Name = "toString")]
  215. public string ToStringJS()
  216. {
  217. return this.ToString();
  218. }
  219. }
  220. }