ScriptFunctionInstance.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System;
  2. using System.Linq;
  3. using Jint.Native.Argument;
  4. using Jint.Native.Object;
  5. using Jint.Parser;
  6. using Jint.Runtime;
  7. using Jint.Runtime.Descriptors;
  8. using Jint.Runtime.Environments;
  9. namespace Jint.Native.Function
  10. {
  11. /// <summary>
  12. ///
  13. /// </summary>
  14. public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor
  15. {
  16. private readonly Engine _engine;
  17. private readonly IFunctionDeclaration _functionDeclaration;
  18. public ScriptFunctionInstance(Engine engine, IFunctionDeclaration functionDeclaration, ObjectInstance instancePrototype, ObjectInstance functionPrototype, LexicalEnvironment scope, bool strict)
  19. : base(engine, instancePrototype, functionDeclaration.Parameters.Select(x => x.Name).ToArray(), scope, strict)
  20. {
  21. // http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  22. _engine = engine;
  23. _functionDeclaration = functionDeclaration;
  24. Extensible = true;
  25. var len = functionDeclaration.Parameters.Count();
  26. DefineOwnProperty("length", new DataDescriptor(len) { Writable = false, Enumerable = false, Configurable = false }, false);
  27. DefineOwnProperty("name", new DataDescriptor(_functionDeclaration.Id), false);
  28. instancePrototype.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = true, Configurable = true }, false);
  29. DefineOwnProperty("prototype", new DataDescriptor(functionPrototype) { Writable = true, Enumerable = true, Configurable = true }, false);
  30. if (strict)
  31. {
  32. var thrower = engine.Function.ThrowTypeError;
  33. DefineOwnProperty("caller", new AccessorDescriptor(thrower) { Enumerable = false, Configurable = false }, false);
  34. DefineOwnProperty("arguments", new AccessorDescriptor(thrower) { Enumerable = false, Configurable = false }, false);
  35. }
  36. }
  37. /// <summary>
  38. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1
  39. /// </summary>
  40. /// <param name="thisArg"></param>
  41. /// <param name="arguments"></param>
  42. /// <returns></returns>
  43. public override object Call(object thisArg, object[] arguments)
  44. {
  45. object thisBinding;
  46. // setup new execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3
  47. if (_engine.Options.IsStrict())
  48. {
  49. thisBinding = thisArg;
  50. }
  51. else if (thisArg == Undefined.Instance || thisArg == Null.Instance)
  52. {
  53. thisBinding = _engine.Global;
  54. }
  55. else if (TypeConverter.GetType(thisArg) != TypeCode.Object)
  56. {
  57. thisBinding = TypeConverter.ToObject(_engine, thisArg);
  58. }
  59. else
  60. {
  61. thisBinding = thisArg;
  62. }
  63. var localEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, Scope);
  64. _engine.EnterExecutionContext(localEnv, localEnv, thisBinding);
  65. // Declaration Binding Instantiation http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
  66. var env = localEnv.Record;
  67. var configurableBindings = false;
  68. var argCount = arguments.Length;
  69. var n = 0;
  70. foreach (var parameter in _functionDeclaration.Parameters)
  71. {
  72. var argName = parameter.Name;
  73. n++;
  74. var v = n > argCount ? Undefined.Instance : arguments[n-1];
  75. var argAlreadyDeclared = env.HasBinding(argName);
  76. if (!argAlreadyDeclared)
  77. {
  78. env.CreateMutableBinding(argName);
  79. }
  80. env.SetMutableBinding(argName, v, Strict);
  81. }
  82. _engine.FunctionDeclarationBindings(_functionDeclaration, localEnv, true, Strict);
  83. var argumentsAlreadyDeclared = env.HasBinding("arguments");
  84. if (!argumentsAlreadyDeclared)
  85. {
  86. var argsObj = ArgumentsInstance.CreateArgumentsObject(_engine, this, _functionDeclaration.Parameters.Select(x => x.Name).ToArray(), arguments, env, Strict);
  87. if (Strict)
  88. {
  89. var declEnv = env as DeclarativeEnvironmentRecord;
  90. declEnv.CreateImmutableBinding("arguments");
  91. declEnv.InitializeImmutableBinding("arguments", argsObj);
  92. }
  93. else
  94. {
  95. env.CreateMutableBinding("arguments");
  96. env.SetMutableBinding("arguments", argsObj, false);
  97. }
  98. }
  99. // process all variable declarations in the current parser scope
  100. _engine.VariableDeclarationBinding(_functionDeclaration, env, configurableBindings, Strict);
  101. var result = _engine.ExecuteStatement(_functionDeclaration.Body);
  102. _engine.LeaveExecutionContext();
  103. if (result.Type == Completion.Throw)
  104. {
  105. throw new JavaScriptException(result.Value);
  106. }
  107. return result;
  108. }
  109. public ObjectInstance Construct(object[] arguments)
  110. {
  111. // todo: http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2
  112. var instance = new FunctionShim(_engine, Prototype, null, null);
  113. return instance;
  114. }
  115. }
  116. }