FunctionConstructor.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Jint.Native.Object;
  5. using Jint.Parser;
  6. using Jint.Parser.Ast;
  7. using Jint.Runtime;
  8. using Jint.Runtime.Descriptors;
  9. using Jint.Runtime.Environments;
  10. namespace Jint.Native.Function
  11. {
  12. /// <summary>
  13. ///
  14. /// </summary>
  15. public sealed class FunctionConstructor : FunctionInstance, IConstructor
  16. {
  17. private FunctionConstructor(Engine engine):base(engine, null, null, false)
  18. {
  19. }
  20. public static FunctionConstructor CreateFunctionConstructor(Engine engine)
  21. {
  22. var obj = new FunctionConstructor(engine);
  23. obj.Extensible = true;
  24. // The initial value of Function.prototype is the standard built-in Function prototype object
  25. obj.PrototypeObject = FunctionPrototype.CreatePrototypeObject(engine);
  26. // The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object
  27. obj.Prototype = obj.PrototypeObject;
  28. obj.FastAddProperty("prototype", obj.PrototypeObject, false, false, false);
  29. obj.FastAddProperty("length", 1, false, false, false);
  30. return obj;
  31. }
  32. public void Configure()
  33. {
  34. }
  35. public FunctionPrototype PrototypeObject { get; private set; }
  36. public override object Call(object thisObject, object[] arguments)
  37. {
  38. return Construct(arguments);
  39. }
  40. public ObjectInstance Construct(object[] arguments)
  41. {
  42. var argCount = arguments.Length;
  43. string p = "";
  44. string body = "";
  45. if (argCount == 1)
  46. {
  47. body = TypeConverter.ToString(arguments[0]);
  48. }
  49. else if (argCount > 1)
  50. {
  51. var firstArg = arguments[0];
  52. p = TypeConverter.ToString(firstArg);
  53. for (var k = 1; k < argCount - 1; k++)
  54. {
  55. var nextArg = arguments[k];
  56. p += "," + TypeConverter.ToString(nextArg);
  57. }
  58. body = TypeConverter.ToString(arguments[argCount-1]);
  59. }
  60. body = TypeConverter.ToString(body);
  61. // todo: ensure parsable as parameter list
  62. var parameters = p.Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries);
  63. var parser = new JavaScriptParser();
  64. FunctionExpression function;
  65. try
  66. {
  67. var functionExpression = "function(" + p + ") { " + body + "}";
  68. function = parser.ParseFunctionExpression(functionExpression);
  69. }
  70. catch (ParserError e)
  71. {
  72. throw new JavaScriptException(Engine.SyntaxError);
  73. }
  74. // todo: check if there is not a way to use the FunctionExpression directly instead of creating a FunctionDeclaration
  75. var functionObject = new ScriptFunctionInstance(
  76. Engine,
  77. new FunctionDeclaration
  78. {
  79. Type = SyntaxNodes.FunctionDeclaration,
  80. Body = new BlockStatement
  81. {
  82. Type = SyntaxNodes.BlockStatement,
  83. Body = new Statement[] { function.Body }
  84. },
  85. Parameters = parameters.Select(x => new Identifier
  86. {
  87. Type = SyntaxNodes.Identifier,
  88. Name = x
  89. }).ToArray(),
  90. FunctionDeclarations = new List<FunctionDeclaration>(),
  91. VariableDeclarations = new List<VariableDeclaration>()
  92. },
  93. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  94. function.Strict
  95. ) { Extensible = true };
  96. return functionObject;
  97. }
  98. /// <summary>
  99. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  100. /// </summary>
  101. /// <param name="functionDeclaration"></param>
  102. /// <returns></returns>
  103. public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration)
  104. {
  105. var functionObject = new ScriptFunctionInstance(
  106. Engine,
  107. functionDeclaration,
  108. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  109. functionDeclaration.Strict
  110. ) { Extensible = true };
  111. return functionObject;
  112. }
  113. private FunctionInstance _throwTypeError;
  114. public FunctionInstance ThrowTypeError
  115. {
  116. get
  117. {
  118. if (_throwTypeError != null)
  119. {
  120. return _throwTypeError;
  121. }
  122. _throwTypeError = new ThrowTypeError(Engine);
  123. return _throwTypeError;
  124. }
  125. }
  126. public object Apply(object thisObject, object[] arguments)
  127. {
  128. if (arguments.Length != 2)
  129. {
  130. throw new ArgumentException("Apply has to be called with two arguments.");
  131. }
  132. var func = thisObject as ICallable;
  133. var thisArg = arguments[0];
  134. var argArray = arguments[1];
  135. if (func == null)
  136. {
  137. throw new JavaScriptException(Engine.TypeError);
  138. }
  139. if (argArray == Null.Instance || argArray == Undefined.Instance)
  140. {
  141. return func.Call(thisArg, Arguments.Empty);
  142. }
  143. var argArrayObj = argArray as ObjectInstance;
  144. if (argArrayObj == null)
  145. {
  146. throw new JavaScriptException(Engine.TypeError);
  147. }
  148. var len = argArrayObj.Get("length");
  149. var n = TypeConverter.ToUint32(len);
  150. var argList = new List<object>();
  151. for (var index = 0; index < n; index++)
  152. {
  153. var indexName = index.ToString();
  154. var nextArg = argArrayObj.Get(indexName);
  155. argList.Add(nextArg);
  156. }
  157. return func.Call(thisArg, argList.ToArray());
  158. }
  159. }
  160. }