FunctionConstructor.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. var parser = new JavaScriptParser();
  62. // todo: ensure parsable as parameter list
  63. var parameters = p.Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries);
  64. var statements = parser.ParseFunctionBody(body);
  65. var functionObject = new ScriptFunctionInstance(
  66. Engine,
  67. new FunctionDeclaration
  68. {
  69. Type = SyntaxNodes.FunctionDeclaration,
  70. Body = new BlockStatement
  71. {
  72. Type = SyntaxNodes.BlockStatement,
  73. Body = statements
  74. },
  75. Parameters = parameters.Select(x => new Identifier
  76. {
  77. Type = SyntaxNodes.Identifier,
  78. Name = x
  79. }),
  80. FunctionDeclarations = new List<FunctionDeclaration>(),
  81. VariableDeclarations = new List<VariableDeclaration>()
  82. },
  83. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  84. false
  85. ) { Extensible = true };
  86. return functionObject;
  87. }
  88. /// <summary>
  89. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  90. /// </summary>
  91. /// <param name="functionDeclaration"></param>
  92. /// <returns></returns>
  93. public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration)
  94. {
  95. var functionObject = new ScriptFunctionInstance(
  96. Engine,
  97. functionDeclaration,
  98. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  99. functionDeclaration.Strict
  100. ) { Extensible = true };
  101. return functionObject;
  102. }
  103. private FunctionInstance _throwTypeError;
  104. public FunctionInstance ThrowTypeError
  105. {
  106. get
  107. {
  108. if (_throwTypeError != null)
  109. {
  110. return _throwTypeError;
  111. }
  112. _throwTypeError = new ThrowTypeError(Engine);
  113. return _throwTypeError;
  114. }
  115. }
  116. public object Apply(object thisObject, object[] arguments)
  117. {
  118. if (arguments.Length != 2)
  119. {
  120. throw new ArgumentException("Apply has to be called with two arguments.");
  121. }
  122. var func = thisObject as ICallable;
  123. var thisArg = arguments[0];
  124. var argArray = arguments[1];
  125. if (func == null)
  126. {
  127. throw new JavaScriptException(Engine.TypeError);
  128. }
  129. if (argArray == Null.Instance || argArray == Undefined.Instance)
  130. {
  131. return func.Call(thisArg, Arguments.Empty);
  132. }
  133. var argArrayObj = argArray as ObjectInstance;
  134. if (argArrayObj == null)
  135. {
  136. throw new JavaScriptException(Engine.TypeError);
  137. }
  138. var len = argArrayObj.Get("length");
  139. var n = TypeConverter.ToUint32(len);
  140. var argList = new List<object>();
  141. for (var index = 0; index < n; index++)
  142. {
  143. var indexName = index.ToString();
  144. var nextArg = argArrayObj.Get(indexName);
  145. argList.Add(nextArg);
  146. }
  147. return func.Call(thisArg, argList.ToArray());
  148. }
  149. }
  150. }