FunctionConstructor.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using Esprima;
  2. using Esprima.Ast;
  3. using Jint.Native.Object;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Environments;
  7. namespace Jint.Native.Function
  8. {
  9. public sealed class FunctionConstructor : FunctionInstance, IConstructor
  10. {
  11. private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
  12. private FunctionConstructor(Engine engine):base(engine, "Function", null, null, false)
  13. {
  14. }
  15. public static FunctionConstructor CreateFunctionConstructor(Engine engine)
  16. {
  17. var obj = new FunctionConstructor(engine);
  18. obj.Extensible = true;
  19. // The initial value of Function.prototype is the standard built-in Function prototype object
  20. obj.PrototypeObject = FunctionPrototype.CreatePrototypeObject(engine);
  21. // The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object
  22. obj.Prototype = obj.PrototypeObject;
  23. obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
  24. obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
  25. return obj;
  26. }
  27. public void Configure()
  28. {
  29. }
  30. public FunctionPrototype PrototypeObject { get; private set; }
  31. public override JsValue Call(JsValue thisObject, JsValue[] arguments)
  32. {
  33. return Construct(arguments);
  34. }
  35. public ObjectInstance Construct(JsValue[] arguments)
  36. {
  37. var argCount = arguments.Length;
  38. string p = "";
  39. string body = "";
  40. if (argCount == 1)
  41. {
  42. body = TypeConverter.ToString(arguments[0]);
  43. }
  44. else if (argCount > 1)
  45. {
  46. var firstArg = arguments[0];
  47. p = TypeConverter.ToString(firstArg);
  48. for (var k = 1; k < argCount - 1; k++)
  49. {
  50. var nextArg = arguments[k];
  51. p += "," + TypeConverter.ToString(nextArg);
  52. }
  53. body = TypeConverter.ToString(arguments[argCount-1]);
  54. }
  55. IFunction function;
  56. try
  57. {
  58. var functionExpression = "function f(" + p + ") { " + body + "}";
  59. var parser = new JavaScriptParser(functionExpression, ParserOptions);
  60. function = (IFunction) parser.ParseProgram().Body[0];
  61. }
  62. catch (ParserException)
  63. {
  64. ExceptionHelper.ThrowSyntaxError(_engine);
  65. return null;
  66. }
  67. var functionObject = new ScriptFunctionInstance(
  68. Engine,
  69. function,
  70. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  71. function.Strict)
  72. {
  73. Extensible = true
  74. };
  75. return functionObject;
  76. }
  77. /// <summary>
  78. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  79. /// </summary>
  80. /// <param name="functionDeclaration"></param>
  81. /// <returns></returns>
  82. public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration)
  83. {
  84. var functionObject = new ScriptFunctionInstance(
  85. Engine,
  86. functionDeclaration,
  87. LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment),
  88. functionDeclaration.Strict)
  89. {
  90. Extensible = true
  91. };
  92. return functionObject;
  93. }
  94. private FunctionInstance _throwTypeError;
  95. private static readonly char[] ArgumentNameSeparator = new[] { ',' };
  96. public FunctionInstance ThrowTypeError
  97. {
  98. get
  99. {
  100. if (!ReferenceEquals(_throwTypeError, null))
  101. {
  102. return _throwTypeError;
  103. }
  104. _throwTypeError = new ThrowTypeError(Engine);
  105. return _throwTypeError;
  106. }
  107. }
  108. public object Apply(JsValue thisObject, JsValue[] arguments)
  109. {
  110. if (arguments.Length != 2)
  111. {
  112. ExceptionHelper.ThrowArgumentException("Apply has to be called with two arguments.");
  113. }
  114. var func = thisObject.TryCast<ICallable>();
  115. var thisArg = arguments[0];
  116. var argArray = arguments[1];
  117. if (func is null)
  118. {
  119. return ExceptionHelper.ThrowTypeError<object>(Engine);
  120. }
  121. if (argArray.IsNullOrUndefined())
  122. {
  123. return func.Call(thisArg, Arguments.Empty);
  124. }
  125. var argArrayObj = argArray.TryCast<ObjectInstance>();
  126. if (ReferenceEquals(argArrayObj, null))
  127. {
  128. ExceptionHelper.ThrowTypeError(Engine);
  129. }
  130. var len = argArrayObj.Get("length");
  131. var n = TypeConverter.ToUint32(len);
  132. var argList = new JsValue[n];
  133. for (var index = 0; index < n; index++)
  134. {
  135. var indexName = TypeConverter.ToString(index);
  136. var nextArg = argArrayObj.Get(indexName);
  137. argList[index] = nextArg;
  138. }
  139. return func.Call(thisArg, argList);
  140. }
  141. }
  142. }