HoistingScope.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System.Collections.Generic;
  2. using Esprima.Ast;
  3. namespace Jint
  4. {
  5. internal readonly struct HoistingScope
  6. {
  7. internal readonly List<FunctionDeclaration> _functionDeclarations;
  8. internal readonly List<VariableDeclaration> _variablesDeclarations;
  9. internal readonly List<Key> _varNames;
  10. internal readonly List<VariableDeclaration> _lexicalDeclarations;
  11. internal readonly List<string> _lexicalNames;
  12. private HoistingScope(
  13. List<FunctionDeclaration> functionDeclarations,
  14. List<Key> varNames,
  15. List<VariableDeclaration> variableDeclarations,
  16. List<VariableDeclaration> lexicalDeclarations,
  17. List<string> lexicalNames)
  18. {
  19. _functionDeclarations = functionDeclarations;
  20. _varNames = varNames;
  21. _variablesDeclarations = variableDeclarations;
  22. _lexicalDeclarations = lexicalDeclarations;
  23. _lexicalNames = lexicalNames;
  24. }
  25. public static HoistingScope GetProgramLevelDeclarations(
  26. Script script,
  27. bool collectVarNames = false,
  28. bool collectLexicalNames = false)
  29. {
  30. var treeWalker = new ScriptWalker(StrictModeScope.IsStrictModeCode, collectVarNames, collectLexicalNames);
  31. treeWalker.Visit(script, null);
  32. return new HoistingScope(
  33. treeWalker._functions,
  34. treeWalker._varNames,
  35. treeWalker._variableDeclarations,
  36. treeWalker._lexicalDeclarations,
  37. treeWalker._lexicalNames);
  38. }
  39. public static HoistingScope GetFunctionLevelDeclarations(
  40. IFunction node,
  41. bool collectVarNames = false,
  42. bool collectLexicalNames = false)
  43. {
  44. var treeWalker = new ScriptWalker(StrictModeScope.IsStrictModeCode, collectVarNames, collectLexicalNames);
  45. treeWalker.Visit(node.Body, null);
  46. return new HoistingScope(
  47. treeWalker._functions,
  48. treeWalker._varNames,
  49. treeWalker._variableDeclarations,
  50. treeWalker._lexicalDeclarations,
  51. treeWalker._lexicalNames);
  52. }
  53. public static List<VariableDeclaration> GetLexicalDeclarations(BlockStatement statement)
  54. {
  55. List<VariableDeclaration> lexicalDeclarations = null ;
  56. ref readonly var statementListItems = ref statement.Body;
  57. for (var i = 0; i < statementListItems.Count; i++)
  58. {
  59. var node = statementListItems[i];
  60. if (node.Type != Nodes.VariableDeclaration)
  61. {
  62. continue;
  63. }
  64. var rootVariable = (VariableDeclaration) node;
  65. if (rootVariable.Kind == VariableDeclarationKind.Var)
  66. {
  67. continue;
  68. }
  69. lexicalDeclarations ??= new List<VariableDeclaration>();
  70. lexicalDeclarations.Add(rootVariable);
  71. }
  72. return lexicalDeclarations;
  73. }
  74. public static List<VariableDeclaration> GetLexicalDeclarations(SwitchCase statement)
  75. {
  76. List<VariableDeclaration> lexicalDeclarations = null ;
  77. ref readonly var statementListItems = ref statement.Consequent;
  78. for (var i = 0; i < statementListItems.Count; i++)
  79. {
  80. var node = statementListItems[i];
  81. if (node.Type != Nodes.VariableDeclaration)
  82. {
  83. continue;
  84. }
  85. var rootVariable = (VariableDeclaration) node;
  86. if (rootVariable.Kind == VariableDeclarationKind.Var)
  87. {
  88. continue;
  89. }
  90. lexicalDeclarations ??= new List<VariableDeclaration>();
  91. lexicalDeclarations.Add(rootVariable);
  92. }
  93. return lexicalDeclarations;
  94. }
  95. private sealed class ScriptWalker
  96. {
  97. internal List<FunctionDeclaration> _functions;
  98. private readonly bool _strict;
  99. private readonly bool _collectVarNames;
  100. internal List<VariableDeclaration> _variableDeclarations;
  101. internal List<Key> _varNames;
  102. private readonly bool _collectLexicalNames;
  103. internal List<VariableDeclaration> _lexicalDeclarations;
  104. internal List<string> _lexicalNames;
  105. public ScriptWalker(bool strict, bool collectVarNames, bool collectLexicalNames)
  106. {
  107. _strict = strict;
  108. _collectVarNames = collectVarNames;
  109. _collectLexicalNames = collectLexicalNames;
  110. }
  111. public void Visit(Node node, Node parent)
  112. {
  113. foreach (var childNode in node.ChildNodes)
  114. {
  115. if (childNode is null)
  116. {
  117. // array expression can push null nodes in Esprima
  118. continue;
  119. }
  120. if (childNode.Type == Nodes.VariableDeclaration)
  121. {
  122. var variableDeclaration = (VariableDeclaration) childNode;
  123. if (variableDeclaration.Kind == VariableDeclarationKind.Var)
  124. {
  125. _variableDeclarations ??= new List<VariableDeclaration>();
  126. _variableDeclarations.Add(variableDeclaration);
  127. if (_collectVarNames)
  128. {
  129. _varNames ??= new List<Key>();
  130. ref readonly var nodeList = ref variableDeclaration.Declarations;
  131. foreach (var declaration in nodeList)
  132. {
  133. if (declaration.Id is Identifier identifier)
  134. {
  135. _varNames.Add(identifier.Name);
  136. }
  137. }
  138. }
  139. }
  140. if (parent is null && variableDeclaration.Kind != VariableDeclarationKind.Var)
  141. {
  142. _lexicalDeclarations ??= new List<VariableDeclaration>();
  143. _lexicalDeclarations.Add(variableDeclaration);
  144. if (_collectLexicalNames)
  145. {
  146. _lexicalNames ??= new List<string>();
  147. ref readonly var nodeList = ref variableDeclaration.Declarations;
  148. foreach (var declaration in nodeList)
  149. {
  150. if (declaration.Id is Identifier identifier)
  151. {
  152. _lexicalNames.Add(identifier.Name);
  153. }
  154. }
  155. }
  156. }
  157. }
  158. else if (childNode.Type == Nodes.FunctionDeclaration
  159. // in strict mode cannot include function declarations directly under block or case clauses
  160. && (!_strict || parent is null || (node.Type != Nodes.BlockStatement && node.Type != Nodes.SwitchCase)))
  161. {
  162. _functions ??= new List<FunctionDeclaration>();
  163. _functions.Add((FunctionDeclaration) childNode);
  164. }
  165. if (childNode.Type != Nodes.FunctionDeclaration
  166. && childNode.Type != Nodes.ArrowFunctionExpression
  167. && childNode.Type != Nodes.ArrowParameterPlaceHolder
  168. && childNode.Type != Nodes.FunctionExpression
  169. && childNode.ChildNodes.Count > 0)
  170. {
  171. Visit(childNode, node);
  172. }
  173. }
  174. }
  175. }
  176. }
  177. }