DebugScopes.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using Jint.Runtime.Environments;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace Jint.Runtime.Debugger
  5. {
  6. public sealed class DebugScopes : IReadOnlyList<DebugScope>
  7. {
  8. private readonly HashSet<string> _foundBindings = new HashSet<string>();
  9. private readonly List<DebugScope> _scopes = new List<DebugScope>();
  10. internal DebugScopes(LexicalEnvironment environment)
  11. {
  12. Populate(environment);
  13. }
  14. /// <summary>
  15. /// Shortcut to Global scope
  16. /// </summary>
  17. public DebugScope Global { get; private set; }
  18. /// <summary>
  19. /// Shortcut to Local scope. Note that this is only present inside functions, and only includes
  20. /// function scope bindings.
  21. /// </summary>
  22. public DebugScope Local { get; private set; }
  23. public DebugScope this[int index] => _scopes[index];
  24. public int Count => _scopes.Count;
  25. private void Populate(LexicalEnvironment environment)
  26. {
  27. bool inLocalScope = true;
  28. while (environment != null)
  29. {
  30. EnvironmentRecord record = environment._record;
  31. switch (record)
  32. {
  33. case GlobalEnvironmentRecord:
  34. AddScope(DebugScopeType.Global, record);
  35. break;
  36. case FunctionEnvironmentRecord:
  37. AddScope(inLocalScope ? DebugScopeType.Local : DebugScopeType.Closure, record);
  38. // We're now in closure territory
  39. inLocalScope = false;
  40. break;
  41. case ObjectEnvironmentRecord:
  42. // If an ObjectEnvironmentRecord is not a GlobalEnvironmentRecord, it's With
  43. AddScope(DebugScopeType.With, record);
  44. break;
  45. case DeclarativeEnvironmentRecord der:
  46. if (der._catchEnvironment)
  47. {
  48. AddScope(DebugScopeType.Catch, record);
  49. }
  50. else
  51. {
  52. bool isTopLevel = environment._outer?._record is FunctionEnvironmentRecord;
  53. AddScope(DebugScopeType.Block, record, isTopLevel);
  54. }
  55. break;
  56. }
  57. environment = environment._outer;
  58. }
  59. }
  60. private void AddScope(DebugScopeType type, EnvironmentRecord record, bool isTopLevel = false)
  61. {
  62. var bindings = new List<string>();
  63. PopulateBindings(bindings, record);
  64. if (bindings.Count > 0)
  65. {
  66. var scope = new DebugScope(type, record, bindings, isTopLevel);
  67. _scopes.Add(scope);
  68. switch (type)
  69. {
  70. case DebugScopeType.Global:
  71. Global = scope;
  72. break;
  73. case DebugScopeType.Local:
  74. Local = scope;
  75. break;
  76. }
  77. }
  78. }
  79. private void PopulateBindings(List<string> bindings, EnvironmentRecord record)
  80. {
  81. var bindingNames = record.GetAllBindingNames();
  82. foreach (var name in bindingNames)
  83. {
  84. // Only add non-shadowed bindings
  85. if (!_foundBindings.Contains(name))
  86. {
  87. bindings.Add(name);
  88. _foundBindings.Add(name);
  89. }
  90. }
  91. }
  92. public IEnumerator<DebugScope> GetEnumerator()
  93. {
  94. return _scopes.GetEnumerator();
  95. }
  96. IEnumerator IEnumerable.GetEnumerator()
  97. {
  98. return _scopes.GetEnumerator();
  99. }
  100. }
  101. }