DeclarationCache.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System.Runtime.InteropServices;
  2. namespace Jint.Runtime.Interpreter;
  3. internal readonly record struct DeclarationCache(List<ScopedDeclaration> Declarations, bool AllLexicalScoped);
  4. [StructLayout(LayoutKind.Auto)]
  5. internal readonly record struct ScopedDeclaration(Key[] BoundNames, bool IsConstantDeclaration, Node Declaration);
  6. internal static class DeclarationCacheBuilder
  7. {
  8. public static DeclarationCache Build(List<Declaration>? lexicalDeclarations)
  9. {
  10. if (lexicalDeclarations is null)
  11. {
  12. return new DeclarationCache([], AllLexicalScoped: true);
  13. }
  14. var allLexical = true;
  15. List<Key> boundNames = [];
  16. List<ScopedDeclaration> declarations = [];
  17. for (var i = 0; i < lexicalDeclarations.Count; i++)
  18. {
  19. var d = lexicalDeclarations[i];
  20. Collect(boundNames, d, ref allLexical, declarations);
  21. }
  22. return new DeclarationCache(declarations, allLexical);
  23. }
  24. public static DeclarationCache Build(BlockStatement statement)
  25. {
  26. var allLexical = true;
  27. List<Key> boundNames = [];
  28. List<ScopedDeclaration> declarations = [];
  29. ref readonly var statementListItems = ref statement.Body;
  30. foreach (var node in statementListItems.AsSpan())
  31. {
  32. if (node.Type != NodeType.VariableDeclaration && node.Type != NodeType.FunctionDeclaration && node.Type != NodeType.ClassDeclaration)
  33. {
  34. continue;
  35. }
  36. if (node is VariableDeclaration { Kind: VariableDeclarationKind.Var })
  37. {
  38. continue;
  39. }
  40. Collect(boundNames, node, ref allLexical, declarations);
  41. }
  42. return new DeclarationCache(declarations, allLexical);
  43. }
  44. public static DeclarationCache Build(SwitchCase statement)
  45. {
  46. var allLexical = true;
  47. List<Key> boundNames = [];
  48. List<ScopedDeclaration> declarations = [];
  49. ref readonly var statementListItems = ref statement.Consequent;
  50. foreach (var node in statementListItems.AsSpan())
  51. {
  52. if (node.Type != NodeType.VariableDeclaration)
  53. {
  54. continue;
  55. }
  56. var rootVariable = (VariableDeclaration) node;
  57. if (rootVariable.Kind == VariableDeclarationKind.Var)
  58. {
  59. continue;
  60. }
  61. Collect(boundNames, node, ref allLexical, declarations);
  62. }
  63. return new DeclarationCache(declarations, allLexical);
  64. }
  65. private static void Collect(
  66. List<Key> boundNames,
  67. Node node,
  68. ref bool allLexical,
  69. List<ScopedDeclaration> declarations)
  70. {
  71. boundNames.Clear();
  72. node.GetBoundNames(boundNames);
  73. var isConstantDeclaration = false;
  74. if (node is VariableDeclaration variableDeclaration)
  75. {
  76. isConstantDeclaration = variableDeclaration.Kind == VariableDeclarationKind.Const;
  77. allLexical &= variableDeclaration.Kind != VariableDeclarationKind.Var;
  78. }
  79. else
  80. {
  81. allLexical = false;
  82. }
  83. declarations.Add(new ScopedDeclaration(boundNames.ToArray(), isConstantDeclaration, node));
  84. }
  85. }