JintFunctionDefinition.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Esprima;
  4. using Esprima.Ast;
  5. using Jint.Runtime.Interpreter.Statements;
  6. namespace Jint.Runtime.Interpreter
  7. {
  8. internal sealed class JintFunctionDefinition
  9. {
  10. internal readonly IFunction _function;
  11. internal readonly string _name;
  12. internal readonly bool _strict;
  13. internal readonly string[] _parameterNames;
  14. internal readonly JintStatement _body;
  15. internal bool _hasRestParameter;
  16. internal int _length;
  17. public readonly HoistingScope _hoistingScope;
  18. public JintFunctionDefinition(Engine engine, IFunction function)
  19. {
  20. _function = function;
  21. _hoistingScope = function.HoistingScope;
  22. _name = !string.IsNullOrEmpty(function.Id?.Name) ? function.Id.Name : null;
  23. _strict = function.Strict;
  24. _parameterNames = GetParameterNames(function);
  25. Statement bodyStatement;
  26. if (function.Expression)
  27. {
  28. bodyStatement = new ReturnStatement((Expression) function.Body);
  29. }
  30. else
  31. {
  32. // Esprima doesn't detect strict at the moment for
  33. // language/expressions/object/method-definition/name-invoke-fn-strict.js
  34. var blockStatement = (BlockStatement) function.Body;
  35. for (int i = 0; i < blockStatement.Body.Count; ++i)
  36. {
  37. if (blockStatement.Body[i] is Directive d && d.Directiv == "use strict")
  38. {
  39. _strict = true;
  40. }
  41. }
  42. bodyStatement = blockStatement;
  43. }
  44. _body = JintStatement.Build(engine, bodyStatement);
  45. }
  46. private IEnumerable<Identifier> GetParameterIdentifiers(INode parameter)
  47. {
  48. if (parameter is Identifier identifier)
  49. {
  50. return new [] { identifier };
  51. }
  52. if (parameter is RestElement restElement)
  53. {
  54. _hasRestParameter = true;
  55. return GetParameterIdentifiers(restElement.Argument);
  56. }
  57. if (parameter is ArrayPattern arrayPattern)
  58. {
  59. return arrayPattern.Elements.SelectMany(GetParameterIdentifiers);
  60. }
  61. if (parameter is ObjectPattern objectPattern)
  62. {
  63. return objectPattern.Properties.SelectMany(property => GetParameterIdentifiers(property.Value));
  64. }
  65. if (parameter is AssignmentPattern assignmentPattern)
  66. {
  67. return GetParameterIdentifiers(assignmentPattern.Left);
  68. }
  69. return Enumerable.Empty<Identifier>();
  70. }
  71. private string[] GetParameterNames(IFunction functionDeclaration)
  72. {
  73. var parameterNames = new List<string>();
  74. var functionDeclarationParams = functionDeclaration.Params;
  75. int count = functionDeclarationParams.Count;
  76. bool onlyIdentifiers = true;
  77. for (var i = 0; i < count; i++)
  78. {
  79. var parameter = functionDeclarationParams[i];
  80. if (parameter is Identifier id)
  81. {
  82. parameterNames.Add(id.Name);
  83. if (onlyIdentifiers)
  84. {
  85. _length++;
  86. }
  87. }
  88. else
  89. {
  90. onlyIdentifiers = false;
  91. foreach (var identifier in GetParameterIdentifiers(parameter))
  92. {
  93. parameterNames.Add(identifier.Name);
  94. }
  95. }
  96. }
  97. return parameterNames.ToArray();
  98. }
  99. }
  100. }