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. // The initial value of Function.prototype is the standard built-in Function prototype object
  24. obj.PrototypeObject = FunctionPrototype.CreatePrototypeObject(engine);
  25. // The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object
  26. obj.Prototype = obj.PrototypeObject;
  27. obj.FastAddProperty("prototype", obj.PrototypeObject, false, false, false);
  28. obj.FastAddProperty("length", 1, false, false, false);
  29. return obj;
  30. }
  31. public void Configure()
  32. {
  33. }
  34. public FunctionPrototype PrototypeObject { get; private set; }
  35. public override object Call(object thisObject, object[] arguments)
  36. {
  37. return Construct(arguments);
  38. }
  39. public ObjectInstance Construct(object[] arguments)
  40. {
  41. var argCount = arguments.Length;
  42. string p = "";
  43. string body = "";
  44. if (argCount == 1)
  45. {
  46. body = TypeConverter.ToString(arguments[0]);
  47. }
  48. else if (argCount > 1)
  49. {
  50. var firstArg = arguments[0];
  51. p = TypeConverter.ToString(firstArg);
  52. for (var k = 1; k < argCount - 1; k++)
  53. {
  54. var nextArg = arguments[k];
  55. p += "," + TypeConverter.ToString(nextArg);
  56. }
  57. body = TypeConverter.ToString(arguments[argCount-1]);
  58. }
  59. body = TypeConverter.ToString(body);
  60. var parser = new JavaScriptParser();
  61. // todo: ensure parsable as parameter list
  62. var parameters = p.Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries);
  63. var statements = parser.ParseFunctionBody(body);
  64. var functionObject = new ScriptFunctionInstance(
  65. Engine,
  66. new FunctionDeclaration
  67. {
  68. Type = SyntaxNodes.FunctionDeclaration,
  69. Body = new BlockStatement
  70. {
  71. Type = SyntaxNodes.BlockStatement,
  72. Body = statements
  73. },
  74. Parameters = parameters.Select(x => new Identifier
  75. {
  76. Type = SyntaxNodes.Identifier,
  77. Name = x
  78. }),
  79. FunctionDeclarations = new List<FunctionDeclaration>(),
  80. VariableDeclarations = new List<VariableDeclaration>()
  81. },
  82. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  83. false
  84. ) { Extensible = true };
  85. return functionObject;
  86. }
  87. /// <summary>
  88. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  89. /// </summary>
  90. /// <param name="functionDeclaration"></param>
  91. /// <returns></returns>
  92. public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration)
  93. {
  94. var functionObject = new ScriptFunctionInstance(
  95. Engine,
  96. functionDeclaration,
  97. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  98. functionDeclaration.Strict
  99. ) { Extensible = true };
  100. return functionObject;
  101. }
  102. private FunctionInstance _throwTypeError;
  103. public FunctionInstance ThrowTypeError
  104. {
  105. get
  106. {
  107. if (_throwTypeError != null)
  108. {
  109. return _throwTypeError;
  110. }
  111. _throwTypeError = new ThrowTypeError(Engine);
  112. return _throwTypeError;
  113. }
  114. }
  115. public object Apply(object thisObject, object[] arguments)
  116. {
  117. if (arguments.Length != 2)
  118. {
  119. throw new ArgumentException("Apply has to be called with two arguments.");
  120. }
  121. var func = thisObject as ICallable;
  122. var thisArg = arguments[0];
  123. var argArray = arguments[1];
  124. if (func == null)
  125. {
  126. throw new JavaScriptException(Engine.TypeError);
  127. }
  128. if (argArray == Null.Instance || argArray == Undefined.Instance)
  129. {
  130. return func.Call(thisArg, Arguments.Empty);
  131. }
  132. var argArrayObj = argArray as ObjectInstance;
  133. if (argArrayObj == null)
  134. {
  135. throw new JavaScriptException(Engine.TypeError);
  136. }
  137. var len = argArrayObj.Get("length");
  138. var n = TypeConverter.ToUint32(len);
  139. var argList = new List<object>();
  140. for (var index = 0; index < n; index++)
  141. {
  142. var indexName = index.ToString();
  143. var nextArg = argArrayObj.Get(indexName);
  144. argList.Add(nextArg);
  145. }
  146. return func.Call(thisArg, argList.ToArray());
  147. }
  148. }
  149. }